diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 5d9ae27bd462..ef4b9218ae1e 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -203,7 +203,34 @@ Description: Shows total written kbytes issued to disk. What: /sys/fs/f2fs//features Date: July 2017 Contact: "Jaegeuk Kim" -Description: Shows all enabled features in current device. +Description: /feature_list/ + Shows all enabled features in current device. + Supported features: + encryption, blkzoned, extra_attr, projquota, inode_checksum, + flexible_inline_xattr, quota_ino, inode_crtime, lost_found, + verity, sb_checksum, casefold, readonly, compression, pin_file. + +What: /sys/fs/f2fs//feature_list/ +Date: June 2021 +Contact: "Jaegeuk Kim" +Description: Expand /sys/fs/f2fs//features to meet sysfs rule. + Supported on-disk features: + encryption, block_zoned (aka blkzoned), extra_attr, + project_quota (aka projquota), inode_checksum, + flexible_inline_xattr, quota_ino, inode_crtime, lost_found, + verity, sb_checksum, casefold, readonly, compression. + Note that, pin_file is moved into /sys/fs/f2fs/features/. + +What: /sys/fs/f2fs/features/ +Date: July 2017 +Contact: "Jaegeuk Kim" +Description: Shows all enabled kernel features. + Supported features: + encryption, block_zoned, extra_attr, project_quota, + inode_checksum, flexible_inline_xattr, quota_ino, + inode_crtime, lost_found, verity, sb_checksum, + casefold, readonly, compression, test_dummy_encryption_v2, + atomic_write, pin_file, encrypted_casefold. What: /sys/fs/f2fs//inject_rate Date: May 2016 @@ -438,3 +465,31 @@ Description: Show the count of inode newly enabled for compression since mount. Note that when the compression is disabled for the files, this count doesn't decrease. If you write "0" here, you can initialize compr_new_inode to "0". + +What: /sys/fs/f2fs//atgc_candidate_ratio +Date: May 2021 +Contact: "Chao Yu" +Description: When ATGC is on, it controls candidate ratio in order to limit total + number of potential victim in all candidates, the value should be in + range of [0, 100], by default it was initialized as 20(%). + +What: /sys/fs/f2fs//atgc_candidate_count +Date: May 2021 +Contact: "Chao Yu" +Description: When ATGC is on, it controls candidate count in order to limit total + number of potential victim in all candidates, by default it was + initialized as 10 (sections). + +What: /sys/fs/f2fs//atgc_age_weight +Date: May 2021 +Contact: "Chao Yu" +Description: When ATGC is on, it controls age weight to balance weight proportion + in between aging and valid blocks, the value should be in range of + [0, 100], by default it was initialized as 60(%). + +What: /sys/fs/f2fs//atgc_age_threshold +Date: May 2021 +Contact: "Chao Yu" +Description: When ATGC is on, it controls age threshold to bypass GCing young + candidates whose age is not beyond the threshold, by default it was + initialized as 604800 seconds (equals to 7 days). diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index 84ceebb08cac..187f43a03200 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -295,7 +295,7 @@ and let the driver restart normal I/O processing. A driver can still return a critical failure for this function if it can't get the device operational after reset. If the platform previously tried a soft reset, it might now try a hard reset (power -cycle) and then call slot_reset() again. It the device still can't +cycle) and then call slot_reset() again. If the device still can't be recovered, there is nothing more that can be done; the platform will typically report a "permanent failure" in such a case. The device will be considered "dead" in this case. diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 4346ae17a72c..d941717a191b 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -125,6 +125,17 @@ used when printing stack backtraces. The specifier takes into consideration the effect of compiler optimisations which may occur when tail-calls are used and marked with the noreturn GCC attribute. +If the pointer is within a module, the module name and optionally build ID is +printed after the symbol name with an extra ``b`` appended to the end of the +specifier. + +:: + %pS versatile_init+0x0/0x110 [module_name] + %pSb versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + %pSRb versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + (with __builtin_extract_return_addr() translation) + %pBb prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + Probed Pointers from BPF / tracing ---------------------------------- diff --git a/Documentation/cpu-freq/cpu-drivers.rst b/Documentation/cpu-freq/cpu-drivers.rst index a697278ce190..d84ededb66f9 100644 --- a/Documentation/cpu-freq/cpu-drivers.rst +++ b/Documentation/cpu-freq/cpu-drivers.rst @@ -58,9 +58,6 @@ And optionally .driver_data - cpufreq driver specific data. - .resolve_freq - Returns the most appropriate frequency for a target - frequency. Doesn't change the frequency though. - .get_intermediate and target_intermediate - Used to switch to stable frequency while changing CPU frequency. @@ -71,9 +68,6 @@ And optionally .exit - A pointer to a per-policy cleanup function called during CPU_POST_DEAD phase of cpu hotplug process. - .stop_cpu - A pointer to a per-policy stop function called during - CPU_DOWN_PREPARE phase of cpu hotplug process. - .suspend - A pointer to a per-policy suspend function which is called with interrupts disabled and _after_ the governor is stopped for the policy. diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index 97fb96266344..6423377710ee 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -167,6 +167,7 @@ properties: - description: Boards with the Amlogic Meson SM1 S905X3/D3/Y3 SoC items: - enum: + - bananapi,bpi-m5 - hardkernel,odroid-c4 - hardkernel,odroid-hc4 - khadas,vim3l diff --git a/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml b/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml index 812ae8cc5959..230b80d9d6cf 100644 --- a/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/bcm2835.yaml @@ -18,6 +18,7 @@ properties: - description: BCM2711 based Boards items: - enum: + - raspberrypi,400 - raspberrypi,4-model-b - const: brcm,bcm2711 diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index f3c7249c73d6..9a2432a88074 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -257,6 +257,13 @@ properties: where voltage is in V, frequency is in MHz. + performance-domains: + maxItems: 1 + description: + List of phandles and performance domain specifiers, as defined by + bindings of the performance domain provider. See also + dvfs/performance-domain.yaml. + power-domains: description: List of phandles and PM domain specifiers, as defined by bindings of the diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index e3c50f231d71..1c827c1954dc 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -197,6 +197,7 @@ properties: - boundary,imx6q-nitrogen6x - compulab,cm-fx6 # CompuLab CM-FX6 - dmo,imx6q-edmqmx6 # Data Modul eDM-QMX6 Board + - ds,imx6q-sbc # Da Sheng COM-9XX Modules - embest,imx6q-marsboard # Embest MarS Board i.MX6Dual - emtrion,emcon-mx6 # emCON-MX6D or emCON-MX6Q SoM - emtrion,emcon-mx6-avari # emCON-MX6D or emCON-MX6Q SoM on Avari Base @@ -400,6 +401,17 @@ properties: - const: armadeus,imx6dl-apf6 # APF6 (Solo) SoM - const: fsl,imx6dl + - description: i.MX6DL based congatec QMX6 Boards + items: + - enum: + - ge,imx6dl-b105v2 # General Electric B105v2 + - ge,imx6dl-b105pv2 # General Electric B105Pv2 + - ge,imx6dl-b125v2 # General Electric B125v2 + - ge,imx6dl-b125pv2 # General Electric B125Pv2 + - ge,imx6dl-b155v2 # General Electric B155v2 + - const: congatec,qmx6 + - const: fsl,imx6dl + - description: i.MX6DL based DFI FS700-M60-6DL Board items: - const: dfi,fs700-m60-6dl @@ -685,6 +697,7 @@ properties: - gw,imx8mm-gw71xx-0x # i.MX8MM Gateworks Development Kit - gw,imx8mm-gw72xx-0x # i.MX8MM Gateworks Development Kit - gw,imx8mm-gw73xx-0x # i.MX8MM Gateworks Development Kit + - gw,imx8mm-gw7901 # i.MX8MM Gateworks Board - kontron,imx8mm-n801x-som # i.MX8MM Kontron SL (N801X) SOM - variscite,var-som-mx8mm # i.MX8MM Variscite VAR-SOM-MX8MM module - const: fsl,imx8mm diff --git a/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml b/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml index d72e92bdf7c1..230bffeec0e5 100644 --- a/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml +++ b/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml @@ -17,6 +17,7 @@ properties: - items: - enum: - linksys,nslu2 + - welltech,epbx100 - const: intel,ixp42x - items: - enum: diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml index aff57a8c8c30..80a05f6fee85 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek.yaml @@ -122,6 +122,10 @@ properties: - enum: - mediatek,mt8195-evb - const: mediatek,mt8195 + - description: Google Burnet (HP Chromebook x360 11MK G3 EE) + items: + - const: google,burnet + - const: mediatek,mt8183 - description: Google Krane (Lenovo IdeaPad Duet, 10e,...) items: - enum: @@ -133,9 +137,19 @@ properties: items: - const: google,damu - const: mediatek,mt8183 - - description: Google Juniper (Acer Chromebook Spin 311) + - description: Google Fennel (Lenovo IdeaPad 3 Chromebook) items: - - const: google,juniper-sku16 + - enum: + - google,fennel-sku0 + - google,fennel-sku1 + - google,fennel-sku6 + - const: google,fennel + - const: mediatek,mt8183 + - description: Google Juniper (Acer Chromebook Spin 311) / Kenzo (Acer Chromebook 311) + items: + - enum: + - google,juniper-sku16 + - google,juniper-sku17 - const: google,juniper - const: mediatek,mt8183 - description: Google Kakadu (ASUS Chromebook Detachable CM3) @@ -144,6 +158,10 @@ properties: - const: google,kakadu-rev2 - const: google,kakadu - const: mediatek,mt8183 + - description: Google Kappa (HP Chromebook 11a) + items: + - const: google,kappa + - const: mediatek,mt8183 - description: Google Kodama (Lenovo 10e Chromebook Tablet) items: - enum: @@ -153,6 +171,13 @@ properties: - google,kodama-sku32 - const: google,kodama - const: mediatek,mt8183 + - description: Google Willow (Acer Chromebook 311 C722/C722T) + items: + - enum: + - google,willow-sku0 + - google,willow-sku1 + - const: google,willow + - const: mediatek,mt8183 - items: - enum: - mediatek,mt8183-pumpkin diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt b/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt index ae4afc6dcfe0..94d50a949be1 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt @@ -25,6 +25,7 @@ PROPERTIES "qcom,saw2" A more specific value could be one of: "qcom,apq8064-saw2-v1.1-cpu" + "qcom,msm8226-saw2-v2.1-cpu" "qcom,msm8974-saw2-v2.1-cpu" "qcom,apq8084-saw2-v2.1-cpu" diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 9b27e991bddc..9720b00c41d2 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -36,17 +36,20 @@ description: | msm8992 msm8994 msm8996 + sa8155p sc7180 sc7280 sdm630 sdm660 sdm845 sdx55 + sm8150 sm8250 sm8350 The 'board' element must be one of the following strings: + adp cdp cp01-c1 dragonboard @@ -178,6 +181,7 @@ properties: - items: - enum: - qcom,sc7280-idp + - google,senor - const: qcom,sc7280 - items: @@ -198,6 +202,16 @@ properties: - qcom,ipq6018-cp01-c1 - const: qcom,ipq6018 + - items: + - enum: + - qcom,sa8155p-adp + - const: qcom,sa8155p + + - items: + - enum: + - qcom,sm8150-mtp + - const: qcom,sm8150 + - items: - enum: - qcom,qrb5165-rb5 diff --git a/Documentation/devicetree/bindings/arm/renesas.yaml b/Documentation/devicetree/bindings/arm/renesas.yaml index 5fd0696a9f91..a0cce4e25039 100644 --- a/Documentation/devicetree/bindings/arm/renesas.yaml +++ b/Documentation/devicetree/bindings/arm/renesas.yaml @@ -302,6 +302,24 @@ properties: - renesas,rzn1d400-db # RZN1D-DB (RZ/N1D Demo Board for the RZ/N1D 400 pins package) - const: renesas,r9a06g032 + - description: RZ/G2UL (R9A07G043) + items: + - enum: + - renesas,r9a07g043u11 # RZ/G2UL Type-1 + - renesas,r9a07g043u12 # RZ/G2UL Type-2 + - const: renesas,r9a07g043 + + - description: RZ/G2{L,LC} (R9A07G044) + items: + - enum: + - renesas,smarc-evk # SMARC EVK + - enum: + - renesas,r9a07g044c1 # Single Cortex-A55 RZ/G2LC + - renesas,r9a07g044c2 # Dual Cortex-A55 RZ/G2LC + - renesas,r9a07g044l1 # Single Cortex-A55 RZ/G2L + - renesas,r9a07g044l2 # Dual Cortex-A55 RZ/G2L + - const: renesas,r9a07g044 + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 4a6f772c1043..6546b015fc62 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -600,6 +600,11 @@ properties: - const: zkmagic,a95x-z2 - const: rockchip,rk3318 + - description: Rockchip RK3568 Evaluation board + items: + - const: rockchip,rk3568-evb1-v10 + - const: rockchip,rk3568 + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.txt b/Documentation/devicetree/bindings/arm/rockchip/pmu.txt deleted file mode 100644 index 3ee9b428b2f7..000000000000 --- a/Documentation/devicetree/bindings/arm/rockchip/pmu.txt +++ /dev/null @@ -1,16 +0,0 @@ -Rockchip power-management-unit: -------------------------------- - -The pmu is used to turn off and on different power domains of the SoCs -This includes the power to the CPU cores. - -Required node properties: -- compatible value : = "rockchip,rk3066-pmu"; -- reg : physical base address and the size of the registers window - -Example: - - pmu@20004000 { - compatible = "rockchip,rk3066-pmu"; - reg = <0x20004000 0x100>; - }; diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml new file mode 100644 index 000000000000..53115b92d17f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/rockchip/pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip Power Management Unit (PMU) + +maintainers: + - Elaine Zhang + - Heiko Stuebner + +description: | + The PMU is used to turn on and off different power domains of the SoCs. + This includes the power to the CPU cores. + +select: + properties: + compatible: + contains: + enum: + - rockchip,px30-pmu + - rockchip,rk3066-pmu + - rockchip,rk3288-pmu + - rockchip,rk3399-pmu + + required: + - compatible + +properties: + compatible: + items: + - enum: + - rockchip,px30-pmu + - rockchip,rk3066-pmu + - rockchip,rk3288-pmu + - rockchip,rk3399-pmu + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: true + +examples: + - | + pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; + reg = <0x20004000 0x100>; + }; diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index ac750025a2eb..889128acf49a 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -224,6 +224,12 @@ properties: - const: empire-electronix,m712 - const: allwinner,sun5i-a13 + - description: Forlinx OKA40i-C Development board + items: + - const: forlinx,oka40i-c + - const: forlinx,feta40i-c + - const: allwinner,sun8i-r40 + - description: FriendlyARM NanoPi A64 items: - const: friendlyarm,nanopi-a64 @@ -269,6 +275,11 @@ properties: - const: friendlyarm,nanopi-r1 - const: allwinner,sun8i-h3 + - description: FriendlyARM NanoPi R1S H5 + items: + - const: friendlyarm,nanopi-r1s-h5 + - const: allwinner,sun50i-h5 + - description: FriendlyARM ZeroPi items: - const: friendlyarm,zeropi diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml index 43fd2f8927d0..0afec83cc723 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml @@ -301,6 +301,33 @@ patternProperties: additionalProperties: false + core-domain: + type: object + description: | + The vast majority of hardware blocks of Tegra SoC belong to a + Core power domain, which has a dedicated voltage rail that powers + the blocks. + + properties: + operating-points-v2: + description: + Should contain level, voltages and opp-supported-hw property. + The supported-hw is a bitfield indicating SoC speedo or process + ID mask. + + "#power-domain-cells": + const: 0 + + required: + - operating-points-v2 + - "#power-domain-cells" + + additionalProperties: false + + core-supply: + description: + Phandle to voltage regulator connected to the SoC Core power rail. + required: - compatible - reg @@ -325,6 +352,7 @@ examples: tegra_pmc: pmc@7000e400 { compatible = "nvidia,tegra210-pmc"; reg = <0x7000e400 0x400>; + core-supply = <®ulator>; clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; clock-names = "pclk", "clk32k_in"; #clock-cells = <1>; @@ -338,17 +366,24 @@ examples: nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; + pd_core: core-domain { + operating-points-v2 = <&core_opp_table>; + #power-domain-cells = <0>; + }; + powergates { pd_audio: aud { clocks = <&tegra_car TEGRA210_CLK_APE>, <&tegra_car TEGRA210_CLK_APB2APE>; resets = <&tegra_car 198>; + power-domains = <&pd_core>; #power-domain-cells = <0>; }; pd_xusbss: xusba { clocks = <&tegra_car TEGRA210_CLK_XUSB_SS>; resets = <&tegra_car TEGRA210_CLK_XUSB_SS>; + power-domains = <&pd_core>; #power-domain-cells = <0>; }; }; diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt deleted file mode 100644 index ab730ea0a560..000000000000 --- a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt +++ /dev/null @@ -1,313 +0,0 @@ -Broadcom iProc Family Clocks - -This binding uses the common clock binding: - Documentation/devicetree/bindings/clock/clock-bindings.txt - -The iProc clock controller manages clocks that are common to the iProc family. -An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, -LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL -comprises of several leaf clocks - -Required properties for a PLL and its leaf clocks: - -- compatible: - Should have a value of the form "brcm,-". For example, GENPLL on -Cygnus has a compatible string of "brcm,cygnus-genpll" - -- #clock-cells: - Have a value of <1> since there are more than 1 leaf clock of a given PLL - -- reg: - Define the base and range of the I/O address space that contain the iProc -clock control registers required for the PLL - -- clocks: - The input parent clock phandle for the PLL. For most iProc PLLs, this is an -onboard crystal with a fixed rate - -- clock-output-names: - An ordered list of strings defining the names of the clocks - -Example: - - osc: oscillator { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <25000000>; - }; - - genpll: genpll { - #clock-cells = <1>; - compatible = "brcm,cygnus-genpll"; - reg = <0x0301d000 0x2c>, <0x0301c020 0x4>; - clocks = <&osc>; - clock-output-names = "genpll", "axi21", "250mhz", "ihost_sys", - "enet_sw", "audio_125", "can"; - }; - -Required properties for ASIU clocks: - -ASIU clocks are a special case. These clocks are derived directly from the -reference clock of the onboard crystal - -- compatible: - Should have a value of the form "brcm,-asiu-clk". For example, ASIU -clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" - -- #clock-cells: - Have a value of <1> since there are more than 1 ASIU clocks - -- reg: - Define the base and range of the I/O address space that contain the iProc -clock control registers required for ASIU clocks - -- clocks: - The input parent clock phandle for the ASIU clock, i.e., the onboard -crystal - -- clock-output-names: - An ordered list of strings defining the names of the ASIU clocks - -Example: - - osc: oscillator { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <25000000>; - }; - - asiu_clks: asiu_clks { - #clock-cells = <1>; - compatible = "brcm,cygnus-asiu-clk"; - reg = <0x0301d048 0xc>, <0x180aa024 0x4>; - clocks = <&osc>; - clock-output-names = "keypad", "adc/touch", "pwm"; - }; - -Cygnus ------- -PLL and leaf clock compatible strings for Cygnus are: - "brcm,cygnus-armpll" - "brcm,cygnus-genpll" - "brcm,cygnus-lcpll0" - "brcm,cygnus-mipipll" - "brcm,cygnus-asiu-clk" - "brcm,cygnus-audiopll" - -The following table defines the set of PLL/clock index and ID for Cygnus. -These clock IDs are defined in: - "include/dt-bindings/clock/bcm-cygnus.h" - - Clock Source (Parent) Index ID - --- ----- ----- --------- - crystal N/A N/A N/A - - armpll crystal N/A N/A - - keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK - adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK - pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK - - genpll crystal 0 BCM_CYGNUS_GENPLL - axi21 genpll 1 BCM_CYGNUS_GENPLL_AXI21_CLK - 250mhz genpll 2 BCM_CYGNUS_GENPLL_250MHZ_CLK - ihost_sys genpll 3 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK - enet_sw genpll 4 BCM_CYGNUS_GENPLL_ENET_SW_CLK - audio_125 genpll 5 BCM_CYGNUS_GENPLL_AUDIO_125_CLK - can genpll 6 BCM_CYGNUS_GENPLL_CAN_CLK - - lcpll0 crystal 0 BCM_CYGNUS_LCPLL0 - pcie_phy lcpll0 1 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK - ddr_phy lcpll0 2 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK - sdio lcpll0 3 BCM_CYGNUS_LCPLL0_SDIO_CLK - usb_phy lcpll0 4 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK - smart_card lcpll0 5 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK - ch5_unused lcpll0 6 BCM_CYGNUS_LCPLL0_CH5_UNUSED - - mipipll crystal 0 BCM_CYGNUS_MIPIPLL - ch0_unused mipipll 1 BCM_CYGNUS_MIPIPLL_CH0_UNUSED - ch1_lcd mipipll 2 BCM_CYGNUS_MIPIPLL_CH1_LCD - ch2_v3d mipipll 3 BCM_CYGNUS_MIPIPLL_CH2_V3D - ch3_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH3_UNUSED - ch4_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH4_UNUSED - ch5_unused mipipll 6 BCM_CYGNUS_MIPIPLL_CH5_UNUSED - - audiopll crystal 0 BCM_CYGNUS_AUDIOPLL - ch0_audio audiopll 1 BCM_CYGNUS_AUDIOPLL_CH0 - ch1_audio audiopll 2 BCM_CYGNUS_AUDIOPLL_CH1 - ch2_audio audiopll 3 BCM_CYGNUS_AUDIOPLL_CH2 - -Hurricane 2 ------- -PLL and leaf clock compatible strings for Hurricane 2 are: - "brcm,hr2-armpll" - -The following table defines the set of PLL/clock for Hurricane 2: - - Clock Source Index ID - --- ----- ----- --------- - crystal N/A N/A N/A - - armpll crystal N/A N/A - - -Northstar and Northstar Plus ------- -PLL and leaf clock compatible strings for Northstar and Northstar Plus are: - "brcm,nsp-armpll" - "brcm,nsp-genpll" - "brcm,nsp-lcpll0" - -The following table defines the set of PLL/clock index and ID for Northstar and -Northstar Plus. These clock IDs are defined in: - "include/dt-bindings/clock/bcm-nsp.h" - - Clock Source Index ID - --- ----- ----- --------- - crystal N/A N/A N/A - - armpll crystal N/A N/A - - genpll crystal 0 BCM_NSP_GENPLL - phy genpll 1 BCM_NSP_GENPLL_PHY_CLK - ethernetclk genpll 2 BCM_NSP_GENPLL_ENET_SW_CLK - usbclk genpll 3 BCM_NSP_GENPLL_USB_PHY_REF_CLK - iprocfast genpll 4 BCM_NSP_GENPLL_IPROCFAST_CLK - sata1 genpll 5 BCM_NSP_GENPLL_SATA1_CLK - sata2 genpll 6 BCM_NSP_GENPLL_SATA2_CLK - - lcpll0 crystal 0 BCM_NSP_LCPLL0 - pcie_phy lcpll0 1 BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK - sdio lcpll0 2 BCM_NSP_LCPLL0_SDIO_CLK - ddr_phy lcpll0 3 BCM_NSP_LCPLL0_DDR_PHY_CLK - -Northstar 2 ------------ -PLL and leaf clock compatible strings for Northstar 2 are: - "brcm,ns2-genpll-scr" - "brcm,ns2-genpll-sw" - "brcm,ns2-lcpll-ddr" - "brcm,ns2-lcpll-ports" - -The following table defines the set of PLL/clock index and ID for Northstar 2. -These clock IDs are defined in: - "include/dt-bindings/clock/bcm-ns2.h" - - Clock Source Index ID - --- ----- ----- --------- - crystal N/A N/A N/A - - genpll_scr crystal 0 BCM_NS2_GENPLL_SCR - scr genpll_scr 1 BCM_NS2_GENPLL_SCR_SCR_CLK - fs genpll_scr 2 BCM_NS2_GENPLL_SCR_FS_CLK - audio_ref genpll_scr 3 BCM_NS2_GENPLL_SCR_AUDIO_CLK - ch3_unused genpll_scr 4 BCM_NS2_GENPLL_SCR_CH3_UNUSED - ch4_unused genpll_scr 5 BCM_NS2_GENPLL_SCR_CH4_UNUSED - ch5_unused genpll_scr 6 BCM_NS2_GENPLL_SCR_CH5_UNUSED - - genpll_sw crystal 0 BCM_NS2_GENPLL_SW - rpe genpll_sw 1 BCM_NS2_GENPLL_SW_RPE_CLK - 250 genpll_sw 2 BCM_NS2_GENPLL_SW_250_CLK - nic genpll_sw 3 BCM_NS2_GENPLL_SW_NIC_CLK - chimp genpll_sw 4 BCM_NS2_GENPLL_SW_CHIMP_CLK - port genpll_sw 5 BCM_NS2_GENPLL_SW_PORT_CLK - sdio genpll_sw 6 BCM_NS2_GENPLL_SW_SDIO_CLK - - lcpll_ddr crystal 0 BCM_NS2_LCPLL_DDR - pcie_sata_usb lcpll_ddr 1 BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK - ddr lcpll_ddr 2 BCM_NS2_LCPLL_DDR_DDR_CLK - ch2_unused lcpll_ddr 3 BCM_NS2_LCPLL_DDR_CH2_UNUSED - ch3_unused lcpll_ddr 4 BCM_NS2_LCPLL_DDR_CH3_UNUSED - ch4_unused lcpll_ddr 5 BCM_NS2_LCPLL_DDR_CH4_UNUSED - ch5_unused lcpll_ddr 6 BCM_NS2_LCPLL_DDR_CH5_UNUSED - - lcpll_ports crystal 0 BCM_NS2_LCPLL_PORTS - wan lcpll_ports 1 BCM_NS2_LCPLL_PORTS_WAN_CLK - rgmii lcpll_ports 2 BCM_NS2_LCPLL_PORTS_RGMII_CLK - ch2_unused lcpll_ports 3 BCM_NS2_LCPLL_PORTS_CH2_UNUSED - ch3_unused lcpll_ports 4 BCM_NS2_LCPLL_PORTS_CH3_UNUSED - ch4_unused lcpll_ports 5 BCM_NS2_LCPLL_PORTS_CH4_UNUSED - ch5_unused lcpll_ports 6 BCM_NS2_LCPLL_PORTS_CH5_UNUSED - -BCM63138 --------- -PLL and leaf clock compatible strings for BCM63138 are: - "brcm,bcm63138-armpll" - -Stingray ------------ -PLL and leaf clock compatible strings for Stingray are: - "brcm,sr-genpll0" - "brcm,sr-genpll1" - "brcm,sr-genpll2" - "brcm,sr-genpll3" - "brcm,sr-genpll4" - "brcm,sr-genpll5" - "brcm,sr-genpll6" - - "brcm,sr-lcpll0" - "brcm,sr-lcpll1" - "brcm,sr-lcpll-pcie" - - -The following table defines the set of PLL/clock index and ID for Stingray. -These clock IDs are defined in: - "include/dt-bindings/clock/bcm-sr.h" - - Clock Source Index ID - --- ----- ----- --------- - crystal N/A N/A N/A - crmu_ref25m crystal N/A N/A - - genpll0 crystal 0 BCM_SR_GENPLL0 - clk_125m genpll0 1 BCM_SR_GENPLL0_125M_CLK - clk_scr genpll0 2 BCM_SR_GENPLL0_SCR_CLK - clk_250 genpll0 3 BCM_SR_GENPLL0_250M_CLK - clk_pcie_axi genpll0 4 BCM_SR_GENPLL0_PCIE_AXI_CLK - clk_paxc_axi_x2 genpll0 5 BCM_SR_GENPLL0_PAXC_AXI_X2_CLK - clk_paxc_axi genpll0 6 BCM_SR_GENPLL0_PAXC_AXI_CLK - - genpll1 crystal 0 BCM_SR_GENPLL1 - clk_pcie_tl genpll1 1 BCM_SR_GENPLL1_PCIE_TL_CLK - clk_mhb_apb genpll1 2 BCM_SR_GENPLL1_MHB_APB_CLK - - genpll2 crystal 0 BCM_SR_GENPLL2 - clk_nic genpll2 1 BCM_SR_GENPLL2_NIC_CLK - clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK - clk_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK - clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_CLK - clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH_CLK - clk_fs genpll2 6 BCM_SR_GENPLL2_FS_CLK - - genpll3 crystal 0 BCM_SR_GENPLL3 - clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK - clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK - - genpll4 crystal 0 BCM_SR_GENPLL4 - clk_ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK - clk_tpiu_pll genpll4 2 BCM_SR_GENPLL4_TPIU_PLL_CLK - clk_noc genpll4 3 BCM_SR_GENPLL4_NOC_CLK - clk_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK - clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK - - genpll5 crystal 0 BCM_SR_GENPLL5 - clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK - clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK - clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK - - genpll6 crystal 0 BCM_SR_GENPLL6 - clk_48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK - - lcpll0 crystal 0 BCM_SR_LCPLL0 - clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK - clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK - clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK - clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK - - lcpll1 crystal 0 BCM_SR_LCPLL1 - clk_wan lcpll1 1 BCM_SR_LCPLL1_WAN_CLK - clk_usb_ref lcpll1 2 BCM_SR_LCPLL1_USB_REF_CLK - clk_crmu_ts lcpll1 3 BCM_SR_LCPLL1_CRMU_TS_CLK - - lcpll_pcie crystal 0 BCM_SR_LCPLL_PCIE - clk_pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.yaml b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.yaml new file mode 100644 index 000000000000..8dc7b404ee12 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.yaml @@ -0,0 +1,395 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/brcm,iproc-clocks.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom iProc Family Clocks + +maintainers: + - Ray Jui + - Scott Branden + +description: | + The iProc clock controller manages clocks that are common to the iProc family. + An SoC from the iProc family may have several PLLs, e.g., ARMPLL, GENPLL, + LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL + comprises of several leaf clocks + + ASIU clocks are a special case. These clocks are derived directly from the + reference clock of the onboard crystal. + +properties: + compatible: + enum: + - brcm,bcm63138-armpll + - brcm,cygnus-armpll + - brcm,cygnus-genpll + - brcm,cygnus-lcpll0 + - brcm,cygnus-mipipll + - brcm,cygnus-asiu-clk + - brcm,cygnus-audiopll + - brcm,hr2-armpll + - brcm,nsp-armpll + - brcm,nsp-genpll + - brcm,nsp-lcpll0 + - brcm,ns2-genpll-scr + - brcm,ns2-genpll-sw + - brcm,ns2-lcpll-ddr + - brcm,ns2-lcpll-ports + - brcm,sr-genpll0 + - brcm,sr-genpll1 + - brcm,sr-genpll2 + - brcm,sr-genpll3 + - brcm,sr-genpll4 + - brcm,sr-genpll5 + - brcm,sr-genpll6 + - brcm,sr-lcpll0 + - brcm,sr-lcpll1 + - brcm,sr-lcpll-pcie + + reg: + minItems: 1 + maxItems: 3 + items: + - description: base register + - description: power register + - description: ASIU or split status register + + clocks: + description: The input parent clock phandle for the PLL / ASIU clock. For + most iProc PLLs, this is an onboard crystal with a fixed rate. + maxItems: 1 + + '#clock-cells': + const: 1 + + clock-output-names: + minItems: 1 + maxItems: 45 + +allOf: + - if: + properties: + compatible: + contains: + enum: + - brcm,cygnus-armpll + - brcm,cygnus-genpll + - brcm,cygnus-lcpll0 + - brcm,cygnus-mipipll + - brcm,cygnus-asiu-clk + - brcm,cygnus-audiopll + then: + properties: + clock-output-names: + description: | + The following table defines the set of PLL/clock index and ID for Cygnus. + These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source (Parent) Index ID + ----- --------------- ----- -- + crystal N/A N/A N/A + + armpll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + genpll crystal 0 BCM_CYGNUS_GENPLL + axi21 genpll 1 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 2 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 3 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 4 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 5 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 6 BCM_CYGNUS_GENPLL_CAN_CLK + + lcpll0 crystal 0 BCM_CYGNUS_LCPLL0 + pcie_phy lcpll0 1 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 2 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 3 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 4 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 5 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5_unused lcpll0 6 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + mipipll crystal 0 BCM_CYGNUS_MIPIPLL + ch0_unused mipipll 1 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 2 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_v3d mipipll 3 BCM_CYGNUS_MIPIPLL_CH2_V3D + ch3_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 6 BCM_CYGNUS_MIPIPLL_CH5_UNUSED + + audiopll crystal 0 BCM_CYGNUS_AUDIOPLL + ch0_audio audiopll 1 BCM_CYGNUS_AUDIOPLL_CH0 + ch1_audio audiopll 2 BCM_CYGNUS_AUDIOPLL_CH1 + ch2_audio audiopll 3 BCM_CYGNUS_AUDIOPLL_CH2 + - if: + properties: + compatible: + contains: + enum: + - brcm,hr2-armpll + then: + properties: + clock-output-names: + description: | + The following table defines the set of PLL/clock for Hurricane 2: + + Clock Source Index ID + ----- ------ ----- -- + crystal N/A N/A N/A + + armpll crystal N/A N/A + - if: + properties: + compatible: + contains: + enum: + - brcm,nsp-armpll + - brcm,nsp-genpll + - brcm,nsp-lcpll0 + then: + properties: + clock-output-names: + description: | + The following table defines the set of PLL/clock index and ID for Northstar and + Northstar Plus. These clock IDs are defined in: + "include/dt-bindings/clock/bcm-nsp.h" + + Clock Source Index ID + ----- ------ ----- -- + crystal N/A N/A N/A + + armpll crystal N/A N/A + + genpll crystal 0 BCM_NSP_GENPLL + phy genpll 1 BCM_NSP_GENPLL_PHY_CLK + ethernetclk genpll 2 BCM_NSP_GENPLL_ENET_SW_CLK + usbclk genpll 3 BCM_NSP_GENPLL_USB_PHY_REF_CLK + iprocfast genpll 4 BCM_NSP_GENPLL_IPROCFAST_CLK + sata1 genpll 5 BCM_NSP_GENPLL_SATA1_CLK + sata2 genpll 6 BCM_NSP_GENPLL_SATA2_CLK + + lcpll0 crystal 0 BCM_NSP_LCPLL0 + pcie_phy lcpll0 1 BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK + sdio lcpll0 2 BCM_NSP_LCPLL0_SDIO_CLK + ddr_phy lcpll0 3 BCM_NSP_LCPLL0_DDR_PHY_CLK + - if: + properties: + compatible: + contains: + enum: + - brcm,ns2-genpll-scr + - brcm,ns2-genpll-sw + - brcm,ns2-lcpll-ddr + - brcm,ns2-lcpll-ports + then: + properties: + clock-output-names: + description: | + The following table defines the set of PLL/clock index and ID for Northstar 2. + These clock IDs are defined in: + "include/dt-bindings/clock/bcm-ns2.h" + + Clock Source Index ID + ----- ------ ----- -- + crystal N/A N/A N/A + + genpll_scr crystal 0 BCM_NS2_GENPLL_SCR + scr genpll_scr 1 BCM_NS2_GENPLL_SCR_SCR_CLK + fs genpll_scr 2 BCM_NS2_GENPLL_SCR_FS_CLK + audio_ref genpll_scr 3 BCM_NS2_GENPLL_SCR_AUDIO_CLK + ch3_unused genpll_scr 4 BCM_NS2_GENPLL_SCR_CH3_UNUSED + ch4_unused genpll_scr 5 BCM_NS2_GENPLL_SCR_CH4_UNUSED + ch5_unused genpll_scr 6 BCM_NS2_GENPLL_SCR_CH5_UNUSED + + genpll_sw crystal 0 BCM_NS2_GENPLL_SW + rpe genpll_sw 1 BCM_NS2_GENPLL_SW_RPE_CLK + 250 genpll_sw 2 BCM_NS2_GENPLL_SW_250_CLK + nic genpll_sw 3 BCM_NS2_GENPLL_SW_NIC_CLK + chimp genpll_sw 4 BCM_NS2_GENPLL_SW_CHIMP_CLK + port genpll_sw 5 BCM_NS2_GENPLL_SW_PORT_CLK + sdio genpll_sw 6 BCM_NS2_GENPLL_SW_SDIO_CLK + + lcpll_ddr crystal 0 BCM_NS2_LCPLL_DDR + pcie_sata_usb lcpll_ddr 1 BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK + ddr lcpll_ddr 2 BCM_NS2_LCPLL_DDR_DDR_CLK + ch2_unused lcpll_ddr 3 BCM_NS2_LCPLL_DDR_CH2_UNUSED + ch3_unused lcpll_ddr 4 BCM_NS2_LCPLL_DDR_CH3_UNUSED + ch4_unused lcpll_ddr 5 BCM_NS2_LCPLL_DDR_CH4_UNUSED + ch5_unused lcpll_ddr 6 BCM_NS2_LCPLL_DDR_CH5_UNUSED + + lcpll_ports crystal 0 BCM_NS2_LCPLL_PORTS + wan lcpll_ports 1 BCM_NS2_LCPLL_PORTS_WAN_CLK + rgmii lcpll_ports 2 BCM_NS2_LCPLL_PORTS_RGMII_CLK + ch2_unused lcpll_ports 3 BCM_NS2_LCPLL_PORTS_CH2_UNUSED + ch3_unused lcpll_ports 4 BCM_NS2_LCPLL_PORTS_CH3_UNUSED + ch4_unused lcpll_ports 5 BCM_NS2_LCPLL_PORTS_CH4_UNUSED + ch5_unused lcpll_ports 6 BCM_NS2_LCPLL_PORTS_CH5_UNUSED + - if: + properties: + compatible: + contains: + enum: + - brcm,sr-genpll0 + - brcm,sr-genpll1 + - brcm,sr-genpll2 + - brcm,sr-genpll3 + - brcm,sr-genpll4 + - brcm,sr-genpll5 + - brcm,sr-genpll6 + - brcm,sr-lcpll0 + - brcm,sr-lcpll1 + - brcm,sr-lcpll-pcie + then: + properties: + clock-output-names: + description: | + The following table defines the set of PLL/clock index and ID for Stingray. + These clock IDs are defined in: + "include/dt-bindings/clock/bcm-sr.h" + + Clock Source Index ID + ----- ------ ----- -- + crystal N/A N/A N/A + crmu_ref25m crystal N/A N/A + + genpll0 crystal 0 BCM_SR_GENPLL0 + clk_125m genpll0 1 BCM_SR_GENPLL0_125M_CLK + clk_scr genpll0 2 BCM_SR_GENPLL0_SCR_CLK + clk_250 genpll0 3 BCM_SR_GENPLL0_250M_CLK + clk_pcie_axi genpll0 4 BCM_SR_GENPLL0_PCIE_AXI_CLK + clk_paxc_axi_x2 genpll0 5 BCM_SR_GENPLL0_PAXC_AXI_X2_CLK + clk_paxc_axi genpll0 6 BCM_SR_GENPLL0_PAXC_AXI_CLK + + genpll1 crystal 0 BCM_SR_GENPLL1 + clk_pcie_tl genpll1 1 BCM_SR_GENPLL1_PCIE_TL_CLK + clk_mhb_apb genpll1 2 BCM_SR_GENPLL1_MHB_APB_CLK + + genpll2 crystal 0 BCM_SR_GENPLL2 + clk_nic genpll2 1 BCM_SR_GENPLL2_NIC_CLK + clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK + clk_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK + clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_CLK + clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH_CLK + clk_fs genpll2 6 BCM_SR_GENPLL2_FS_CLK + + genpll3 crystal 0 BCM_SR_GENPLL3 + clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK + clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK + + genpll4 crystal 0 BCM_SR_GENPLL4 + clk_ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK + clk_tpiu_pll genpll4 2 BCM_SR_GENPLL4_TPIU_PLL_CLK + clk_noc genpll4 3 BCM_SR_GENPLL4_NOC_CLK + clk_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK + clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK + + genpll5 crystal 0 BCM_SR_GENPLL5 + clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK + clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK + clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK + + genpll6 crystal 0 BCM_SR_GENPLL6 + clk_48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK + + lcpll0 crystal 0 BCM_SR_LCPLL0 + clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK + clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK + clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK + clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK + + lcpll1 crystal 0 BCM_SR_LCPLL1 + clk_wan lcpll1 1 BCM_SR_LCPLL1_WAN_CLK + clk_usb_ref lcpll1 2 BCM_SR_LCPLL1_USB_REF_CLK + clk_crmu_ts lcpll1 3 BCM_SR_LCPLL1_CRMU_TS_CLK + + lcpll_pcie crystal 0 BCM_SR_LCPLL_PCIE + clk_pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK + - if: + properties: + compatible: + contains: + const: brcm,cygnus-genpll + then: + properties: + clock-output-names: + items: + - const: genpll + - const: axi21 + - const: 250mhz + - const: ihost_sys + - const: enet_sw + - const: audio_125 + - const: can + - if: + properties: + compatible: + contains: + const: brcm,nsp-lcpll0 + then: + properties: + clock-output-names: + items: + - const: lcpll0 + - const: pcie_phy + - const: sdio + - const: ddr_phy + - if: + properties: + compatible: + contains: + const: brcm,nsp-genpll + then: + properties: + clock-output-names: + items: + - const: genpll + - const: phy + - const: ethernetclk + - const: usbclk + - const: iprocfast + - const: sata1 + - const: sata2 + +required: + - reg + - clocks + - '#clock-cells' + - clock-output-names + +additionalProperties: false + +examples: + - | + osc1: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll@301d000 { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll"; + reg = <0x301d000 0x2c>, <0x301c020 0x4>; + clocks = <&os1c>; + clock-output-names = "genpll", "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + - | + osc2: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks@301d048 { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x301d048 0xc>, <0x180aa024 0x4>; + clocks = <&osc2>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt deleted file mode 100644 index 9acea9d93160..000000000000 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt +++ /dev/null @@ -1,63 +0,0 @@ -NVIDIA Tegra114 Clock And Reset Controller - -This binding uses the common clock binding: -Documentation/devicetree/bindings/clock/clock-bindings.txt - -The CAR (Clock And Reset) Controller on Tegra is the HW module responsible -for muxing and gating Tegra's clocks, and setting their rates. - -Required properties : -- compatible : Should be "nvidia,tegra114-car" -- reg : Should contain CAR registers location and length -- clocks : Should contain phandle and clock specifiers for two clocks: - the 32 KHz "32k_in", and the board-specific oscillator "osc". -- #clock-cells : Should be 1. - In clock consumers, this cell represents the clock ID exposed by the - CAR. The assignments may be found in header file - . -- #reset-cells : Should be 1. - In clock consumers, this cell represents the bit number in the CAR's - array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. - -Example SoC include file: - -/ { - tegra_car: clock { - compatible = "nvidia,tegra114-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - usb@c5004000 { - clocks = <&tegra_car TEGRA114_CLK_USB2>; - }; -}; - -Example board file: - -/ { - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - osc: clock@0 { - compatible = "fixed-clock"; - reg = <0>; - #clock-cells = <0>; - clock-frequency = <12000000>; - }; - - clk_32k: clock@1 { - compatible = "fixed-clock"; - reg = <1>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - &tegra_car { - clocks = <&clk_32k> <&osc>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt deleted file mode 100644 index 7f02fb4ca4ad..000000000000 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt +++ /dev/null @@ -1,107 +0,0 @@ -NVIDIA Tegra124 and Tegra132 Clock And Reset Controller - -This binding uses the common clock binding: -Documentation/devicetree/bindings/clock/clock-bindings.txt - -The CAR (Clock And Reset) Controller on Tegra is the HW module responsible -for muxing and gating Tegra's clocks, and setting their rates. - -Required properties : -- compatible : Should be "nvidia,tegra124-car" or "nvidia,tegra132-car" -- reg : Should contain CAR registers location and length -- clocks : Should contain phandle and clock specifiers for two clocks: - the 32 KHz "32k_in", and the board-specific oscillator "osc". -- #clock-cells : Should be 1. - In clock consumers, this cell represents the clock ID exposed by the - CAR. The assignments may be found in the header files - (which covers IDs common - to Tegra124 and Tegra132) and - (for Tegra124-specific clocks). -- #reset-cells : Should be 1. - In clock consumers, this cell represents the bit number in the CAR's - array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. -- nvidia,external-memory-controller : phandle of the EMC driver. - -The node should contain a "emc-timings" subnode for each supported RAM type (see -field RAM_CODE in register PMC_STRAPPING_OPT_A). - -Required properties for "emc-timings" nodes : -- nvidia,ram-code : Should contain the value of RAM_CODE this timing set - is used for. - -Each "emc-timings" node should contain a "timing" subnode for every supported -EMC clock rate. - -Required properties for "timing" nodes : -- clock-frequency : Should contain the memory clock rate to which this timing -relates. -- nvidia,parent-clock-frequency : Should contain the rate at which the current -parent of the EMC clock should be running at this timing. -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - emc-parent : the clock that should be the parent of the EMC clock at this -timing. - -Example SoC include file: - -/ { - tegra_car: clock@60006000 { - compatible = "nvidia,tegra124-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - nvidia,external-memory-controller = <&emc>; - }; - - usb@c5004000 { - clocks = <&tegra_car TEGRA124_CLK_USB2>; - }; -}; - -Example board file: - -/ { - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - osc: clock@0 { - compatible = "fixed-clock"; - reg = <0>; - #clock-cells = <0>; - clock-frequency = <112400000>; - }; - - clk_32k: clock@1 { - compatible = "fixed-clock"; - reg = <1>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - &tegra_car { - clocks = <&clk_32k> <&osc>; - }; - - clock@60006000 { - emc-timings-3 { - nvidia,ram-code = <3>; - - timing-12750000 { - clock-frequency = <12750000>; - nvidia,parent-clock-frequency = <408000000>; - clocks = <&tegra_car TEGRA124_CLK_PLL_P>; - clock-names = "emc-parent"; - }; - timing-20400000 { - clock-frequency = <20400000>; - nvidia,parent-clock-frequency = <408000000>; - clocks = <&tegra_car TEGRA124_CLK_PLL_P>; - clock-names = "emc-parent"; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.yaml b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.yaml new file mode 100644 index 000000000000..ec7ab1483652 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.yaml @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/nvidia,tegra124-car.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Clock and Reset Controller + +maintainers: + - Jon Hunter + - Thierry Reding + +description: | + The Clock and Reset (CAR) is the HW module responsible for muxing and gating + Tegra's clocks, and setting their rates. It comprises CLKGEN and RSTGEN units. + + CLKGEN provides the registers to program the PLLs. It controls most of + the clock source programming and most of the clock dividers. + + CLKGEN input signals include the external clock for the reference frequency + (12 MHz, 26 MHz) and the external clock for the Real Time Clock (32.768 KHz). + + Outputs from CLKGEN are inputs clock of the h/w blocks in the Tegra system. + + RSTGEN provides the registers needed to control resetting of each block in + the Tegra system. + +properties: + compatible: + const: nvidia,tegra124-car + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + "#reset-cells": + const: 1 + + nvidia,external-memory-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle of the external memory controller node + +patternProperties: + "^emc-timings-[0-9]+$": + type: object + properties: + nvidia,ram-code: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + value of the RAM_CODE field in the PMC_STRAPPING_OPT_A register that + this timing set is used for + + patternProperties: + "^timing-[0-9]+$": + type: object + properties: + clock-frequency: + description: + external memory clock rate in Hz + minimum: 1000000 + maximum: 1000000000 + + nvidia,parent-clock-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + rate of parent clock in Hz + minimum: 1000000 + maximum: 1000000000 + + clocks: + items: + - description: parent clock of EMC + + clock-names: + items: + - const: emc-parent + + required: + - clock-frequency + - nvidia,parent-clock-frequency + - clocks + - clock-names + + additionalProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - '#clock-cells' + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + + car: clock-controller@60006000 { + compatible = "nvidia,tegra124-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb-controller@c5004000 { + compatible = "nvidia,tegra20-ehci"; + reg = <0xc5004000 0x4000>; + clocks = <&car TEGRA124_CLK_USB2>; + resets = <&car TEGRA124_CLK_USB2>; + }; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt deleted file mode 100644 index 6c5901b503d0..000000000000 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +++ /dev/null @@ -1,63 +0,0 @@ -NVIDIA Tegra20 Clock And Reset Controller - -This binding uses the common clock binding: -Documentation/devicetree/bindings/clock/clock-bindings.txt - -The CAR (Clock And Reset) Controller on Tegra is the HW module responsible -for muxing and gating Tegra's clocks, and setting their rates. - -Required properties : -- compatible : Should be "nvidia,tegra20-car" -- reg : Should contain CAR registers location and length -- clocks : Should contain phandle and clock specifiers for two clocks: - the 32 KHz "32k_in", and the board-specific oscillator "osc". -- #clock-cells : Should be 1. - In clock consumers, this cell represents the clock ID exposed by the - CAR. The assignments may be found in header file - . -- #reset-cells : Should be 1. - In clock consumers, this cell represents the bit number in the CAR's - array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. - -Example SoC include file: - -/ { - tegra_car: clock { - compatible = "nvidia,tegra20-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - usb@c5004000 { - clocks = <&tegra_car TEGRA20_CLK_USB2>; - }; -}; - -Example board file: - -/ { - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - osc: clock@0 { - compatible = "fixed-clock"; - reg = <0>; - #clock-cells = <0>; - clock-frequency = <12000000>; - }; - - clk_32k: clock@1 { - compatible = "fixed-clock"; - reg = <1>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - &tegra_car { - clocks = <&clk_32k> <&osc>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml new file mode 100644 index 000000000000..459d2a525393 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/nvidia,tegra20-car.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Clock and Reset Controller + +maintainers: + - Jon Hunter + - Thierry Reding + +description: | + The Clock and Reset (CAR) is the HW module responsible for muxing and gating + Tegra's clocks, and setting their rates. It comprises CLKGEN and RSTGEN units. + + CLKGEN provides the registers to program the PLLs. It controls most of + the clock source programming and most of the clock dividers. + + CLKGEN input signals include the external clock for the reference frequency + (12 MHz, 26 MHz) and the external clock for the Real Time Clock (32.768 KHz). + + Outputs from CLKGEN are inputs clock of the h/w blocks in the Tegra system. + + RSTGEN provides the registers needed to control resetting of each block in + the Tegra system. + +properties: + compatible: + enum: + - nvidia,tegra20-car + - nvidia,tegra30-car + - nvidia,tegra114-car + - nvidia,tegra210-car + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + + car: clock-controller@60006000 { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb-controller@c5004000 { + compatible = "nvidia,tegra20-ehci"; + reg = <0xc5004000 0x4000>; + clocks = <&car TEGRA20_CLK_USB2>; + resets = <&car TEGRA20_CLK_USB2>; + }; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt deleted file mode 100644 index 26f237f641b7..000000000000 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt +++ /dev/null @@ -1,56 +0,0 @@ -NVIDIA Tegra210 Clock And Reset Controller - -This binding uses the common clock binding: -Documentation/devicetree/bindings/clock/clock-bindings.txt - -The CAR (Clock And Reset) Controller on Tegra is the HW module responsible -for muxing and gating Tegra's clocks, and setting their rates. - -Required properties : -- compatible : Should be "nvidia,tegra210-car" -- reg : Should contain CAR registers location and length -- clocks : Should contain phandle and clock specifiers for two clocks: - the 32 KHz "32k_in". -- #clock-cells : Should be 1. - In clock consumers, this cell represents the clock ID exposed by the - CAR. The assignments may be found in header file - . -- #reset-cells : Should be 1. - In clock consumers, this cell represents the bit number in the CAR's - array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. - -Example SoC include file: - -/ { - tegra_car: clock { - compatible = "nvidia,tegra210-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - usb@c5004000 { - clocks = <&tegra_car TEGRA210_CLK_USB2>; - }; -}; - -Example board file: - -/ { - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - clk_32k: clock@1 { - compatible = "fixed-clock"; - reg = <1>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - &tegra_car { - clocks = <&clk_32k>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt deleted file mode 100644 index 63618cde12df..000000000000 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt +++ /dev/null @@ -1,63 +0,0 @@ -NVIDIA Tegra30 Clock And Reset Controller - -This binding uses the common clock binding: -Documentation/devicetree/bindings/clock/clock-bindings.txt - -The CAR (Clock And Reset) Controller on Tegra is the HW module responsible -for muxing and gating Tegra's clocks, and setting their rates. - -Required properties : -- compatible : Should be "nvidia,tegra30-car" -- reg : Should contain CAR registers location and length -- clocks : Should contain phandle and clock specifiers for two clocks: - the 32 KHz "32k_in", and the board-specific oscillator "osc". -- #clock-cells : Should be 1. - In clock consumers, this cell represents the clock ID exposed by the - CAR. The assignments may be found in header file - . -- #reset-cells : Should be 1. - In clock consumers, this cell represents the bit number in the CAR's - array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. - -Example SoC include file: - -/ { - tegra_car: clock { - compatible = "nvidia,tegra30-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - usb@c5004000 { - clocks = <&tegra_car TEGRA30_CLK_USB2>; - }; -}; - -Example board file: - -/ { - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - osc: clock@0 { - compatible = "fixed-clock"; - reg = <0>; - #clock-cells = <0>; - clock-frequency = <12000000>; - }; - - clk_32k: clock@1 { - compatible = "fixed-clock"; - reg = <1>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - &tegra_car { - clocks = <&clk_32k> <&osc>; - }; -}; diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt index ea4994b35207..ef68711716fb 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt @@ -202,11 +202,11 @@ Example 2 (MT8173 SoC): cpu2: cpu@100 { device_type = "cpu"; - compatible = "arm,cortex-a57"; + compatible = "arm,cortex-a72"; reg = <0x100>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; - clocks = <&infracfg CLK_INFRA_CA57SEL>, + clocks = <&infracfg CLK_INFRA_CA72SEL>, <&apmixedsys CLK_APMIXED_MAINPLL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cpu_opp_table_b>; @@ -214,11 +214,11 @@ Example 2 (MT8173 SoC): cpu3: cpu@101 { device_type = "cpu"; - compatible = "arm,cortex-a57"; + compatible = "arm,cortex-a72"; reg = <0x101>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; - clocks = <&infracfg CLK_INFRA_CA57SEL>, + clocks = <&infracfg CLK_INFRA_CA72SEL>, <&apmixedsys CLK_APMIXED_MAINPLL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cpu_opp_table_b>; diff --git a/Documentation/devicetree/bindings/dvfs/performance-domain.yaml b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml new file mode 100644 index 000000000000..c8b91207f34d --- /dev/null +++ b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dvfs/performance-domain.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic performance domains + +maintainers: + - Sudeep Holla + +description: |+ + This binding is intended for performance management of groups of devices or + CPUs that run in the same performance domain. Performance domains must not + be confused with power domains. A performance domain is defined by a set + of devices that always have to run at the same performance level. For a given + performance domain, there is a single point of control that affects all the + devices in the domain, making it impossible to set the performance level of + an individual device in the domain independently from other devices in + that domain. For example, a set of CPUs that share a voltage domain, and + have a common frequency control, is said to be in the same performance + domain. + + This device tree binding can be used to bind performance domain consumer + devices with their performance domains provided by performance domain + providers. A performance domain provider can be represented by any node in + the device tree and can provide one or more performance domains. A consumer + node can refer to the provider by a phandle and a set of phandle arguments + (so called performance domain specifiers) of length specified by the + \#performance-domain-cells property in the performance domain provider node. + +select: true + +properties: + "#performance-domain-cells": + description: + Number of cells in a performance domain specifier. Typically 0 for nodes + representing a single performance domain and 1 for nodes providing + multiple performance domains (e.g. performance controllers), but can be + any value as specified by device tree binding documentation of particular + provider. + enum: [ 0, 1 ] + + performance-domains: + $ref: '/schemas/types.yaml#/definitions/phandle-array' + maxItems: 1 + description: + A phandle and performance domain specifier as defined by bindings of the + performance controller/provider specified by phandle. + +additionalProperties: true + +examples: + - | + performance: performance-controller@12340000 { + compatible = "qcom,cpufreq-hw"; + reg = <0x12340000 0x1000>; + #performance-domain-cells = <1>; + }; + + // The node above defines a performance controller that is a performance + // domain provider and expects one cell as its phandle argument. + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x0>; + performance-domains = <&performance 1>; + }; + }; diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index e747d73687cb..a7333ad938d2 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -12,6 +12,7 @@ Required properties: * "qcom,scm-ipq4019" * "qcom,scm-ipq806x" * "qcom,scm-ipq8074" + * "qcom,scm-mdm9607" * "qcom,scm-msm8660" * "qcom,scm-msm8916" * "qcom,scm-msm8960" diff --git a/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml b/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml new file mode 100644 index 000000000000..10e5a53e447b --- /dev/null +++ b/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwlock/allwinner,sun6i-a31-hwspinlock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SUN6I hardware spinlock driver for Allwinner sun6i compatible SoCs + +maintainers: + - Wilken Gottwalt + +description: + The hardware unit provides semaphores between the ARM cores and the embedded + companion core on the SoC. + +properties: + compatible: + const: allwinner,sun6i-a31-hwspinlock + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - resets + +additionalProperties: false + +examples: + - | + #include + #include + + hwlock@1c18000 { + compatible = "allwinner,sun6i-a31-hwspinlock"; + reg = <0x01c18000 0x1000>; + clocks = <&ccu CLK_BUS_SPINLOCK>; + resets = <&ccu RST_BUS_SPINLOCK>; + }; +... diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt index 96c914e048f5..2015f50aed0f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt @@ -73,7 +73,7 @@ i2c0: i2c@f8034600 { pinctrl-0 = <&pinctrl_i2c0>; pinctrl-1 = <&pinctrl_i2c0_gpio>; sda-gpios = <&pioA 30 GPIO_ACTIVE_HIGH>; - scl-gpios = <&pioA 31 GPIO_ACTIVE_HIGH>; + scl-gpios = <&pioA 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; wm8731: wm8731@1a { compatible = "wm8731"; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 9d27aa5111d4..1181b590db71 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -54,8 +54,14 @@ properties: - const: arm,mmu-500 - description: NVIDIA SoCs that program two ARM MMU-500s identically items: + - description: NVIDIA SoCs that require memory controller interaction + and may program multiple ARM MMU-500s identically with the memory + controller interleaving translations between multiple instances + for improved performance. + items: - enum: - - nvidia,tegra194-smmu + - const: nvidia,tegra194-smmu + - const: nvidia,tegra186-smmu - const: nvidia,smmu-500 - items: - const: arm,mmu-500 @@ -165,10 +171,11 @@ allOf: contains: enum: - nvidia,tegra194-smmu + - nvidia,tegra186-smmu then: properties: reg: - minItems: 2 + minItems: 1 maxItems: 2 else: properties: diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.yaml b/Documentation/devicetree/bindings/net/stm32-dwmac.yaml index 19c7bd482a51..d3f05d5934d5 100644 --- a/Documentation/devicetree/bindings/net/stm32-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/stm32-dwmac.yaml @@ -52,10 +52,11 @@ properties: - description: MAC RX clock - description: For MPU family, used for power mode - description: For MPU family, used for PHY without quartz + - description: PTP clock clock-names: minItems: 3 - maxItems: 5 + maxItems: 6 contains: enum: - stmmaceth @@ -63,6 +64,7 @@ properties: - mac-clk-rx - ethstp - eth-ck + - ptp_ref st,syscon: $ref: "/schemas/types.yaml#/definitions/phandle-array" diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index de4b2baf91e8..d8971ab99274 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt @@ -38,6 +38,9 @@ Optional properties: The regulator will be enabled when initializing the PCIe host and disabled either as part of the init process or when shutting down the host. +- vph-supply: Should specify the regulator in charge of VPH one of the three + PCIe PHY powers. This regulator can be supplied by both 1.8v and 3.3v voltage + supplies. Additional required properties for imx6sx-pcie: - clock names: Must include the following additional entries: diff --git a/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml b/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml new file mode 100644 index 000000000000..debfb54a8042 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/intel,ixp4xx-pci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel IXP4xx PCI controller + +maintainers: + - Linus Walleij + +description: PCI host controller found in the Intel IXP4xx SoC series. + +allOf: + - $ref: /schemas/pci/pci-bus.yaml# + +properties: + compatible: + items: + - enum: + - intel,ixp42x-pci + - intel,ixp43x-pci + description: The two supported variants are ixp42x and ixp43x, + though more variants may exist. + + reg: + items: + - description: IXP4xx-specific registers + + interrupts: + items: + - description: Main PCI interrupt + - description: PCI DMA interrupt 1 + - description: PCI DMA interrupt 2 + + ranges: + maxItems: 2 + description: Typically one memory range of 64MB and one IO + space range of 64KB. + + dma-ranges: + maxItems: 1 + description: The DMA range tells the PCI host which addresses + the RAM is at. It can map only 64MB so if the RAM is bigger + than 64MB the DMA access has to be restricted to these + addresses. + + "#interrupt-cells": true + + interrupt-map: true + + interrupt-map-mask: + items: + - const: 0xf800 + - const: 0 + - const: 0 + - const: 7 + +required: + - compatible + - reg + - dma-ranges + - "#interrupt-cells" + - interrupt-map + - interrupt-map-mask + +unevaluatedProperties: false + +examples: + - | + pci@c0000000 { + compatible = "intel,ixp43x-pci"; + reg = <0xc0000000 0x1000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x00 0xff>; + + ranges = + <0x02000000 0 0x48000000 0x48000000 0 0x04000000>, + <0x01000000 0 0x00000000 0x4c000000 0 0x00010000>; + dma-ranges = + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */ + <0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */ + <0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */ + <0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */ + <0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */ + <0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */ + <0x1000 0 0 3 &gpio0 8 3>, /* INT C on slot 2 is irq 8 */ + <0x1000 0 0 4 &gpio0 11 3>, /* INT D on slot 2 is irq 11 */ + <0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */ + <0x1800 0 0 2 &gpio0 8 3>, /* INT B on slot 3 is irq 8 */ + <0x1800 0 0 3 &gpio0 11 3>, /* INT C on slot 3 is irq 11 */ + <0x1800 0 0 4 &gpio0 10 3>; /* INT D on slot 3 is irq 10 */ + }; diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt b/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt index 8c60e6985950..5ffd0f55d010 100644 --- a/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt +++ b/Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt @@ -42,22 +42,22 @@ Required properties (child nodes): Examples: - cpm_comphy: phy@120000 { + CP11X_LABEL(comphy): phy@120000 { compatible = "marvell,comphy-cp110"; reg = <0x120000 0x6000>; - marvell,system-controller = <&cpm_syscon0>; - clocks = <&CP110_LABEL(clk) 1 5>, <&CP110_LABEL(clk) 1 6>, - <&CP110_LABEL(clk) 1 18>; + marvell,system-controller = <&CP11X_LABEL(syscon0)>; + clocks = <&CP11X_LABEL(clk) 1 5>, <&CP11X_LABEL(clk) 1 6>, + <&CP11X_LABEL(clk) 1 18>; clock-names = "mg_clk", "mg_core_clk", "axi_clk"; #address-cells = <1>; #size-cells = <0>; - cpm_comphy0: phy@0 { + CP11X_LABEL(comphy0): phy@0 { reg = <0>; #phy-cells = <1>; }; - cpm_comphy1: phy@1 { + CP11X_LABEL(comphy1): phy@1 { reg = <1>; #phy-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml index a5b027a6e70f..5bebd86bf8b6 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml @@ -30,9 +30,6 @@ properties: "#clock-cells": const: 0 - "#phy-cells": - const: 0 - clocks: maxItems: 1 @@ -120,7 +117,6 @@ required: - reg - clock-output-names - "#clock-cells" - - "#phy-cells" - host-port - otg-port @@ -131,26 +127,25 @@ examples: #include #include #include - u2phy0: usb2-phy@e450 { + u2phy0: usb2phy@e450 { compatible = "rockchip,rk3399-usb2phy"; reg = <0xe450 0x10>; clocks = <&cru SCLK_USB2PHY0_REF>; clock-names = "phyclk"; clock-output-names = "clk_usbphy0_480m"; #clock-cells = <0>; - #phy-cells = <0>; u2phy0_host: host-port { - #phy-cells = <0>; interrupts = ; interrupt-names = "linestate"; + #phy-cells = <0>; }; u2phy0_otg: otg-port { - #phy-cells = <0>; interrupts = , , ; interrupt-names = "otg-bvalid", "otg-id", "linestate"; + #phy-cells = <0>; }; }; diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.yaml index a96e6dbf1858..01bdda167eef 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.yaml +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.yaml @@ -25,7 +25,9 @@ properties: compatible: enum: - fsl,imx7d-gpc + - fsl,imx8mn-gpc - fsl,imx8mq-gpc + - fsl,imx8mm-gpc reg: maxItems: 1 @@ -54,6 +56,7 @@ properties: Power domain index. Valid values are defined in include/dt-bindings/power/imx7-power.h for fsl,imx7d-gpc and include/dt-bindings/power/imx8m-power.h for fsl,imx8mq-gpc + include/dt-bindings/power/imx8mm-power.h for fsl,imx8mm-gpc maxItems: 1 clocks: @@ -66,6 +69,16 @@ properties: power-supply: true + resets: + description: | + A number of phandles to resets that need to be asserted during + power-up sequencing of the domain. The resets belong to devices + located inside the power domain, which need to be held in reset + across the power-up sequence. So no means to specify what each + reset is in a generic power-domain binding. + minItems: 1 + maxItems: 4 + required: - '#power-domain-cells' - reg diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index ff21bfef8204..4807b560f00d 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,mdm9607-rpmpd - qcom,msm8916-rpmpd - qcom,msm8939-rpmpd - qcom,msm8976-rpmpd @@ -26,6 +27,7 @@ properties: - qcom,sdm660-rpmpd - qcom,sc7180-rpmhpd - qcom,sc7280-rpmhpd + - qcom,sc8180x-rpmhpd - qcom,sdm845-rpmhpd - qcom,sdx55-rpmhpd - qcom,sm8150-rpmhpd diff --git a/Documentation/devicetree/bindings/power/renesas,rzg2l-sysc.yaml b/Documentation/devicetree/bindings/power/renesas,rzg2l-sysc.yaml new file mode 100644 index 000000000000..84ddc772b003 --- /dev/null +++ b/Documentation/devicetree/bindings/power/renesas,rzg2l-sysc.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/power/renesas,rzg2l-sysc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Renesas RZ/G2L System Controller (SYSC) + +maintainers: + - Geert Uytterhoeven + +description: + The RZ/G2L System Controller (SYSC) performs system control of the LSI and + supports following functions, + - External terminal state capture function + - 34-bit address space access function + - Low power consumption control + - WDT stop control + +properties: + compatible: + enum: + - renesas,r9a07g044-sysc # RZ/G2{L,LC} + + reg: + maxItems: 1 + + interrupts: + items: + - description: CA55/CM33 Sleep/Software Standby Mode request interrupt + - description: CA55 Software Standby Mode release request interrupt + - description: CM33 Software Standby Mode release request interrupt + - description: CA55 ACE Asynchronous Bridge Master/Slave interface deny request interrupt + + interrupt-names: + items: + - const: lpm_int + - const: ca55stbydone_int + - const: cm33stbyr_int + - const: ca55_deny + +required: + - compatible + - reg + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | + #include + + sysc: system-controller@11020000 { + compatible = "renesas,r9a07g044-sysc"; + reg = <0x11020000 0x10000>; + interrupts = , + , + , + ; + interrupt-names = "lpm_int", "ca55stbydone_int", "cm33stbyr_int", + "ca55_deny"; + }; diff --git a/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml new file mode 100644 index 000000000000..9b9d71087466 --- /dev/null +++ b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml @@ -0,0 +1,248 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/rockchip,power-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip Power Domains + +maintainers: + - Elaine Zhang + - Heiko Stuebner + +description: | + Rockchip processors include support for multiple power domains + which can be powered up/down by software based on different + application scenarios to save power. + + Power domains contained within power-controller node are + generic power domain providers documented in + Documentation/devicetree/bindings/power/power-domain.yaml. + + IP cores belonging to a power domain should contain a + "power-domains" property that is a phandle for the + power domain node representing the domain. + +properties: + $nodename: + const: power-controller + + compatible: + enum: + - rockchip,px30-power-controller + - rockchip,rk3036-power-controller + - rockchip,rk3066-power-controller + - rockchip,rk3128-power-controller + - rockchip,rk3188-power-controller + - rockchip,rk3228-power-controller + - rockchip,rk3288-power-controller + - rockchip,rk3328-power-controller + - rockchip,rk3366-power-controller + - rockchip,rk3368-power-controller + - rockchip,rk3399-power-controller + - rockchip,rk3568-power-controller + + "#power-domain-cells": + const: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +required: + - compatible + - "#power-domain-cells" + +additionalProperties: false + +patternProperties: + "^power-domain@[0-9a-f]+$": + + $ref: "#/$defs/pd-node" + + unevaluatedProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^power-domain@[0-9a-f]+$": + + $ref: "#/$defs/pd-node" + + unevaluatedProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^power-domain@[0-9a-f]+$": + + $ref: "#/$defs/pd-node" + + unevaluatedProperties: false + + properties: + "#power-domain-cells": + const: 0 + +$defs: + pd-node: + type: object + description: | + Represents the power domains within the power controller node. + + properties: + reg: + maxItems: 1 + description: | + Power domain index. Valid values are defined in + "include/dt-bindings/power/px30-power.h" + "include/dt-bindings/power/rk3036-power.h" + "include/dt-bindings/power/rk3066-power.h" + "include/dt-bindings/power/rk3128-power.h" + "include/dt-bindings/power/rk3188-power.h" + "include/dt-bindings/power/rk3228-power.h" + "include/dt-bindings/power/rk3288-power.h" + "include/dt-bindings/power/rk3328-power.h" + "include/dt-bindings/power/rk3366-power.h" + "include/dt-bindings/power/rk3368-power.h" + "include/dt-bindings/power/rk3399-power.h" + "include/dt-bindings/power/rk3568-power.h" + + clocks: + minItems: 1 + maxItems: 30 + description: | + A number of phandles to clocks that need to be enabled + while power domain switches state. + + pm_qos: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + A number of phandles to qos blocks which need to be saved and restored + while power domain switches state. + + "#power-domain-cells": + enum: [0, 1] + description: + Must be 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains. + + required: + - reg + - "#power-domain-cells" + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + qos_hdcp: qos@ffa90000 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffa90000 0x0 0x20>; + }; + + qos_iep: qos@ffa98000 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffa98000 0x0 0x20>; + }; + + qos_rga_r: qos@ffab0000 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffab0000 0x0 0x20>; + }; + + qos_rga_w: qos@ffab0080 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffab0080 0x0 0x20>; + }; + + qos_video_m0: qos@ffab8000 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffab8000 0x0 0x20>; + }; + + qos_video_m1_r: qos@ffac0000 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffac0000 0x0 0x20>; + }; + + qos_video_m1_w: qos@ffac0080 { + compatible = "rockchip,rk3399-qos", "syscon"; + reg = <0x0 0xffac0080 0x0 0x20>; + }; + + power-management@ff310000 { + compatible = "rockchip,rk3399-pmu", "syscon", "simple-mfd"; + reg = <0x0 0xff310000 0x0 0x1000>; + + power-controller { + compatible = "rockchip,rk3399-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + /* These power domains are grouped by VD_CENTER */ + power-domain@RK3399_PD_IEP { + reg = ; + clocks = <&cru ACLK_IEP>, + <&cru HCLK_IEP>; + pm_qos = <&qos_iep>; + #power-domain-cells = <0>; + }; + power-domain@RK3399_PD_RGA { + reg = ; + clocks = <&cru ACLK_RGA>, + <&cru HCLK_RGA>; + pm_qos = <&qos_rga_r>, + <&qos_rga_w>; + #power-domain-cells = <0>; + }; + power-domain@RK3399_PD_VCODEC { + reg = ; + clocks = <&cru ACLK_VCODEC>, + <&cru HCLK_VCODEC>; + pm_qos = <&qos_video_m0>; + #power-domain-cells = <0>; + }; + power-domain@RK3399_PD_VDU { + reg = ; + clocks = <&cru ACLK_VDU>, + <&cru HCLK_VDU>; + pm_qos = <&qos_video_m1_r>, + <&qos_video_m1_w>; + #power-domain-cells = <0>; + }; + power-domain@RK3399_PD_VIO { + reg = ; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3399_PD_HDCP { + reg = ; + clocks = <&cru ACLK_HDCP>, + <&cru HCLK_HDCP>, + <&cru PCLK_HDCP>; + pm_qos = <&qos_hdcp>; + #power-domain-cells = <0>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/power/supply/charger-manager.txt b/Documentation/devicetree/bindings/power/supply/charger-manager.txt deleted file mode 100644 index b5ae9061b7a0..000000000000 --- a/Documentation/devicetree/bindings/power/supply/charger-manager.txt +++ /dev/null @@ -1,91 +0,0 @@ -charger-manager bindings -~~~~~~~~~~~~~~~~~~~~~~~~ - -Required properties : - - compatible : "charger-manager" - - <>-supply : for regulator consumer, named according to cm-regulator-name - - cm-chargers : name of chargers - - cm-fuel-gauge : name of battery fuel gauge - - subnode : - - cm-regulator-name : name of charger regulator - - subnode : - - cm-cable-name : name of charger cable - one of USB, USB-HOST, - SDP, DCP, CDP, ACA, FAST-CHARGER, SLOW-CHARGER, WPT, - PD, DOCK, JIG, or MECHANICAL - - cm-cable-extcon : name of extcon dev -(optional) - cm-cable-min : minimum current of cable -(optional) - cm-cable-max : maximum current of cable - -Optional properties : - - cm-name : charger manager's name (default : "battery") - - cm-poll-mode : polling mode - 0 for disabled, 1 for always, 2 for when - external power is connected, or 3 for when charging. If not present, - then polling is disabled - - cm-poll-interval : polling interval (in ms) - - cm-battery-stat : battery status - 0 for battery always present, 1 for no - battery, 2 to check presence via fuel gauge, or 3 to check presence - via charger - - cm-fullbatt-vchkdrop-volt : voltage drop (in uV) before restarting charging - - cm-fullbatt-voltage : voltage (in uV) of full battery - - cm-fullbatt-soc : state of charge to consider as full battery - - cm-fullbatt-capacity : capcity (in uAh) to consider as full battery - - cm-thermal-zone : name of external thermometer's thermal zone - - cm-battery-* : threshold battery temperature for charging - -cold : critical cold temperature of battery for charging - -cold-in-minus : flag that cold temperature is in minus degrees - -hot : critical hot temperature of battery for charging - -temp-diff : temperature difference to allow recharging - - cm-dis/charging-max = limits of charging duration - -Deprecated properties: - - cm-num-chargers - - cm-fullbatt-vchkdrop-ms - -Example : - charger-manager@0 { - compatible = "charger-manager"; - chg-reg-supply = <&charger_regulator>; - - cm-name = "battery"; - /* Always polling ON : 30s */ - cm-poll-mode = <1>; - cm-poll-interval = <30000>; - - cm-fullbatt-vchkdrop-volt = <150000>; - cm-fullbatt-soc = <100>; - - cm-battery-stat = <3>; - - cm-chargers = "charger0", "charger1", "charger2"; - - cm-fuel-gauge = "fuelgauge0"; - - cm-thermal-zone = "thermal_zone.1" - /* in deci centigrade */ - cm-battery-cold = <50>; - cm-battery-cold-in-minus; - cm-battery-hot = <800>; - cm-battery-temp-diff = <100>; - - /* Allow charging for 5hr */ - cm-charging-max = <18000000>; - /* Allow discharging for 2hr */ - cm-discharging-max = <7200000>; - - regulator@0 { - cm-regulator-name = "chg-reg"; - cable@0 { - cm-cable-name = "USB"; - cm-cable-extcon = "extcon-dev.0"; - cm-cable-min = <475000>; - cm-cable-max = <500000>; - }; - cable@1 { - cm-cable-name = "SDP"; - cm-cable-extcon = "extcon-dev.0"; - cm-cable-min = <650000>; - cm-cable-max = <675000>; - }; - }; - - }; diff --git a/Documentation/devicetree/bindings/power/supply/charger-manager.yaml b/Documentation/devicetree/bindings/power/supply/charger-manager.yaml new file mode 100644 index 000000000000..c863cfa67865 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/charger-manager.yaml @@ -0,0 +1,215 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/charger-manager.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Charger Manager + +maintainers: + - Sebastian Reichel + +description: | + Binding for the legacy charger manager driver. + Please do not use for new products. + +properties: + compatible: + const: charger-manager + + cm-chargers: + description: name of chargers + $ref: /schemas/types.yaml#/definitions/string-array + + cm-num-chargers: + $ref: /schemas/types.yaml#/definitions/uint32 + deprecated: true + + cm-fuel-gauge: + description: name of battery fuel gauge + $ref: /schemas/types.yaml#/definitions/string + + cm-name: + description: name of the charger manager + default: battery + $ref: /schemas/types.yaml#/definitions/string + + cm-poll-mode: + description: polling mode + default: 0 + enum: + - 0 # disabled + - 1 # always + - 2 # when external power is connected + - 3 # when charging + + cm-poll-interval: + description: polling interval (in ms) + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-battery-stat: + description: battery status + enum: + - 0 # battery always present + - 1 # no battery + - 2 # check presence via fuel gauge + - 3 # check presence via charger + + cm-fullbatt-vchkdrop-volt: + description: voltage drop before restarting charging in uV + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-fullbatt-vchkdrop-ms: + deprecated: true + + cm-fullbatt-voltage: + description: voltage of full battery in uV + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-fullbatt-soc: + description: state of charge to consider as full battery in % + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-fullbatt-capacity: + description: capcity to consider as full battery in uAh + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-thermal-zone: + description: name of external thermometer's thermal zone + $ref: /schemas/types.yaml#/definitions/string + + cm-discharging-max: + description: limits of discharging duration in ms + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-charging-max: + description: limits of charging duration in ms + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-battery-cold: + description: critical cold temperature of battery for charging in deci-degree celsius + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-battery-cold-in-minus: + description: if set cm-battery-cold temperature is in minus degrees + type: boolean + + cm-battery-hot: + description: critical hot temperature of battery for charging in deci-degree celsius + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-battery-temp-diff: + description: temperature difference to allow recharging in deci-degree celsius + $ref: /schemas/types.yaml#/definitions/uint32 + +patternProperties: + "-supply$": + description: regulator consumer, named according to cm-regulator-name + $ref: /schemas/types.yaml#/definitions/phandle + + "^regulator[@-][0-9]$": + type: object + properties: + cm-regulator-name: + description: name of charger regulator + $ref: /schemas/types.yaml#/definitions/string + + required: + - cm-regulator-name + + additionalProperties: false + + patternProperties: + "^cable[@-][0-9]$": + type: object + properties: + cm-cable-name: + description: name of charger cable + enum: + - USB + - USB-HOST + - SDP + - DCP + - CDP + - ACA + - FAST-CHARGER + - SLOW-CHARGER + - WPT + - PD + - DOCK + - JIG + - MECHANICAL + + cm-cable-extcon: + description: name of extcon dev + $ref: /schemas/types.yaml#/definitions/string + + cm-cable-min: + description: minimum current of cable in uA + $ref: /schemas/types.yaml#/definitions/uint32 + + cm-cable-max: + description: maximum current of cable in uA + $ref: /schemas/types.yaml#/definitions/uint32 + + required: + - cm-cable-name + - cm-cable-extcon + + additionalProperties: false + +required: + - compatible + - cm-chargers + - cm-fuel-gauge + +additionalProperties: false + +examples: + - | + charger-manager { + compatible = "charger-manager"; + chg-reg-supply = <&charger_regulator>; + + cm-name = "battery"; + /* Always polling ON : 30s */ + cm-poll-mode = <1>; + cm-poll-interval = <30000>; + + cm-fullbatt-vchkdrop-volt = <150000>; + cm-fullbatt-soc = <100>; + + cm-battery-stat = <3>; + + cm-chargers = "charger0", "charger1", "charger2"; + + cm-fuel-gauge = "fuelgauge0"; + + cm-thermal-zone = "thermal_zone.1"; + /* in deci centigrade */ + cm-battery-cold = <50>; + cm-battery-cold-in-minus; + cm-battery-hot = <800>; + cm-battery-temp-diff = <100>; + + /* Allow charging for 5hr */ + cm-charging-max = <18000000>; + /* Allow discharging for 2hr */ + cm-discharging-max = <7200000>; + + regulator-0 { + cm-regulator-name = "chg-reg"; + cable-0 { + cm-cable-name = "USB"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <475000>; + cm-cable-max = <500000>; + }; + cable-1 { + cm-cable-name = "SDP"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <650000>; + cm-cable-max = <675000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml index de91cf3f058c..f792d06db413 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml @@ -89,7 +89,7 @@ examples: reg = <0x36>; maxim,alert-low-soc-level = <10>; interrupt-parent = <&gpio7>; - interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; wakeup-source; }; }; diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml new file mode 100644 index 000000000000..ae647d3355a2 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/power/supply/richtek,rt5033-battery.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Richtek RT5033 PMIC Fuel Gauge + +maintainers: + - Stephan Gerhold + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: richtek,rt5033-battery + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + battery@35 { + compatible = "richtek,rt5033-battery"; + reg = <0x35>; + }; + }; + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + battery@35 { + compatible = "richtek,rt5033-battery"; + reg = <0x35>; + interrupt-parent = <&msmgpio>; + interrupts = <121 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml index 54a7700df08f..800d511502c4 100644 --- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml @@ -24,6 +24,9 @@ properties: - items: - const: allwinner,sun8i-a83t-pwm - const: allwinner,sun8i-h3-pwm + - items: + - const: allwinner,sun8i-v3s-pwm + - const: allwinner,sun7i-a20-pwm - items: - const: allwinner,sun50i-a64-pwm - const: allwinner,sun5i-a13-pwm diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt deleted file mode 100644 index c7c4347a769a..000000000000 --- a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt +++ /dev/null @@ -1,51 +0,0 @@ -TI SOC ECAP based APWM controller - -Required properties: -- compatible: Must be "ti,-ecap". - for am33xx - compatible = "ti,am3352-ecap", "ti,am33xx-ecap"; - for am4372 - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; - for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; - for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap"; - for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap"; - for am654 - compatible = "ti,am654-ecap", "ti,am3352-ecap"; -- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of - the cells format. The PWM channel index ranges from 0 to 4. The only third - cell flag supported by this binding is PWM_POLARITY_INVERTED. -- reg: physical base address and size of the registers map. - -Optional properties: -- clocks: Handle to the ECAP's functional clock. -- clock-names: Must be set to "fck". - -Example: - -ecap0: ecap@48300100 { /* ECAP on am33xx */ - compatible = "ti,am3352-ecap", "ti,am33xx-ecap"; - #pwm-cells = <3>; - reg = <0x48300100 0x80>; - clocks = <&l4ls_gclk>; - clock-names = "fck"; -}; - -ecap0: ecap@48300100 { /* ECAP on am4372 */ - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; - #pwm-cells = <3>; - reg = <0x48300100 0x80>; - ti,hwmods = "ecap0"; - clocks = <&l4ls_gclk>; - clock-names = "fck"; -}; - -ecap0: ecap@1f06000 { /* ECAP on da850 */ - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; - #pwm-cells = <3>; - reg = <0x1f06000 0x80>; -}; - -ecap0: ecap@4843e100 { - compatible = "ti,dra746-ecap", "ti,am3352-ecap"; - #pwm-cells = <3>; - reg = <0x4843e100 0x80>; - clocks = <&l4_root_clk_div>; - clock-names = "fck"; -}; diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml b/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml new file mode 100644 index 000000000000..ed35b6cc48d5 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/pwm-tiecap.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI SOC ECAP based APWM controller + +maintainers: + - Vignesh R + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + oneOf: + - const: ti,am3352-ecap + - items: + - enum: + - ti,da850-ecap + - ti,am4372-ecap + - ti,dra746-ecap + - ti,k2g-ecap + - ti,am654-ecap + - ti,am64-ecap + - const: ti,am3352-ecap + + reg: + maxItems: 1 + + "#pwm-cells": + const: 3 + description: | + See pwm.yaml in this directory for a description of the cells format. + The only third cell flag supported by this binding is PWM_POLARITY_INVERTED. + + clock-names: + const: fck + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - "#pwm-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + ecap0: pwm@48300100 { /* ECAP on am33xx */ + compatible = "ti,am3352-ecap"; + #pwm-cells = <3>; + reg = <0x48300100 0x80>; + clocks = <&l4ls_gclk>; + clock-names = "fck"; + }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt deleted file mode 100644 index c7e28f6d28be..000000000000 --- a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt +++ /dev/null @@ -1,50 +0,0 @@ -TI SOC EHRPWM based PWM controller - -Required properties: -- compatible: Must be "ti,-ehrpwm". - for am33xx - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; - for am4372 - compatible = "ti,am4372-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm"; - for am654 - compatible = "ti,am654-ehrpwm", "ti-am3352-ehrpwm"; - for da850 - compatible = "ti,da850-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm"; - for dra746 - compatible = "ti,dra746-ehrpwm", "ti-am3352-ehrpwm"; -- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of - the cells format. The only third cell flag supported by this binding is - PWM_POLARITY_INVERTED. -- reg: physical base address and size of the registers map. - -Optional properties: -- clocks: Handle to the PWM's time-base and functional clock. -- clock-names: Must be set to "tbclk" and "fck". - -Example: - -ehrpwm0: pwm@48300200 { /* EHRPWM on am33xx */ - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; - #pwm-cells = <3>; - reg = <0x48300200 0x100>; - clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; - clock-names = "tbclk", "fck"; -}; - -ehrpwm0: pwm@48300200 { /* EHRPWM on am4372 */ - compatible = "ti,am4372-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; - #pwm-cells = <3>; - reg = <0x48300200 0x80>; - clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; - clock-names = "tbclk", "fck"; - ti,hwmods = "ehrpwm0"; -}; - -ehrpwm0: pwm@1f00000 { /* EHRPWM on da850 */ - compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; - #pwm-cells = <3>; - reg = <0x1f00000 0x2000>; -}; - -ehrpwm0: pwm@4843e200 { /* EHRPWM on dra746 */ - compatible = "ti,dra746-ehrpwm", "ti,am3352-ehrpwm"; - #pwm-cells = <3>; - reg = <0x4843e200 0x80>; - clocks = <&ehrpwm0_tbclk>, <&l4_root_clk_div>; - clock-names = "tbclk", "fck"; -}; diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml new file mode 100644 index 000000000000..ee312cb210e6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/pwm-tiehrpwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI SOC EHRPWM based PWM controller + +maintainers: + - Vignesh R + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + oneOf: + - const: ti,am3352-ehrpwm + - items: + - enum: + - ti,da850-ehrpwm + - ti,am4372-ehrpwm + - ti,dra746-ehrpwm + - ti,am654-ehrpwm + - ti,am64-epwm + - const: ti,am3352-ehrpwm + + reg: + maxItems: 1 + + "#pwm-cells": + const: 3 + description: | + See pwm.yaml in this directory for a description of the cells format. + The only third cell flag supported by this binding is PWM_POLARITY_INVERTED. + + clock-names: + items: + - const: tbclk + - const: fck + + clocks: + maxItems: 2 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - "#pwm-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + ehrpwm0: pwm@48300200 { /* EHRPWM on am33xx */ + compatible = "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x48300200 0x100>; + clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; + clock-names = "tbclk", "fck"; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index 208a628f8d6c..fc16d903353e 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -17,7 +17,11 @@ properties: enum: - fsl,imx8mq-cm4 - fsl,imx8mm-cm4 + - fsl,imx8mn-cm7 + - fsl,imx8mp-cm7 + - fsl,imx8ulp-cm33 - fsl,imx7d-cm4 + - fsl,imx7ulp-cm4 - fsl,imx6sx-cm4 clocks: @@ -49,10 +53,14 @@ properties: minItems: 1 maxItems: 32 + fsl,auto-boot: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicate whether need to load the default firmware and start the remote + processor automatically. + required: - compatible - - clocks - - syscon additionalProperties: false diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt deleted file mode 100644 index 229f908fd831..000000000000 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt +++ /dev/null @@ -1,228 +0,0 @@ -Qualcomm ADSP Peripheral Image Loader - -This document defines the binding for a component that loads and boots firmware -on the Qualcomm ADSP Hexagon core. - -- compatible: - Usage: required - Value type: - Definition: must be one of: - "qcom,msm8974-adsp-pil" - "qcom,msm8996-adsp-pil" - "qcom,msm8996-slpi-pil" - "qcom,msm8998-adsp-pas" - "qcom,msm8998-slpi-pas" - "qcom,qcs404-adsp-pas" - "qcom,qcs404-cdsp-pas" - "qcom,qcs404-wcss-pas" - "qcom,sc7180-mpss-pas" - "qcom,sdm845-adsp-pas" - "qcom,sdm845-cdsp-pas" - "qcom,sdx55-mpss-pas" - "qcom,sm8150-adsp-pas" - "qcom,sm8150-cdsp-pas" - "qcom,sm8150-mpss-pas" - "qcom,sm8150-slpi-pas" - "qcom,sm8250-adsp-pas" - "qcom,sm8250-cdsp-pas" - "qcom,sm8250-slpi-pas" - "qcom,sm8350-adsp-pas" - "qcom,sm8350-cdsp-pas" - "qcom,sm8350-slpi-pas" - "qcom,sm8350-mpss-pas" - -- interrupts-extended: - Usage: required - Value type: - Definition: reference to the interrupts that match interrupt-names - -- interrupt-names: - Usage: required - Value type: - Definition: The interrupts needed depends on the compatible - string: - qcom,msm8974-adsp-pil: - qcom,msm8996-adsp-pil: - qcom,msm8996-slpi-pil: - qcom,msm8998-adsp-pas: - qcom,msm8998-slpi-pas: - qcom,qcs404-adsp-pas: - qcom,qcs404-cdsp-pas: - qcom,sdm845-adsp-pas: - qcom,sdm845-cdsp-pas: - qcom,sm8150-adsp-pas: - qcom,sm8150-cdsp-pas: - qcom,sm8150-slpi-pas: - qcom,sm8250-adsp-pas: - qcom,sm8250-cdsp-pas: - qcom,sm8250-slpi-pas: - qcom,sm8350-adsp-pas: - qcom,sm8350-cdsp-pas: - qcom,sm8350-slpi-pas: - must be "wdog", "fatal", "ready", "handover", "stop-ack" - qcom,qcs404-wcss-pas: - qcom,sc7180-mpss-pas: - qcom,sdx55-mpss-pas: - qcom,sm8150-mpss-pas: - qcom,sm8350-mpss-pas: - must be "wdog", "fatal", "ready", "handover", "stop-ack", - "shutdown-ack" - -- firmware-name: - Usage: optional - Value type: - Definition: must list the relative firmware image path for the - Hexagon Core. - -- clocks: - Usage: required - Value type: - Definition: reference to the xo clock and optionally aggre2 clock to be - held on behalf of the booting Hexagon core - -- clock-names: - Usage: required - Value type: - Definition: must be "xo" and optionally include "aggre2" - -- cx-supply: - Usage: required - Value type: - Definition: reference to the regulator to be held on behalf of the - booting Hexagon core - -- px-supply: - Usage: required - Value type: - Definition: reference to the px regulator to be held on behalf of the - booting Hexagon core - -- power-domains: - Usage: required - Value type: - Definition: reference to power-domains that match the power-domain-names - -- power-domain-names: - Usage: required - Value type: - Definition: The power-domains needed depend on the compatible string: - qcom,msm8974-adsp-pil: - qcom,msm8996-adsp-pil: - qcom,msm8998-adsp-pas: - must be "cx" - qcom,msm8996-slpi-pil: - must be "ss_cx" - qcom,msm8998-slpi-pas: - must be "ssc_cx" - qcom,qcs404-adsp-pas: - must be "lpi_cx" - qcom,qcs404-cdsp-pas: - qcom,qcs404-wcss-pas: - must be "mx" - qcom,sdm845-adsp-pas: - qcom,sdm845-cdsp-pas: - qcom,sm8150-adsp-pas: - qcom,sm8150-cdsp-pas: - qcom,sm8250-cdsp-pas: - qcom,sm8350-cdsp-pas: - must be "cx", "load_state" - qcom,sc7180-mpss-pas: - qcom,sm8150-mpss-pas: - qcom,sm8350-mpss-pas: - must be "cx", "load_state", "mss" - qcom,sdx55-mpss-pas: - must be "cx", "mss" - qcom,sm8250-adsp-pas: - qcom,sm8350-adsp-pas: - qcom,sm8150-slpi-pas: - qcom,sm8250-slpi-pas: - qcom,sm8350-slpi-pas: - must be "lcx", "lmx", "load_state" - -- memory-region: - Usage: required - Value type: - Definition: reference to the reserved-memory for the ADSP - -- qcom,smem-states: - Usage: required - Value type: - Definition: reference to the smem state for requesting the ADSP to - shut down - -- qcom,smem-state-names: - Usage: required - Value type: - Definition: must be "stop" - - -= SUBNODES -The adsp node may have an subnode named either "smd-edge" or "glink-edge" that -describes the communication edge, channels and devices related to the ADSP. -See ../soc/qcom/qcom,smd.txt and ../soc/qcom/qcom,glink.txt for details on how -to describe these. - - -= EXAMPLE -The following example describes the resources needed to boot control the -ADSP, as it is found on MSM8974 boards. - - adsp { - compatible = "qcom,msm8974-adsp-pil"; - - interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>, - <&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>; - interrupt-names = "wdog", - "fatal", - "ready", - "handover", - "stop-ack"; - - clocks = <&rpmcc RPM_CXO_CLK>; - clock-names = "xo"; - - cx-supply = <&pm8841_s2>; - - memory-region = <&adsp_region>; - - qcom,smem-states = <&adsp_smp2p_out 0>; - qcom,smem-state-names = "stop"; - - smd-edge { - interrupts = <0 156 IRQ_TYPE_EDGE_RISING>; - - qcom,ipc = <&apcs 8 8>; - qcom,smd-edge = <1>; - }; - }; - -The following example describes the resources needed to boot control the -SLPI, as it is found on MSM8996 boards. - - slpi { - compatible = "qcom,msm8996-slpi-pil"; - interrupts-extended = <&intc 0 390 IRQ_TYPE_EDGE_RISING>, - <&slpi_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, - <&slpi_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, - <&slpi_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, - <&slpi_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "wdog", - "fatal", - "ready", - "handover", - "stop-ack"; - - clocks = <&rpmcc MSM8996_RPM_SMD_XO_CLK_SRC>, - <&rpmcc MSM8996_RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "xo", "aggre2"; - - cx-supply = <&pm8994_l26>; - px-supply = <&pm8994_lvs2>; - - memory-region = <&slpi_region>; - qcom,smem-states = <&slpi_smp2p_out 0>; - qcom,smem-state-names = "stop"; - }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml new file mode 100644 index 000000000000..c597ccced623 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -0,0 +1,547 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,adsp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm ADSP Peripheral Image Loader binding + +maintainers: + - Manivannan Sadhasivam + +description: + This document defines the binding for a component that loads and boots + firmware on the Qualcomm ADSP Hexagon core. + +properties: + compatible: + enum: + - qcom,msm8974-adsp-pil + - qcom,msm8996-adsp-pil + - qcom,msm8996-slpi-pil + - qcom,msm8998-adsp-pas + - qcom,msm8998-slpi-pas + - qcom,qcs404-adsp-pas + - qcom,qcs404-cdsp-pas + - qcom,qcs404-wcss-pas + - qcom,sc7180-mpss-pas + - qcom,sc8180x-adsp-pas + - qcom,sc8180x-cdsp-pas + - qcom,sc8180x-mpss-pas + - qcom,sdm845-adsp-pas + - qcom,sdm845-cdsp-pas + - qcom,sdx55-mpss-pas + - qcom,sm8150-adsp-pas + - qcom,sm8150-cdsp-pas + - qcom,sm8150-mpss-pas + - qcom,sm8150-slpi-pas + - qcom,sm8250-adsp-pas + - qcom,sm8250-cdsp-pas + - qcom,sm8250-slpi-pas + - qcom,sm8350-adsp-pas + - qcom,sm8350-cdsp-pas + - qcom,sm8350-slpi-pas + - qcom,sm8350-mpss-pas + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 8 + + clock-names: + minItems: 1 + maxItems: 8 + + interrupts: + minItems: 5 + maxItems: 6 + + interrupt-names: + minItems: 5 + maxItems: 6 + + resets: + minItems: 1 + maxItems: 3 + + reset-names: + minItems: 1 + maxItems: 3 + + cx-supply: + description: Phandle to the CX regulator + + px-supply: + description: Phandle to the PX regulator + + power-domains: + minItems: 1 + maxItems: 3 + + power-domain-names: + minItems: 1 + maxItems: 3 + + firmware-name: + $ref: /schemas/types.yaml#/definitions/string + description: Firmware name for the Hexagon core + + memory-region: + maxItems: 1 + description: Reference to the reserved-memory for the Hexagon core + + qcom,smem-states: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: States used by the AP to signal the Hexagon core + items: + - description: Stop the modem + + qcom,smem-state-names: + $ref: /schemas/types.yaml#/definitions/string-array + description: The names of the state bits used for SMP2P output + items: + - const: stop + + qcom,halt-regs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Phandle reference to a syscon representing TCSR followed by the + three offsets within syscon for q6, modem and nc halt registers. + + smd-edge: + type: object + description: + Qualcomm Shared Memory subnode which represents communication edge, + channels and devices related to the ADSP. + + glink-edge: + type: object + description: + Qualcomm G-Link subnode which represents communication edge, channels + and devices related to the ADSP. + +required: + - compatible + - clocks + - clock-names + - interrupts + - interrupt-names + - memory-region + - qcom,smem-states + - qcom,smem-state-names + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8974-adsp-pil + - qcom,msm8996-adsp-pil + - qcom,msm8996-slpi-pil + - qcom,msm8998-adsp-pas + - qcom,qcs404-adsp-pas + - qcom,qcs404-wcss-pas + - qcom,sc8180x-adsp-pas + - qcom,sc8180x-cdsp-pas + - qcom,sc8180x-mpss-pas + - qcom,sdm845-adsp-pas + - qcom,sdm845-cdsp-pas + - qcom,sm8150-adsp-pas + - qcom,sm8150-cdsp-pas + - qcom,sm8150-mpss-pas + - qcom,sm8150-slpi-pas + - qcom,sm8250-adsp-pas + - qcom,sm8250-cdsp-pas + - qcom,sm8250-slpi-pas + - qcom,sm8350-adsp-pas + - qcom,sm8350-cdsp-pas + - qcom,sm8350-slpi-pas + - qcom,sm8350-mpss-pas + then: + properties: + clocks: + items: + - description: XO clock + clock-names: + items: + - const: xo + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-slpi-pas + then: + properties: + clocks: + items: + - description: XO clock + - description: AGGRE2 clock + clock-names: + items: + - const: xo + - const: aggre2 + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcs404-cdsp-pas + then: + properties: + clocks: + items: + - description: XO clock + - description: SWAY clock + - description: TBU clock + - description: BIMC clock + - description: AHB AON clock + - description: Q6SS SLAVE clock + - description: Q6SS MASTER clock + - description: Q6 AXIM clock + clock-names: + items: + - const: xo + - const: sway + - const: tbu + - const: bimc + - const: ahb_aon + - const: q6ss_slave + - const: q6ss_master + - const: q6_axim + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-mpss-pas + then: + properties: + clocks: + items: + - description: XO clock + - description: IFACE clock + - description: BUS clock + - description: NAC clock + - description: SNOC AXI clock + - description: MNOC AXI clock + clock-names: + items: + - const: xo + - const: iface + - const: bus + - const: nav + - const: snoc_axi + - const: mnoc_axi + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8974-adsp-pil + - qcom,msm8996-adsp-pil + - qcom,msm8996-slpi-pil + - qcom,msm8998-adsp-pas + - qcom,msm8998-slpi-pas + - qcom,qcs404-adsp-pas + - qcom,qcs404-cdsp-pas + - qcom,qcs404-wcss-pas + - qcom,sc8180x-adsp-pas + - qcom,sc8180x-cdsp-pas + - qcom,sdm845-adsp-pas + - qcom,sdm845-cdsp-pas + - qcom,sm8150-adsp-pas + - qcom,sm8150-cdsp-pas + - qcom,sm8150-slpi-pas + - qcom,sm8250-adsp-pas + - qcom,sm8250-cdsp-pas + - qcom,sm8250-slpi-pas + - qcom,sm8350-adsp-pas + - qcom,sm8350-cdsp-pas + - qcom,sm8350-slpi-pas + then: + properties: + interrupts: + items: + - description: Watchdog interrupt + - description: Fatal interrupt + - description: Ready interrupt + - description: Handover interrupt + - description: Stop acknowledge interrupt + interrupt-names: + items: + - const: wdog + - const: fatal + - const: ready + - const: handover + - const: stop-ack + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-mpss-pas + - qcom,sc8180x-mpss-pas + - qcom,sdx55-mpss-pas + - qcom,sm8150-mpss-pas + - qcom,sm8350-mpss-pas + then: + properties: + interrupts: + items: + - description: Watchdog interrupt + - description: Fatal interrupt + - description: Ready interrupt + - description: Handover interrupt + - description: Stop acknowledge interrupt + - description: Shutdown acknowledge interrupt + interrupt-names: + items: + - const: wdog + - const: fatal + - const: ready + - const: handover + - const: stop-ack + - const: shutdown-ack + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8974-adsp-pil + then: + required: + - cx-supply + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-adsp-pil + - qcom,msm8998-adsp-pas + then: + properties: + power-domains: + items: + - description: CX power domain + power-domain-names: + items: + - const: cx + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-slpi-pil + - qcom,msm8998-slpi-pas + then: + properties: + power-domains: + items: + - description: SSC-CX power domain + power-domain-names: + items: + - const: ssc_cx + required: + - px-supply + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-mpss-pas + then: + properties: + power-domains: + items: + - description: Load State power domain + - description: CX power domain + - description: MX power domain + - description: MSS power domain + power-domain-names: + items: + - const: load_state + - const: cx + - const: mx + - const: mss + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8150-adsp-pas + - qcom,sm8150-cdsp-pas + then: + properties: + power-domains: + items: + - description: Load State power domain + - description: CX power domain + power-domain-names: + items: + - const: load_state + - const: cx + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8150-mpss-pas + - qcom,sm8350-mpss-pas + then: + properties: + power-domains: + items: + - description: Load State power domain + - description: CX power domain + - description: MSS power domain + power-domain-names: + items: + - const: load_state + - const: cx + - const: mss + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdx55-mpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MSS power domain + power-domain-names: + items: + - const: cx + - const: mss + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8180x-adsp-pas + - qcom,sc8180x-cdsp-pas + - qcom,sm8150-slpi-pas + - qcom,sm8250-adsp-pas + - qcom,sm8250-slpi-pas + - qcom,sm8350-adsp-pas + - qcom,sm8350-slpi-pas + then: + properties: + power-domains: + items: + - description: Load State power domain + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: load_state + - const: lcx + - const: lmx + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8350-cdsp-pas + then: + properties: + power-domains: + items: + - description: Load State power domain + - description: CX power domain + - description: MXC power domain + power-domain-names: + items: + - const: load_state + - const: cx + - const: mxc + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcs404-cdsp-pas + then: + properties: + resets: + items: + - description: CDSP restart + reset-names: + items: + - const: restart + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-mpss-pas + then: + properties: + resets: + items: + - description: MSS restart + - description: PDC reset + reset-names: + items: + - const: mss_restart + - const: pdc_reset + +examples: + - | + #include + #include + adsp { + compatible = "qcom,msm8974-adsp-pil"; + + interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>, + <&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>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmcc RPM_CXO_CLK>; + clock-names = "xo"; + + cx-supply = <&pm8841_s2>; + + memory-region = <&adsp_region>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + smd-edge { + interrupts = <0 156 IRQ_TYPE_EDGE_RISING>; + + qcom,ipc = <&apcs 8 8>; + qcom,smd-edge = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml index d905d614502b..130fbaacc4b1 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml @@ -14,8 +14,12 @@ description: | processor subsystems/clusters (R5FSS). The dual core cluster can be used either in a LockStep mode providing safety/fault tolerance features or in a Split mode providing two individual compute cores for doubling the compute - capacity. These are used together with other processors present on the SoC - to achieve various system level goals. + capacity on most SoCs. These are used together with other processors present + on the SoC to achieve various system level goals. + + AM64x SoCs do not support LockStep mode, but rather a new non-safety mode + called "Single-CPU" mode, where only Core0 is used, but with ability to use + Core1's TCMs as well. Each Dual-Core R5F sub-system is represented as a single DTS node representing the cluster, with a pair of child DT nodes representing @@ -33,6 +37,7 @@ properties: - ti,am654-r5fss - ti,j721e-r5fss - ti,j7200-r5fss + - ti,am64-r5fss power-domains: description: | @@ -56,11 +61,12 @@ properties: ti,cluster-mode: $ref: /schemas/types.yaml#/definitions/uint32 - enum: [0, 1] description: | Configuration Mode for the Dual R5F cores within the R5F cluster. - Should be either a value of 1 (LockStep mode) or 0 (Split mode), - default is LockStep mode if omitted. + Should be either a value of 1 (LockStep mode) or 0 (Split mode) on + most SoCs (AM65x, J721E, J7200), default is LockStep mode if omitted; + and should be either a value of 0 (Split mode) or 2 (Single-CPU mode) + on AM64x SoCs, default is Split mode if omitted. # R5F Processor Child Nodes: # ========================== @@ -97,6 +103,7 @@ patternProperties: - ti,am654-r5f - ti,j721e-r5f - ti,j7200-r5f + - ti,am64-r5f reg: items: @@ -198,6 +205,20 @@ patternProperties: unevaluatedProperties: false +if: + properties: + compatible: + enum: + - ti,am64-r5fss +then: + properties: + ti,cluster-mode: + enum: [0, 2] +else: + properties: + ti,cluster-mode: + enum: [0, 1] + required: - compatible - power-domains diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml index 63071eef1632..d7c3a78e37e6 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml @@ -36,6 +36,9 @@ properties: enum: - ti,am3356-pru # for AM335x SoC family (AM3356+ SoCs only) - ti,am4376-pru # for AM437x SoC family (AM4376+ SoCs only) + - ti,am642-pru # for PRUs in K3 AM64x SoC family + - ti,am642-rtu # for RTUs in K3 AM64x SoC family + - ti,am642-tx-pru # for Tx_PRUs in K3 AM64x SoC family - ti,am5728-pru # for AM57xx SoC family - ti,k2g-pru # for 66AK2G SoC family - ti,am654-pru # for PRUs in K3 AM65x SoC family @@ -68,6 +71,7 @@ if: enum: - ti,am654-rtu - ti,j721e-rtu + - ti,am642-rtu then: properties: $nodename: @@ -79,6 +83,7 @@ else: enum: - ti,am654-tx-pru - ti,j721e-tx-pru + - ti,am642-tx-pru then: properties: $nodename: diff --git a/Documentation/devicetree/bindings/reset/microchip,rst.yaml b/Documentation/devicetree/bindings/reset/microchip,rst.yaml new file mode 100644 index 000000000000..370579aeeca1 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/microchip,rst.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/reset/microchip,rst.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Microchip Sparx5 Switch Reset Controller + +maintainers: + - Steen Hegelund + - Lars Povlsen + +description: | + The Microchip Sparx5 Switch provides reset control and implements the following + functions + - One Time Switch Core Reset (Soft Reset) + +properties: + $nodename: + pattern: "^reset-controller@[0-9a-f]+$" + + compatible: + const: microchip,sparx5-switch-reset + + reg: + items: + - description: global control block registers + + reg-names: + items: + - const: gcb + + "#reset-cells": + const: 1 + + cpu-syscon: + $ref: "/schemas/types.yaml#/definitions/phandle" + description: syscon used to access CPU reset + +required: + - compatible + - reg + - reg-names + - "#reset-cells" + - cpu-syscon + +additionalProperties: false + +examples: + - | + reset: reset-controller@11010008 { + compatible = "microchip,sparx5-switch-reset"; + reg = <0x11010008 0x4>; + reg-names = "gcb"; + #reset-cells = <1>; + cpu-syscon = <&cpu_ctrl>; + }; + diff --git a/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml b/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml new file mode 100644 index 000000000000..61963fa9347e --- /dev/null +++ b/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/intel,ixp46x-rng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel IXP46x RNG bindings + +description: | + The Intel IXP46x has a random number generator at a fixed physical + location in memory. Each read is guaranteed to provide a unique + 32 bit random number. + +maintainers: + - Linus Walleij + +properties: + compatible: + const: intel,ixp46x-rng + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + rng@70002100 { + compatible = "intel,ixp46x-rng"; + reg = <0x70002100 4>; + }; + diff --git a/Documentation/devicetree/bindings/rtc/epson,rx8900.txt b/Documentation/devicetree/bindings/rtc/epson,rx8900.txt deleted file mode 100644 index 3f61e516ecf6..000000000000 --- a/Documentation/devicetree/bindings/rtc/epson,rx8900.txt +++ /dev/null @@ -1,22 +0,0 @@ -Real Time Clock driver for: - - Epson RX8900 - - Micro Crystal rv8803 - -Required properties: -- compatible: should be: "microcrystal,rv8803" or "epson,rx8900" -- reg : the I2C address of the device for I2C - -Optional properties: -- epson,vdet-disable : boolean, if present will disable voltage detector. - Should be set if no backup battery is used. -- trickle-diode-disable : boolean, if present will disable internal trickle - charger diode - -Example: - - rtc: rtc@32 { - compatible = "epson,rx8900" - reg = <0x32>; - epson,vdet-disable; - trickle-diode-disable; - }; diff --git a/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml b/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml new file mode 100644 index 000000000000..29fe39bb08ad --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/epson,rx8900.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: EPSON RX8900 / Microcrystal RV8803 Real-Time Clock DT bindings + +maintainers: + - Marek Vasut + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - epson,rx8900 + - microcrystal,rv8803 + + reg: + maxItems: 1 + + epson,vdet-disable: + type: boolean + description: | + Disable voltage detector. Should be set if no backup battery is used. + + trickle-diode-disable: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + epson,vdet-disable; + trickle-diode-disable; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt deleted file mode 100644 index e3938f5e0b6c..000000000000 --- a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt +++ /dev/null @@ -1,28 +0,0 @@ -* Faraday Technology FTRTC010 Real Time Clock - -This RTC appears in for example the Storlink Gemini family of -SoCs. - -Required properties: -- compatible : Should be one of: - "faraday,ftrtc010" - "cortina,gemini-rtc", "faraday,ftrtc010" - -Optional properties: -- clocks: when present should contain clock references to the - PCLK and EXTCLK clocks. Faraday calls the later CLK1HZ and - says the clock should be 1 Hz, but implementers actually seem - to choose different clocks here, like Cortina who chose - 32768 Hz (a typical low-power clock). -- clock-names: should name the clocks "PCLK" and "EXTCLK" - respectively. - -Examples: - -rtc@45000000 { - compatible = "cortina,gemini-rtc"; - reg = <0x45000000 0x100>; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&foo 0>, <&foo 1>; - clock-names = "PCLK", "EXTCLK"; -}; diff --git a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml new file mode 100644 index 000000000000..657c13b62b67 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/faraday,ftrtc010.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Faraday Technology FTRTC010 Real Time Clock + +maintainers: + - Linus Walleij + +description: | + This RTC appears in for example the Storlink Gemini family of SoCs. + +properties: + compatible: + oneOf: + - const: faraday,ftrtc010 + - items: + - const: cortina,gemini-rtc + - const: faraday,ftrtc010 + + resets: + maxItems: 1 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 2 + items: + - description: PCLK clocks + - description: EXTCLK clocks. Faraday calls it CLK1HZ and says the clock + should be 1 Hz, but implementers actually seem to choose different + clocks here, like Cortina who chose 32768 Hz (a typical low-power clock). + + clock-names: + items: + - const: "PCLK" + - const: "EXTCLK" + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + rtc@45000000 { + compatible = "cortina,gemini-rtc", "faraday,ftrtc010"; + reg = <0x45000000 0x100>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&foo 0>, <&foo 1>; + clock-names = "PCLK", "EXTCLK"; + }; diff --git a/Documentation/devicetree/bindings/rtc/rtc-m41t80.txt b/Documentation/devicetree/bindings/rtc/rtc-m41t80.txt index c746cb221210..cdd196b1e9bd 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-m41t80.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-m41t80.txt @@ -21,10 +21,19 @@ Optional properties: clock name - wakeup-source: Enables wake up of host system on alarm +Optional child node: +- clock: Provide this if the square wave pin is used as boot-enabled fixed clock. + Example: rtc@68 { compatible = "st,m41t80"; reg = <0x68>; interrupt-parent = <&UIC0>; interrupts = <0x9 0x8>; + + clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; }; diff --git a/Documentation/devicetree/bindings/rtc/ti,bq32000.yaml b/Documentation/devicetree/bindings/rtc/ti,bq32000.yaml new file mode 100644 index 000000000000..bf9c1c4ddb7e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/ti,bq32000.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/ti,bq32000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI BQ32000 I2C Serial Real-Time Clock + +maintainers: + - Alexandre Belloni + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: ti,bq32000 + + reg: + const: 0x68 + + interrupts: + maxItems: 1 + + start-year: true + + trickle-resistor-ohms: + enum: [ 1120, 20180 ] + + trickle-diode-disable: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + bq32000: rtc@68 { + compatible = "ti,bq32000"; + reg = <0x68>; + trickle-resistor-ohms = <1120>; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/ti,bq32k.txt b/Documentation/devicetree/bindings/rtc/ti,bq32k.txt deleted file mode 100644 index e204906b9ad3..000000000000 --- a/Documentation/devicetree/bindings/rtc/ti,bq32k.txt +++ /dev/null @@ -1,18 +0,0 @@ -* TI BQ32000 I2C Serial Real-Time Clock - -Required properties: -- compatible: Should contain "ti,bq32000". -- reg: I2C address for chip - -Optional properties: -- trickle-resistor-ohms : Selected resistor for trickle charger - Values usable are 1120 and 20180 - Should be given if trickle charger should be enabled -- trickle-diode-disable : Do not use internal trickle charger diode - Should be given if internal trickle charger diode should be disabled -Example: - bq32000: rtc@68 { - compatible = "ti,bq32000"; - trickle-resistor-ohms = <1120>; - reg = <0x68>; - }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt index 8051c17e640e..d74a7a5ae9f2 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt @@ -27,6 +27,7 @@ Required properties in pwrap device node. "mediatek,mt8135-pwrap" for MT8135 SoCs "mediatek,mt8173-pwrap" for MT8173 SoCs "mediatek,mt8183-pwrap" for MT8183 SoCs + "mediatek,mt8195-pwrap" for MT8195 SoCs "mediatek,mt8516-pwrap" for MT8516 SoCs - interrupts: IRQ for pwrap in SOC - reg-names: Must include the following entries: diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index 2684f22a1d85..d511f01fcac6 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -32,12 +32,14 @@ properties: enum: - qcom,rpm-apq8084 - qcom,rpm-ipq6018 + - qcom,rpm-msm8226 - qcom,rpm-msm8916 - qcom,rpm-msm8974 - qcom,rpm-msm8976 - qcom,rpm-msm8996 - qcom,rpm-msm8998 - qcom,rpm-sdm660 + - qcom,rpm-sm6125 - qcom,rpm-qcs404 qcom,smd-channels: diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.txt b/Documentation/devicetree/bindings/soc/rockchip/grf.txt deleted file mode 100644 index f96511aa3897..000000000000 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.txt +++ /dev/null @@ -1,61 +0,0 @@ -* Rockchip General Register Files (GRF) - -The general register file will be used to do static set by software, which -is composed of many registers for system control. - -From RK3368 SoCs, the GRF is divided into two sections, -- GRF, used for general non-secure system, -- SGRF, used for general secure system, -- PMUGRF, used for always on system - -On RK3328 SoCs, the GRF adds a section for USB2PHYGRF, - -ON RK3308 SoC, the GRF is divided into four sections: -- GRF, used for general non-secure system, -- SGRF, used for general secure system, -- DETECTGRF, used for audio codec system, -- COREGRF, used for pvtm, - -Required Properties: - -- compatible: GRF should be one of the following: - - "rockchip,px30-grf", "syscon": for px30 - - "rockchip,rk3036-grf", "syscon": for rk3036 - - "rockchip,rk3066-grf", "syscon": for rk3066 - - "rockchip,rk3188-grf", "syscon": for rk3188 - - "rockchip,rk3228-grf", "syscon": for rk3228 - - "rockchip,rk3288-grf", "syscon": for rk3288 - - "rockchip,rk3308-grf", "syscon": for rk3308 - - "rockchip,rk3328-grf", "syscon": for rk3328 - - "rockchip,rk3368-grf", "syscon": for rk3368 - - "rockchip,rk3399-grf", "syscon": for rk3399 - - "rockchip,rv1108-grf", "syscon": for rv1108 -- compatible: DETECTGRF should be one of the following: - - "rockchip,rk3308-detect-grf", "syscon": for rk3308 -- compatilbe: COREGRF should be one of the following: - - "rockchip,rk3308-core-grf", "syscon": for rk3308 -- compatible: PMUGRF should be one of the following: - - "rockchip,px30-pmugrf", "syscon": for px30 - - "rockchip,rk3368-pmugrf", "syscon": for rk3368 - - "rockchip,rk3399-pmugrf", "syscon": for rk3399 -- compatible: SGRF should be one of the following: - - "rockchip,rk3288-sgrf", "syscon": for rk3288 -- compatible: USB2PHYGRF should be one of the following: - - "rockchip,px30-usb2phy-grf", "syscon": for px30 - - "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328 -- compatible: USBGRF should be one of the following: - - "rockchip,rv1108-usbgrf", "syscon": for rv1108 -- reg: physical base address of the controller and length of memory mapped - region. - -Example: GRF and PMUGRF of RK3399 SoCs - - pmugrf: syscon@ff320000 { - compatible = "rockchip,rk3399-pmugrf", "syscon"; - reg = <0x0 0xff320000 0x0 0x1000>; - }; - - grf: syscon@ff770000 { - compatible = "rockchip,rk3399-grf", "syscon"; - reg = <0x0 0xff770000 0x0 0x10000>; - }; diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml new file mode 100644 index 000000000000..62fa72cfea34 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -0,0 +1,261 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/rockchip/grf.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip General Register Files (GRF) + +maintainers: + - Heiko Stuebner + +properties: + compatible: + oneOf: + - items: + - enum: + - rockchip,rk3288-sgrf + - rockchip,rv1108-pmugrf + - rockchip,rv1108-usbgrf + - const: syscon + - items: + - enum: + - rockchip,px30-grf + - rockchip,px30-pmugrf + - rockchip,px30-usb2phy-grf + - rockchip,rk3036-grf + - rockchip,rk3066-grf + - rockchip,rk3188-grf + - rockchip,rk3228-grf + - rockchip,rk3288-grf + - rockchip,rk3308-core-grf + - rockchip,rk3308-detect-grf + - rockchip,rk3308-grf + - rockchip,rk3308-usb2phy-grf + - rockchip,rk3328-grf + - rockchip,rk3328-usb2phy-grf + - rockchip,rk3368-grf + - rockchip,rk3368-pmugrf + - rockchip,rk3399-grf + - rockchip,rk3399-pmugrf + - rockchip,rk3568-grf + - rockchip,rk3568-pmugrf + - rockchip,rv1108-grf + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + +required: + - compatible + - reg + +additionalProperties: + type: object + +allOf: + - if: + properties: + compatible: + contains: + const: rockchip,px30-grf + + then: + properties: + lvds: + description: + Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt + + - if: + properties: + compatible: + contains: + const: rockchip,rk3288-grf + + then: + properties: + edp-phy: + description: + Documentation/devicetree/bindings/phy/rockchip-dp-phy.txt + + - if: + properties: + compatible: + contains: + enum: + - rockchip,rk3066-grf + - rockchip,rk3188-grf + - rockchip,rk3288-grf + + then: + properties: + usbphy: + type: object + + $ref: "/schemas/phy/rockchip-usb-phy.yaml#" + + unevaluatedProperties: false + + - if: + properties: + compatible: + contains: + const: rockchip,rk3328-grf + + then: + properties: + gpio: + type: object + + $ref: "/schemas/gpio/rockchip,rk3328-grf-gpio.yaml#" + + unevaluatedProperties: false + + power-controller: + type: object + + $ref: "/schemas/power/rockchip,power-controller.yaml#" + + unevaluatedProperties: false + + - if: + properties: + compatible: + contains: + const: rockchip,rk3399-grf + + then: + properties: + mipi-dphy-rx0: + type: object + + $ref: "/schemas/phy/rockchip-mipi-dphy-rx0.yaml#" + + unevaluatedProperties: false + + pcie-phy: + description: + Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt + + patternProperties: + "phy@[0-9a-f]+$": + description: + Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt + + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-pmugrf + - rockchip,rk3036-grf + - rockchip,rk3308-grf + - rockchip,rk3368-pmugrf + + then: + properties: + reboot-mode: + type: object + + $ref: "/schemas/power/reset/syscon-reboot-mode.yaml#" + + unevaluatedProperties: false + + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-usb2phy-grf + - rockchip,rk3228-grf + - rockchip,rk3308-usb2phy-grf + - rockchip,rk3328-usb2phy-grf + - rockchip,rk3399-grf + - rockchip,rv1108-grf + + then: + required: + - "#address-cells" + - "#size-cells" + + patternProperties: + "usb2phy@[0-9a-f]+$": + type: object + + $ref: "/schemas/phy/phy-rockchip-inno-usb2.yaml#" + + unevaluatedProperties: false + + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-pmugrf + - rockchip,px30-grf + - rockchip,rk3228-grf + - rockchip,rk3288-grf + - rockchip,rk3328-grf + - rockchip,rk3368-pmugrf + - rockchip,rk3368-grf + - rockchip,rk3399-pmugrf + - rockchip,rk3399-grf + + then: + properties: + io-domains: + description: + Documentation/devicetree/bindings/power/rockchip-io-domain.txt + +examples: + - | + #include + #include + #include + grf: syscon@ff770000 { + compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd"; + reg = <0xff770000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + + mipi_dphy_rx0: mipi-dphy-rx0 { + compatible = "rockchip,rk3399-mipi-dphy-rx0"; + clocks = <&cru SCLK_MIPIDPHY_REF>, + <&cru SCLK_DPHY_RX0_CFG>, + <&cru PCLK_VIO_GRF>; + clock-names = "dphy-ref", "dphy-cfg", "grf"; + power-domains = <&power RK3399_PD_VIO>; + #phy-cells = <0>; + }; + + u2phy0: usb2phy@e450 { + compatible = "rockchip,rk3399-usb2phy"; + reg = <0xe450 0x10>; + clocks = <&cru SCLK_USB2PHY0_REF>; + clock-names = "phyclk"; + #clock-cells = <0>; + clock-output-names = "clk_usbphy0_480m"; + + u2phy0_host: host-port { + #phy-cells = <0>; + interrupts = ; + interrupt-names = "linestate"; + }; + + u2phy0_otg: otg-port { + #phy-cells = <0>; + interrupts = , + , + ; + interrupt-names = "otg-bvalid", "otg-id", + "linestate"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt deleted file mode 100644 index 8304eceb62e4..000000000000 --- a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt +++ /dev/null @@ -1,136 +0,0 @@ -* Rockchip Power Domains - -Rockchip processors include support for multiple power domains which can be -powered up/down by software based on different application scenes to save power. - -Required properties for power domain controller: -- compatible: Should be one of the following. - "rockchip,px30-power-controller" - for PX30 SoCs. - "rockchip,rk3036-power-controller" - for RK3036 SoCs. - "rockchip,rk3066-power-controller" - for RK3066 SoCs. - "rockchip,rk3128-power-controller" - for RK3128 SoCs. - "rockchip,rk3188-power-controller" - for RK3188 SoCs. - "rockchip,rk3228-power-controller" - for RK3228 SoCs. - "rockchip,rk3288-power-controller" - for RK3288 SoCs. - "rockchip,rk3328-power-controller" - for RK3328 SoCs. - "rockchip,rk3366-power-controller" - for RK3366 SoCs. - "rockchip,rk3368-power-controller" - for RK3368 SoCs. - "rockchip,rk3399-power-controller" - for RK3399 SoCs. -- #power-domain-cells: Number of cells in a power-domain specifier. - Should be 1 for multiple PM domains. -- #address-cells: Should be 1. -- #size-cells: Should be 0. - -Required properties for power domain sub nodes: -- reg: index of the power domain, should use macros in: - "include/dt-bindings/power/px30-power.h" - for PX30 type power domain. - "include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain. - "include/dt-bindings/power/rk3066-power.h" - for RK3066 type power domain. - "include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain. - "include/dt-bindings/power/rk3188-power.h" - for RK3188 type power domain. - "include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain. - "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. - "include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain. - "include/dt-bindings/power/rk3366-power.h" - for RK3366 type power domain. - "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. - "include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain. -- clocks (optional): phandles to clocks which need to be enabled while power domain - switches state. -- pm_qos (optional): phandles to qos blocks which need to be saved and restored - while power domain switches state. - -Qos Example: - - qos_gpu: qos_gpu@ffaf0000 { - compatible ="syscon"; - reg = <0x0 0xffaf0000 0x0 0x20>; - }; - -Example: - - power: power-controller { - compatible = "rockchip,rk3288-power-controller"; - #power-domain-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - - pd_gpu { - reg = ; - clocks = <&cru ACLK_GPU>; - pm_qos = <&qos_gpu>; - }; - }; - - power: power-controller { - compatible = "rockchip,rk3368-power-controller"; - #power-domain-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - - pd_gpu_1 { - reg = ; - clocks = <&cru ACLK_GPU_CFG>; - }; - }; - -Example 2: - power: power-controller { - compatible = "rockchip,rk3399-power-controller"; - #power-domain-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - - pd_vio { - #address-cells = <1>; - #size-cells = <0>; - reg = ; - - pd_vo { - #address-cells = <1>; - #size-cells = <0>; - reg = ; - - pd_vopb { - reg = ; - }; - - pd_vopl { - reg = ; - }; - }; - }; - }; - -Node of a device using power domains must have a power-domains property, -containing a phandle to the power device node and an index specifying which -power domain to use. -The index should use macros in: - "include/dt-bindings/power/px30-power.h" - for px30 type power domain. - "include/dt-bindings/power/rk3036-power.h" - for rk3036 type power domain. - "include/dt-bindings/power/rk3128-power.h" - for rk3128 type power domain. - "include/dt-bindings/power/rk3128-power.h" - for rk3228 type power domain. - "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. - "include/dt-bindings/power/rk3328-power.h" - for rk3328 type power domain. - "include/dt-bindings/power/rk3366-power.h" - for rk3366 type power domain. - "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. - "include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain. - -Example of the node using power domain: - - node { - /* ... */ - power-domains = <&power RK3288_PD_GPU>; - /* ... */ - }; - - node { - /* ... */ - power-domains = <&power RK3368_PD_GPU_1>; - /* ... */ - }; - - node { - /* ... */ - power-domains = <&power RK3399_PD_VOPB>; - /* ... */ - }; diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml index a16e37b01e1d..39b66e9ce3e3 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml @@ -20,6 +20,9 @@ properties: - const: allwinner,sun6i-a31-i2s - const: allwinner,sun8i-a83t-i2s - const: allwinner,sun8i-h3-i2s + - items: + - const: allwinner,sun8i-v3-i2s + - const: allwinner,sun8i-h3-i2s - const: allwinner,sun50i-a64-codec-i2s - items: - const: allwinner,sun50i-a64-i2s diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml index 9718358826ab..26eca21e1f0f 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml @@ -12,12 +12,15 @@ maintainers: properties: compatible: - enum: + oneOf: # FIXME: This is documented in the PRCM binding, but needs to be # migrated here at some point # - allwinner,sun8i-a23-codec-analog - - allwinner,sun8i-h3-codec-analog - - allwinner,sun8i-v3s-codec-analog + - const: allwinner,sun8i-h3-codec-analog + - items: + - const: allwinner,sun8i-v3-codec-analog + - const: allwinner,sun8i-h3-codec-analog + - const: allwinner,sun8i-v3s-codec-analog reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml b/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml new file mode 100644 index 000000000000..a35da257b070 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/nvidia,tegra30-tsensor.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra30 Thermal Sensor + +maintainers: + - Dmitry Osipenko + - Jon Hunter + - Thierry Reding + +description: | + TSENSOR provides thermal and voltage sensors which monitor temperature + and voltage of the chip. Sensors are placed across the die to gauge the + temperature of the whole chip. The TSENSOR module: + + Generates an interrupt to SW to lower temperature via DVFS on reaching + a certain thermal/voltage threshold. + + Generates a signal to the CAR to reduce CPU frequency by half on reaching + a certain thermal/voltage threshold. + + Generates a signal to the PMC when the temperature reaches dangerously high + levels to reset the chip and sets a flag in the PMC. + + TSENSOR has two channels which monitor two different spots of the SoC. + +properties: + compatible: + const: nvidia,tegra30-tsensor + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + + assigned-clock-parents: true + assigned-clock-rates: true + assigned-clocks: true + +required: + - compatible + - reg + - clocks + - resets + - interrupts + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + thermal-sensor@70014000 { + compatible = "nvidia,tegra30-tsensor"; + reg = <0x70014000 0x500>; + interrupts = <0 102 4>; + clocks = <&clk 100>; + resets = <&rst 100>; + + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 0b3b6af7bd5b..4a2eaf28e3fd 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -46,6 +46,8 @@ properties: - qcom,msm8996-tsens - qcom,msm8998-tsens - qcom,sc7180-tsens + - qcom,sc7280-tsens + - qcom,sc8180x-tsens - qcom,sdm845-tsens - qcom,sm8150-tsens - qcom,sm8250-tsens diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt deleted file mode 100644 index 7f94669e9ebe..000000000000 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt +++ /dev/null @@ -1,85 +0,0 @@ -* Temperature Sensor ADC (TSADC) on rockchip SoCs - -Required properties: -- compatible : should be "rockchip,-tsadc" - "rockchip,px30-tsadc": found on PX30 SoCs - "rockchip,rv1108-tsadc": found on RV1108 SoCs - "rockchip,rk3228-tsadc": found on RK3228 SoCs - "rockchip,rk3288-tsadc": found on RK3288 SoCs - "rockchip,rk3328-tsadc": found on RK3328 SoCs - "rockchip,rk3368-tsadc": found on RK3368 SoCs - "rockchip,rk3399-tsadc": found on RK3399 SoCs -- reg : physical base address of the controller and length of memory mapped - region. -- interrupts : The interrupt number to the cpu. The interrupt specifier format - depends on the interrupt controller. -- clocks : Must contain an entry for each entry in clock-names. -- clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for - the peripheral clock. -- resets : Must contain an entry for each entry in reset-names. - See ../reset/reset.txt for details. -- reset-names : Must include the name "tsadc-apb". -- pinctrl-names : The pin control state names; -- pinctrl-0 : The "init" pinctrl state, it will be set before device probe. -- pinctrl-1 : The "default" pinctrl state, it will be set after reset the - TSADC controller. -- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. -- #thermal-sensor-cells : Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. - -Optional properties: -- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. -- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. -- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW - 1:HIGH. -- rockchip,grf : The phandle of the syscon node for the general register file. - -Exiample: -tsadc: tsadc@ff280000 { - compatible = "rockchip,rk3288-tsadc"; - reg = <0xff280000 0x100>; - interrupts = ; - clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; - clock-names = "tsadc", "apb_pclk"; - resets = <&cru SRST_TSADC>; - reset-names = "tsadc-apb"; - pinctrl-names = "init", "default", "sleep"; - pinctrl-0 = <&otp_gpio>; - pinctrl-1 = <&otp_out>; - pinctrl-2 = <&otp_gpio>; - #thermal-sensor-cells = <1>; - rockchip,hw-tshut-temp = <95000>; - rockchip,hw-tshut-mode = <0>; - rockchip,hw-tshut-polarity = <0>; -}; - -Example: referring to thermal sensors: -thermal-zones { - cpu_thermal: cpu_thermal { - polling-delay-passive = <1000>; /* milliseconds */ - polling-delay = <5000>; /* milliseconds */ - - /* sensor ID */ - thermal-sensors = <&tsadc 1>; - - trips { - cpu_alert0: cpu_alert { - temperature = <70000>; /* millicelsius */ - hysteresis = <2000>; /* millicelsius */ - type = "passive"; - }; - cpu_crit: cpu_crit { - temperature = <90000>; /* millicelsius */ - hysteresis = <2000>; /* millicelsius */ - type = "critical"; - }; - }; - - cooling-maps { - map0 { - trip = <&cpu_alert0>; - cooling-device = - <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml new file mode 100644 index 000000000000..b96ea277b558 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/rockchip-thermal.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Temperature Sensor ADC (TSADC) on Rockchip SoCs + +maintainers: + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,px30-tsadc # PX30 SoCs + - rockchip,rv1108-tsadc # RV1108 SoCs + - rockchip,rk3228-tsadc # RK3228 SoCs + - rockchip,rk3288-tsadc # RK3288 SoCs + - rockchip,rk3328-tsadc # RK3328 SoCs + - rockchip,rk3368-tsadc # RK3368 SoCs + - rockchip,rk3399-tsadc # RK3399 SoCs + - rockchip,rk3568-tsadc # RK3568 SoCs + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: tsadc + - const: apb_pclk + + resets: + maxItems: 1 + + reset-names: + items: + - const: tsadc-apb + + "#thermal-sensor-cells": + const: 1 + + rockchip,grf: + description: The phandle of the syscon node for the general register file. + $ref: /schemas/types.yaml#/definitions/phandle + + rockchip,hw-tshut-temp: + description: The hardware-controlled shutdown temperature value. + $ref: /schemas/types.yaml#/definitions/uint32 + + rockchip,hw-tshut-mode: + description: The hardware-controlled shutdown mode 0:CRU 1:GPIO. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + + rockchip,hw-tshut-polarity: + description: The hardware-controlled active polarity 0:LOW 1:HIGH. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - reset-names + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + tsadc: tsadc@ff280000 { + compatible = "rockchip,rk3288-tsadc"; + reg = <0xff280000 0x100>; + interrupts = ; + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; + }; diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml index 1c7cf32e7ac2..53fd24bdc34e 100644 --- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml +++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml @@ -12,11 +12,18 @@ maintainers: properties: compatible: - enum: - - allwinner,sun4i-a10-timer - - allwinner,sun8i-a23-timer - - allwinner,sun8i-v3s-timer - - allwinner,suniv-f1c100s-timer + oneOf: + - enum: + - allwinner,sun4i-a10-timer + - allwinner,sun8i-a23-timer + - allwinner,sun8i-v3s-timer + - allwinner,suniv-f1c100s-timer + - items: + - enum: + - allwinner,sun50i-a64-timer + - allwinner,sun50i-h6-timer + - allwinner,sun50i-h616-timer + - const: allwinner,sun8i-a23-timer reg: maxItems: 1 @@ -34,8 +41,8 @@ allOf: - if: properties: compatible: - items: - const: allwinner,sun4i-a10-timer + enum: + - allwinner,sun4i-a10-timer then: properties: @@ -46,8 +53,8 @@ allOf: - if: properties: compatible: - items: - const: allwinner,sun8i-a23-timer + enum: + - allwinner,sun8i-a23-timer then: properties: @@ -58,20 +65,9 @@ allOf: - if: properties: compatible: - items: - const: allwinner,sun8i-v3s-timer - - then: - properties: - interrupts: - minItems: 3 - maxItems: 3 - - - if: - properties: - compatible: - items: - const: allwinner,suniv-f1c100s-timer + enum: + - allwinner,sun8i-v3s-timer + - allwinner,suniv-f1c100s-timer then: properties: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 2bbc27aae977..07fb0d25fc15 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -249,6 +249,8 @@ patternProperties: description: Colorful GRP, Shenzhen Xueyushi Technology Ltd. "^compulab,.*": description: CompuLab Ltd. + "^congatec,.*": + description: congatec GmbH "^coreriver,.*": description: CORERIVER Semiconductor Co.,Ltd. "^corpro,.*": @@ -315,6 +317,8 @@ patternProperties: description: DPTechnics "^dragino,.*": description: Dragino Technology Co., Limited + "^ds,.*": + description: DaSheng, Inc. "^dserve,.*": description: dServe Technology B.V. "^dynaimage,.*": @@ -409,6 +413,8 @@ patternProperties: description: Firefly "^focaltech,.*": description: FocalTech Systems Co.,Ltd + "^forlinx,.*": + description: Baoding Forlinx Embedded Technology Co., Ltd. "^frida,.*": description: Shenzhen Frida LCD Co., Ltd. "^friendlyarm,.*": @@ -1252,6 +1258,8 @@ patternProperties: description: Western Digital Corp. "^we,.*": description: Würth Elektronik GmbH. + "^welltech,.*": + description: Welltech Computer Co., Limited. "^wetek,.*": description: WeTek Electronics, limited. "^wexler,.*": diff --git a/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml new file mode 100644 index 000000000000..9856cd76c28d --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/atmel,sama5d4-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel SAMA5D4 Watchdog Timer (WDT) Controller + +maintainers: + - Eugen Hristev + +allOf: + - $ref: "watchdog.yaml#" + +properties: + compatible: + enum: + - atmel,sama5d4-wdt + - microchip,sam9x60-wdt + - microchip,sama7g5-wdt + + reg: + maxItems: 1 + + atmel,watchdog-type: + $ref: /schemas/types.yaml#/definitions/string + description: should be hardware or software. + oneOf: + - description: + Enable watchdog fault reset. A watchdog fault triggers + watchdog reset. + const: hardware + - description: + Enable watchdog fault interrupt. A watchdog fault asserts + watchdog interrupt. + const: software + default: hardware + + atmel,idle-halt: + $ref: /schemas/types.yaml#/definitions/flag + description: | + present if you want to stop the watchdog when the CPU is in idle state. + CAUTION: This property should be used with care, it actually makes the + watchdog not counting when the CPU is in idle state, therefore the + watchdog reset time depends on mean CPU usage and will not reset at all + if the CPU stop working while it is in idle state, which is probably + not what you want. + + atmel,dbg-halt: + $ref: /schemas/types.yaml#/definitions/flag + description: | + present if you want to stop the watchdog when the CPU is in debug state. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + watchdog@fc068640 { + compatible = "atmel,sama5d4-wdt"; + reg = <0xfc068640 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; + timeout-sec = <10>; + atmel,watchdog-type = "hardware"; + atmel,dbg-halt; + atmel,idle-halt; + }; + +... diff --git a/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt deleted file mode 100644 index 44727fcc2729..000000000000 --- a/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt +++ /dev/null @@ -1,34 +0,0 @@ -* Atmel SAMA5D4 Watchdog Timer (WDT) Controller - -Required properties: -- compatible: "atmel,sama5d4-wdt" or "microchip,sam9x60-wdt" -- reg: base physical address and length of memory mapped region. - -Optional properties: -- timeout-sec: watchdog timeout value (in seconds). -- interrupts: interrupt number to the CPU. -- atmel,watchdog-type: should be "hardware" or "software". - "hardware": enable watchdog fault reset. A watchdog fault triggers - watchdog reset. - "software": enable watchdog fault interrupt. A watchdog fault asserts - watchdog interrupt. -- atmel,idle-halt: present if you want to stop the watchdog when the CPU is - in idle state. - CAUTION: This property should be used with care, it actually makes the - watchdog not counting when the CPU is in idle state, therefore the - watchdog reset time depends on mean CPU usage and will not reset at all - if the CPU stop working while it is in idle state, which is probably - not what you want. -- atmel,dbg-halt: present if you want to stop the watchdog when the CPU is - in debug state. - -Example: - watchdog@fc068640 { - compatible = "atmel,sama5d4-wdt"; - reg = <0xfc068640 0x10>; - interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; - timeout-sec = <10>; - atmel,watchdog-type = "hardware"; - atmel,dbg-halt; - atmel,idle-halt; - }; diff --git a/Documentation/devicetree/bindings/watchdog/mstar,msc313e-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mstar,msc313e-wdt.yaml new file mode 100644 index 000000000000..e3e8b86dbf63 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/mstar,msc313e-wdt.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/mstar,msc313e-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MStar Watchdog Device Tree Bindings + +maintainers: + - Daniel Palmer + - Romain Perier + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + enum: + - mstar,msc313e-wdt + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - clocks + - reg + +unevaluatedProperties: false + +examples: + - | + watchdog@6000 { + compatible = "mstar,msc313e-wdt"; + reg = <0x6000 0x1f>; + clocks = <&xtal_div2>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt index e36ba60de829..416d716403f6 100644 --- a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt @@ -1,5 +1,8 @@ Mediatek SoCs Watchdog timer +The watchdog supports a pre-timeout interrupt that fires timeout-sec/2 +before the expiry. + Required properties: - compatible should contain: @@ -13,10 +16,12 @@ Required properties: "mediatek,mt8183-wdt": for MT8183 "mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516 "mediatek,mt8192-wdt": for MT8192 + "mediatek,mt8195-wdt", "mediatek,mt6589-wdt": for MT8195 - reg : Specifies base physical address and size of the registers. Optional properties: +- interrupts: Watchdog pre-timeout (bark) interrupt. - timeout-sec: contains the watchdog timeout in seconds. - #reset-cells: Should be 1. @@ -26,6 +31,7 @@ watchdog: watchdog@10007000 { compatible = "mediatek,mt8183-wdt", "mediatek,mt6589-wdt"; reg = <0 0x10007000 0 0x100>; + interrupts = ; timeout-sec = <10>; #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index b8e4118945a0..ba60bdf1fecc 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -17,6 +17,7 @@ properties: enum: - qcom,apss-wdt-qcs404 - qcom,apss-wdt-sc7180 + - qcom,apss-wdt-sc7280 - qcom,apss-wdt-sdm845 - qcom,apss-wdt-sdx55 - qcom,apss-wdt-sm8150 diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index b58596b1831d..6461eb4f4a27 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -27,6 +27,7 @@ properties: - rockchip,rk3328-wdt - rockchip,rk3368-wdt - rockchip,rk3399-wdt + - rockchip,rk3568-wdt - rockchip,rv1108-wdt - const: snps,dw-wdt diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 0fe1fffa295e..650096523f4f 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -400,7 +400,8 @@ POWER PWM devm_pwm_get() - devm_pwm_put() + devm_of_pwm_get() + devm_fwnode_pwm_get() REGULATOR devm_regulator_bulk_get() diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index a7ca4f58305a..ccb06e485756 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -40,7 +40,8 @@ after usage with pwm_free(). New users should use the pwm_get() function and pass to it the consumer device or a consumer name. pwm_put() is used to free the PWM device. Managed -variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist. +variants of the getter, devm_pwm_get(), devm_of_pwm_get(), +devm_fwnode_pwm_get(), also exist. After being requested, a PWM has to be configured using:: @@ -48,6 +49,10 @@ After being requested, a PWM has to be configured using:: This API controls both the PWM period/duty_cycle config and the enable/disable state. +There is also a usage_power setting: If set, the PWM driver is only required to +maintain the power output but has more freedom regarding signal form. +If supported by the driver, the signal can be optimized, for example to improve +EMI by phase shifting the individual channels of a chip. The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers around pwm_apply_state() and should not be used if the user wants to change diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index 992bf91eeec8..ff9e7cc97c65 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -281,6 +281,18 @@ compress_extension=%s Support adding specified extension, so that f2fs can enab For other files, we can still enable compression via ioctl. Note that, there is one reserved special extension '*', it can be set to enable compression for all files. +nocompress_extension=%s Support adding specified extension, so that f2fs can disable + compression on those corresponding files, just contrary to compression extension. + If you know exactly which files cannot be compressed, you can use this. + The same extension name can't appear in both compress and nocompress + extension at the same time. + If the compress extension specifies all files, the types specified by the + nocompress extension will be treated as special cases and will not be compressed. + Don't allow use '*' to specifie all file in nocompress extension. + After add nocompress_extension, the priority should be: + dir_flag < comp_extention,nocompress_extension < comp_file_flag,no_comp_file_flag. + See more in compression sections. + compress_chksum Support verifying chksum of raw data in compressed cluster. compress_mode=%s Control file compression mode. This supports "fs" and "user" modes. In "fs" mode (default), f2fs does automatic compression @@ -289,6 +301,9 @@ compress_mode=%s Control file compression mode. This supports "fs" and "user" choosing the target file and the timing. The user can do manual compression/decompression on the compression enabled files using ioctls. +compress_cache Support to use address space of a filesystem managed inode to + cache compressed block, in order to improve cache hit ratio of + random read. inlinecrypt When possible, encrypt/decrypt the contents of encrypted files using the blk-crypto framework rather than filesystem-layer encryption. This allows the use of @@ -717,10 +732,10 @@ users. ===================== ======================== =================== User F2FS Block ===================== ======================== =================== - META WRITE_LIFE_NOT_SET - HOT_NODE " - WARM_NODE " - COLD_NODE " +N/A META WRITE_LIFE_NOT_SET +N/A HOT_NODE " +N/A WARM_NODE " +N/A COLD_NODE " ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME extension list " " @@ -746,10 +761,10 @@ WRITE_LIFE_LONG " WRITE_LIFE_LONG ===================== ======================== =================== User F2FS Block ===================== ======================== =================== - META WRITE_LIFE_MEDIUM; - HOT_NODE WRITE_LIFE_NOT_SET - WARM_NODE " - COLD_NODE WRITE_LIFE_NONE +N/A META WRITE_LIFE_MEDIUM; +N/A HOT_NODE WRITE_LIFE_NOT_SET +N/A WARM_NODE " +N/A COLD_NODE WRITE_LIFE_NONE ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME extension list " " @@ -814,13 +829,30 @@ Compression implementation all logical blocks in cluster contain valid data and compress ratio of cluster data is lower than specified threshold. -- To enable compression on regular inode, there are three ways: +- To enable compression on regular inode, there are four ways: * chattr +c file * chattr +c dir; touch dir/file * mount w/ -o compress_extension=ext; touch file.ext * mount w/ -o compress_extension=*; touch any_file +- To disable compression on regular inode, there are two ways: + + * chattr -c file + * mount w/ -o nocompress_extension=ext; touch file.ext + +- Priority in between FS_COMPR_FL, FS_NOCOMP_FS, extensions: + + * compress_extension=so; nocompress_extension=zip; chattr +c dir; touch + dir/foo.so; touch dir/bar.zip; touch dir/baz.txt; then foo.so and baz.txt + should be compresse, bar.zip should be non-compressed. chattr +c dir/bar.zip + can enable compress on bar.zip. + * compress_extension=so; nocompress_extension=zip; chattr -c dir; touch + dir/foo.so; touch dir/bar.zip; touch dir/baz.txt; then foo.so should be + compresse, bar.zip and baz.txt should be non-compressed. + chattr+c dir/bar.zip; chattr+c dir/baz.txt; can enable compress on bar.zip + and baz.txt. + - At this point, compression feature doesn't expose compressed space to user directly in order to guarantee potential data updates later to the space. Instead, the main goal is to reduce data writes to flash disk as much as diff --git a/Documentation/firmware-guide/acpi/enumeration.rst b/Documentation/firmware-guide/acpi/enumeration.rst index 18074eb71860..74b830b2fd59 100644 --- a/Documentation/firmware-guide/acpi/enumeration.rst +++ b/Documentation/firmware-guide/acpi/enumeration.rst @@ -258,6 +258,38 @@ input driver:: .id_table = mpu3050_ids, }; +Reference to PWM device +======================= + +Sometimes a device can be a consumer of PWM channel. Obviously OS would like +to know which one. To provide this mapping the special property has been +introduced, i.e.:: + + Device (DEV) + { + Name (_DSD, Package () + { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", Package () { "pwm-leds" } }, + Package () { "label", "alarm-led" }, + Package () { "pwms", + Package () { + "\\_SB.PCI0.PWM", // + 0, // + 600000000, // + 0, // + } + } + } + + }) + ... + +In the above example the PWM-based LED driver references to the PWM channel 0 +of \_SB.PCI0.PWM device with initial period setting equal to 600 ms (note that +value is given in nanoseconds). + GPIO support ============ diff --git a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst index 0ca2cb646666..5ae9cfa2ec55 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst @@ -64,8 +64,6 @@ CPUfreq核心层注册一个cpufreq_driver结构体。 .driver_data - cpufreq驱动程序的特定数据。 - .resolve_freq - 返回最适合目标频率的频率。不过并不能改变频率。 - .get_intermediate 和 target_intermediate - 用于在改变CPU频率时切换到稳定 的频率。 @@ -76,9 +74,6 @@ CPUfreq核心层注册一个cpufreq_driver结构体。 .exit - 一个指向per-policy清理函数的指针,该函数在cpu热插拔过程的CPU_POST_DEAD 阶段被调用。 - .stop_cpu - 一个指向per-policy停止函数的指针,该函数在cpu热插拔过程的CPU_DOWN_PREPARE - 阶段被调用。 - .suspend - 一个指向per-policy暂停函数的指针,该函数在关中断且在该策略的调节器停止 后被调用。 diff --git a/Documentation/x86/elf_auxvec.rst b/Documentation/x86/elf_auxvec.rst new file mode 100644 index 000000000000..18e4744717f9 --- /dev/null +++ b/Documentation/x86/elf_auxvec.rst @@ -0,0 +1,53 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================== +x86-specific ELF Auxiliary Vectors +================================== + +This document describes the semantics of the x86 auxiliary vectors. + +Introduction +============ + +ELF Auxiliary vectors enable the kernel to efficiently provide +configuration-specific parameters to userspace. In this example, a program +allocates an alternate stack based on the kernel-provided size:: + + #include + #include + #include + #include + #include + #include + + #ifndef AT_MINSIGSTKSZ + #define AT_MINSIGSTKSZ 51 + #endif + + .... + stack_t ss; + + ss.ss_sp = malloc(ss.ss_size); + assert(ss.ss_sp); + + ss.ss_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ; + ss.ss_flags = 0; + + if (sigaltstack(&ss, NULL)) + err(1, "sigaltstack"); + + +The exposed auxiliary vectors +============================= + +AT_SYSINFO is used for locating the vsyscall entry point. It is not +exported on 64-bit mode. + +AT_SYSINFO_EHDR is the start address of the page containing the vDSO. + +AT_MINSIGSTKSZ denotes the minimum stack size required by the kernel to +deliver a signal to user-space. AT_MINSIGSTKSZ comprehends the space +consumed by the kernel to accommodate the user context for the current +hardware configuration. It does not comprehend subsequent user-space stack +consumption, which must be added by the user. (e.g. Above, user-space adds +SIGSTKSZ to AT_MINSIGSTKSZ.) diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst index 0004f5d2283e..383048396336 100644 --- a/Documentation/x86/index.rst +++ b/Documentation/x86/index.rst @@ -36,3 +36,4 @@ x86-specific Documentation sva sgx features + elf_auxvec diff --git a/MAINTAINERS b/MAINTAINERS index 17b0c3b3096f..37944c2a5ccc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -752,6 +752,12 @@ L: linux-crypto@vger.kernel.org S: Maintained F: drivers/crypto/allwinner/ +ALLWINNER HARDWARE SPINLOCK SUPPORT +M: Wilken Gottwalt +S: Maintained +F: Documentation/devicetree/bindings/hwlock/allwinner,sun6i-hwspinlock.yaml +F: drivers/hwspinlock/sun6i_hwspinlock.c + ALLWINNER THERMAL DRIVER M: Vasily Khoruzhick M: Yangtao Li @@ -1844,6 +1850,7 @@ F: Documentation/devicetree/bindings/arm/gemini.txt F: Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt F: Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt F: Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt +F: arch/arm/boot/dts/gemini* F: arch/arm/mach-gemini/ F: drivers/crypto/gemini/ F: drivers/net/ethernet/cortina/ @@ -2204,6 +2211,7 @@ M: Daniel Palmer L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://linux-chenxing.org/ +T: git git://github.com/linux-chenxing/linux.git F: Documentation/devicetree/bindings/arm/mstar/* F: Documentation/devicetree/bindings/clock/mstar,msc313-mpll.yaml F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml @@ -2211,6 +2219,7 @@ F: arch/arm/boot/dts/mstar-* F: arch/arm/mach-mstar/ F: drivers/clk/mstar/ F: drivers/gpio/gpio-msc313.c +F: drivers/watchdog/msc313e_wdt.c F: include/dt-bindings/clock/mstar-* F: include/dt-bindings/gpio/msc313-gpio.h @@ -2472,9 +2481,12 @@ F: drivers/*/*/*s3c24* F: drivers/*/*s3c24* F: drivers/*/*s3c64xx* F: drivers/*/*s5pv210* +F: drivers/clocksource/samsung_pwm_timer.c F: drivers/memory/samsung/ +F: drivers/pwm/pwm-samsung.c F: drivers/soc/samsung/ F: drivers/tty/serial/samsung* +F: include/clocksource/samsung_pwm.h F: include/linux/platform_data/*s3c* F: include/linux/serial_s3c.h F: include/linux/soc/samsung/ @@ -3769,6 +3781,17 @@ S: Supported F: Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt F: drivers/gpio/gpio-bcm-kona.c +BROADCOM MPI3 STORAGE CONTROLLER DRIVER +M: Sathya Prakash Veerichetty +M: Kashyap Desai +M: Sumit Saxena +M: Sreekanth Reddy +L: mpi3mr-linuxdrv.pdl@broadcom.com +L: linux-scsi@vger.kernel.org +S: Supported +W: https://www.broadcom.com/support/storage +F: drivers/scsi/mpi3mr/ + BROADCOM NETXTREME-E ROCE DRIVER M: Selvin Xavier M: Naresh Kumar PBS @@ -7003,7 +7026,7 @@ F: drivers/iommu/exynos-iommu.c F2FS FILE SYSTEM M: Jaegeuk Kim -M: Chao Yu +M: Chao Yu L: linux-f2fs-devel@lists.sourceforge.net S: Maintained W: https://f2fs.wiki.kernel.org/ @@ -7170,6 +7193,13 @@ F: include/linux/firewire.h F: include/uapi/linux/firewire*.h F: tools/firewire/ +FIRMWARE FRAMEWORK FOR ARMV8-A +M: Sudeep Holla +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: drivers/firmware/arm_ffa/ +F: include/linux/arm_ffa.h + FIRMWARE LOADER (request_firmware) M: Luis Chamberlain L: linux-kernel@vger.kernel.org @@ -9381,6 +9411,7 @@ F: include/linux/soc/ixp4xx/qmgr.h INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT M: Deepak Saxena S: Maintained +F: Documentation/devicetree/bindings/display/intel,ixp46x-rng.yaml F: drivers/char/hw_random/ixp4xx-rng.c INTEL KEEM BAY DRM DRIVER @@ -11941,6 +11972,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git F: Documentation/devicetree/bindings/memory-controllers/ F: drivers/memory/ F: include/dt-bindings/memory/ +F: include/memory/ MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA M: Dmitry Osipenko @@ -13516,12 +13548,6 @@ L: linux-omap@vger.kernel.org S: Maintained F: arch/arm/mach-omap2/omap_hwmod*data* -OMAP HWMOD DATA FOR OMAP4-BASED DEVICES -M: Benoît Cousson -L: linux-omap@vger.kernel.org -S: Maintained -F: arch/arm/mach-omap2/omap_hwmod_44xx_data.c - OMAP HWMOD SUPPORT M: Benoît Cousson M: Paul Walmsley @@ -14112,8 +14138,7 @@ F: Documentation/devicetree/bindings/pci/aardvark-pci.txt F: drivers/pci/controller/pci-aardvark.c PCI DRIVER FOR ALTERA PCIE IP -M: Ley Foon Tan -L: rfi@lists.rocketboards.org (moderated for non-subscribers) +M: Joyce Ooi L: linux-pci@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/pci/altera-pcie.txt @@ -14186,6 +14211,12 @@ S: Maintained F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml F: drivers/pci/controller/dwc/pcie-fu740.c +PCI DRIVER FOR INTEL IXP4XX +M: Linus Walleij +S: Maintained +F: Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml +F: drivers/pci/controller/pci-ixp4xx.c + PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD) M: Jonathan Derrick L: linux-pci@vger.kernel.org @@ -14311,8 +14342,7 @@ S: Supported F: Documentation/PCI/pci-error-recovery.rst PCI MSI DRIVER FOR ALTERA MSI IP -M: Ley Foon Tan -L: rfi@lists.rocketboards.org (moderated for non-subscribers) +M: Joyce Ooi L: linux-pci@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/pci/altera-pcie-msi.txt @@ -14833,6 +14863,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git F: Documentation/ABI/testing/sysfs-class-power F: Documentation/devicetree/bindings/power/supply/ F: drivers/power/supply/ +F: include/linux/power/ F: include/linux/power_supply.h POWERNV OPERATOR PANEL LCD DISPLAY DRIVER @@ -16219,7 +16250,7 @@ W: http://www.ibm.com/developerworks/linux/linux390/ F: drivers/s390/scsi/zfcp_* S3C ADC BATTERY DRIVER -M: Krzysztof Kozlowski +M: Krzysztof Kozlowski L: linux-samsung-soc@vger.kernel.org S: Odd Fixes F: drivers/power/supply/s3c_adc_battery.c @@ -18133,6 +18164,7 @@ F: include/media/i2c/tw9910.h TEE SUBSYSTEM M: Jens Wiklander +R: Sumit Garg L: op-tee@lists.trustedfirmware.org S: Maintained F: Documentation/staging/tee.rst diff --git a/Makefile b/Makefile index aa602a0e2cef..6c0a4686cf10 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 -PATCHLEVEL = 13 +PATCHLEVEL = 14 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Opossums on Parade # *DOCUMENTATION* @@ -129,6 +129,11 @@ endif $(if $(word 2, $(KBUILD_EXTMOD)), \ $(error building multiple external modules is not supported)) +# Remove trailing slashes +ifneq ($(filter %/, $(KBUILD_EXTMOD)),) +KBUILD_EXTMOD := $(shell dirname $(KBUILD_EXTMOD).) +endif + export KBUILD_EXTMOD # ANDROID: set up mixed-build support. mixed-build allows device kernel modules @@ -558,14 +563,21 @@ scripts_basic: $(Q)rm -f .tmp_quiet_recordmcount PHONY += outputmakefile +ifdef building_out_of_srctree # Before starting out-of-tree build, make sure the source tree is clean. # outputmakefile generates a Makefile in the output directory, if using a # separate output directory. This allows convenient use of make in the # output directory. # At the same time when output Makefile generated, generate .gitignore to # ignore whole output directory + +quiet_cmd_makefile = GEN Makefile + cmd_makefile = { \ + echo "\# Automatically generated by $(srctree)/Makefile: don't edit"; \ + echo "include $(srctree)/Makefile"; \ + } > Makefile + outputmakefile: -ifdef building_out_of_srctree $(Q)if [ -f $(srctree)/.config -o \ -d $(srctree)/include/config -o \ -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ @@ -576,7 +588,7 @@ ifdef building_out_of_srctree false; \ fi $(Q)ln -fsn $(srctree) source - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile $(srctree) + $(call cmd,makefile) $(Q)test -e .gitignore || \ { echo "# this is build directory, ignore it"; echo "*"; } > .gitignore endif @@ -672,7 +684,7 @@ endif ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit -core-y := init/ usr/ +core-y := init/ usr/ arch/$(SRCARCH)/ drivers-y := drivers/ sound/ drivers-$(CONFIG_SAMPLES) += samples/ drivers-$(CONFIG_NET) += net/ @@ -977,8 +989,8 @@ KBUILD_CFLAGS += $(CC_FLAGS_CFI) export CC_FLAGS_CFI endif -ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B -KBUILD_CFLAGS += -falign-functions=32 +ifdef CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B +KBUILD_CFLAGS += -falign-functions=64 endif # arch Makefile may override CC so keep this after arch Makefile is included @@ -1105,42 +1117,6 @@ export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE) MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) export MODLIB -HOST_LIBELF_LIBS = $(shell pkg-config libelf --libs 2>/dev/null || echo -lelf) - -has_libelf := $(call try-run,\ - echo "int main() {}" | \ - $(HOSTCC) $(KBUILD_HOSTCFLAGS) -xc -o /dev/null $(KBUILD_HOSTLDFLAGS) $(HOST_LIBELF_LIBS) -,1,0) - -ifdef CONFIG_STACK_VALIDATION - ifeq ($(has_libelf),1) - objtool_target := tools/objtool FORCE - else - SKIP_STACK_VALIDATION := 1 - export SKIP_STACK_VALIDATION - endif -endif - -PHONY += resolve_btfids_clean - -resolve_btfids_O = $(abspath $(objtree))/tools/bpf/resolve_btfids - -# tools/bpf/resolve_btfids directory might not exist -# in output directory, skip its clean in that case -resolve_btfids_clean: -ifneq ($(wildcard $(resolve_btfids_O)),) - $(Q)$(MAKE) -sC $(srctree)/tools/bpf/resolve_btfids O=$(resolve_btfids_O) clean -endif - -ifdef CONFIG_BPF -ifdef CONFIG_DEBUG_INFO_BTF - ifeq ($(has_libelf),1) - resolve_btfids_target := tools/bpf/resolve_btfids FORCE - else - ERROR_RESOLVE_BTFIDS := 1 - endif -endif # CONFIG_DEBUG_INFO_BTF -endif # CONFIG_BPF - PHONY += prepare0 export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/) @@ -1290,7 +1266,7 @@ prepare0: archprepare $(Q)$(MAKE) $(build)=. # All the preparing.. -prepare: prepare0 prepare-objtool prepare-resolve_btfids +prepare: prepare0 PHONY += remove-stale-files remove-stale-files: @@ -1307,26 +1283,6 @@ uapi-asm-generic: $(Q)$(MAKE) $(asm-generic)=arch/$(SRCARCH)/include/generated/uapi/asm \ generic=include/uapi/asm-generic -PHONY += prepare-objtool prepare-resolve_btfids -prepare-objtool: $(objtool_target) -ifeq ($(SKIP_STACK_VALIDATION),1) -ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL - @echo "error: Cannot generate __mcount_loc for CONFIG_DYNAMIC_FTRACE=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 - @false -endif -ifdef CONFIG_UNWINDER_ORC - @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 - @false -else - @echo "warning: Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 -endif -endif - -prepare-resolve_btfids: $(resolve_btfids_target) -ifeq ($(ERROR_RESOLVE_BTFIDS),1) - @echo "error: Cannot resolve BTF IDs for CONFIG_DEBUG_INFO_BTF, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 - @false -endif # Generate some files # --------------------------------------------------------------------------- @@ -1392,6 +1348,43 @@ PHONY += scripts_unifdef scripts_unifdef: scripts_basic $(Q)$(MAKE) $(build)=scripts scripts/unifdef +# --------------------------------------------------------------------------- +# Tools + +ifdef CONFIG_STACK_VALIDATION +prepare: tools/objtool +endif + +ifdef CONFIG_BPF +ifdef CONFIG_DEBUG_INFO_BTF +prepare: tools/bpf/resolve_btfids +endif +endif + +PHONY += resolve_btfids_clean + +resolve_btfids_O = $(abspath $(objtree))/tools/bpf/resolve_btfids + +# tools/bpf/resolve_btfids directory might not exist +# in output directory, skip its clean in that case +resolve_btfids_clean: +ifneq ($(wildcard $(resolve_btfids_O)),) + $(Q)$(MAKE) -sC $(srctree)/tools/bpf/resolve_btfids O=$(resolve_btfids_O) clean +endif + +# Clear a bunch of variables before executing the submake +ifeq ($(quiet),silent_) +tools_silent=s +endif + +tools/: FORCE + $(Q)mkdir -p $(objtree)/tools + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ + +tools/%: FORCE + $(Q)mkdir -p $(objtree)/tools + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ $* + # --------------------------------------------------------------------------- # Kernel selftest @@ -1997,20 +1990,6 @@ kernelversion: image_name: @echo $(KBUILD_IMAGE) -# Clear a bunch of variables before executing the submake - -ifeq ($(quiet),silent_) -tools_silent=s -endif - -tools/: FORCE - $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ - -tools/%: FORCE - $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ $* - quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))) cmd_rmfiles = rm -rf $(rm-files) diff --git a/arch/alpha/Kbuild b/arch/alpha/Kbuild new file mode 100644 index 000000000000..c2302017403a --- /dev/null +++ b/arch/alpha/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += kernel/ mm/ +obj-$(CONFIG_MATHEMU) += math-emu/ diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index c2946431d88d..52529ee42dac 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -38,8 +38,6 @@ KBUILD_CFLAGS += $(cflags-y) -Wa,-mev6 head-y := arch/alpha/kernel/head.o -core-y += arch/alpha/kernel/ arch/alpha/mm/ -core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/ libs-y += arch/alpha/lib/ # export what is needed by arch/alpha/boot/Makefile diff --git a/arch/alpha/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h index ff690846465e..02f0429f1068 100644 --- a/arch/alpha/include/asm/pgtable.h +++ b/arch/alpha/include/asm/pgtable.h @@ -236,8 +236,10 @@ pmd_page_vaddr(pmd_t pmd) #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> 32)) #define pud_page(pud) (pfn_to_page(pud_val(pud) >> 32)) -extern inline unsigned long pud_page_vaddr(pud_t pgd) -{ return PAGE_OFFSET + ((pud_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); } +extern inline pmd_t *pud_pgtable(pud_t pgd) +{ + return (pmd_t *)(PAGE_OFFSET + ((pud_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT))); +} extern inline int pte_none(pte_t pte) { return !pte_val(pte); } extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_VALID; } @@ -287,7 +289,7 @@ extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= __ACCESS_BITS; retu /* Find an entry in the second-level page table.. */ extern inline pmd_t * pmd_offset(pud_t * dir, unsigned long address) { - pmd_t *ret = (pmd_t *) pud_page_vaddr(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1)); + pmd_t *ret = pud_pgtable(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1)); smp_rmb(); /* see above */ return ret; } diff --git a/arch/arc/Makefile b/arch/arc/Makefile index e47adc97a89b..c0d87ac2e221 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -85,9 +85,6 @@ KBUILD_LDFLAGS += $(ldflags-y) head-y := arch/arc/kernel/head.o -# See arch/arc/Kbuild for content of core part of the kernel -core-y += arch/arc/ - # w/o this dtb won't embed into kernel binary core-y += arch/arc/boot/dts/ diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index abfeef7bf6f8..c083bf660cec 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -89,10 +89,7 @@ void __init setup_arch_memory(void) { unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; - init_mm.start_code = (unsigned long)_text; - init_mm.end_code = (unsigned long)_etext; - init_mm.end_data = (unsigned long)_edata; - init_mm.brk = (unsigned long)_end; + setup_initial_init_mm(_text, _etext, _edata, _end); /* first page of system - kernel .vector starts here */ min_low_pfn = virt_to_pfn(CONFIG_LINUX_RAM_BASE); diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d329c12a359a..2bbd373ac034 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -393,7 +393,8 @@ config ARCH_IXP4XX select HAVE_PCI select IXP4XX_IRQ select IXP4XX_TIMER - select NEED_MACH_IO_H + # With the new PCI driver this is not needed + select NEED_MACH_IO_H if PCI_IXP4XX_LEGACY select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO help diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 36016497b1b3..1c4384db223d 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -66,6 +66,8 @@ config UNWINDER_FRAME_POINTER config UNWINDER_ARM bool "ARM EABI stack unwinder" depends on AEABI && !FUNCTION_GRAPH_TRACER + # https://github.com/ClangBuiltLinux/linux/issues/732 + depends on !LD_IS_LLD || LLD_VERSION >= 110000 select ARM_UNWIND help This option enables stack unwinding support in the kernel @@ -607,6 +609,14 @@ choice when u-boot hands over to the kernel, the system silently crashes, with no serial output at all. + config DEBUG_MSTARV7_PMUART + bool "Kernel low-level debugging messages via MSTARV7 PM UART" + depends on ARCH_MSTARV7 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for MSTAR ARMv7-based platforms on PM UART. + config DEBUG_MT6589_UART0 bool "Mediatek mt6589 UART0" depends on ARCH_MEDIATEK @@ -1605,6 +1615,7 @@ config DEBUG_UART_PHYS default 0x18000400 if DEBUG_BCM_HR2 default 0x18023000 if DEBUG_BCM_IPROC_UART3 default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 + default 0x1f221000 if DEBUG_MSTARV7_PMUART default 0x20001000 if DEBUG_HIP01_UART default 0x20060000 if DEBUG_RK29_UART0 default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2 @@ -1722,6 +1733,7 @@ config DEBUG_UART_VIRT default 0xf0100000 if DEBUG_DIGICOLOR_UA0 default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836 + default 0xf0221000 if DEBUG_MSTARV7_PMUART default 0xf1000300 if DEBUG_BCM_5301X default 0xf1000400 if DEBUG_BCM_HR2 default 0xf1002000 if DEBUG_MT8127_UART0 @@ -1803,8 +1815,8 @@ config DEBUG_UART_VIRT default 0xfedc0000 if DEBUG_EP93XX default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1 default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART - default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN - default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN + default 0xfec00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN + default 0xfec00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef36000 if DEBUG_HIGHBANK_UART default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 @@ -1827,6 +1839,7 @@ config DEBUG_UART_8250_SHIFT default 0 if DEBUG_FOOTBRIDGE_COM1 || ARCH_IOP32X || DEBUG_BCM_5301X || \ DEBUG_BCM_HR2 || DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || \ DEBUG_OMAP7XXUART3 + default 3 if DEBUG_MSTARV7_PMUART default 2 config DEBUG_UART_8250_WORD diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 415c3514573a..173da685a52e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -252,7 +252,6 @@ endif export TEXT_OFFSET GZFLAGS MMUEXT -core-y += arch/arm/ # If we have a machine-specific directory, then include it in the build. core-y += $(machdirs) $(platdirs) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 8eb70c1febce..9d91ae1091b0 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -100,7 +100,7 @@ targets := vmlinux vmlinux.lds piggy_data piggy.o \ lib1funcs.o ashldi3.o bswapsdi2.o \ head.o $(OBJS) -clean-files += piggy_data lib1funcs.S ashldi3.S bswapsdi2.S hyp-stub.S +clean-files += lib1funcs.S ashldi3.S bswapsdi2.S hyp-stub.S KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c index 31927d2fe297..1feb6b0f7a1f 100644 --- a/arch/arm/boot/compressed/atags_to_fdt.c +++ b/arch/arm/boot/compressed/atags_to_fdt.c @@ -121,7 +121,7 @@ static void hex_str(char *out, uint32_t value) /* * Convert and fold provided ATAGs into the provided FDT. * - * REturn values: + * Return values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index f8f09c5066e7..863347b6b65e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -88,6 +88,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ bcm2837-rpi-3-b.dtb \ bcm2837-rpi-3-b-plus.dtb \ bcm2837-rpi-cm3-io3.dtb \ + bcm2711-rpi-400.dtb \ bcm2711-rpi-4-b.dtb \ bcm2835-rpi-zero.dtb \ bcm2835-rpi-zero-w.dtb @@ -240,6 +241,7 @@ dtb-$(CONFIG_ARCH_INTEGRATOR) += \ integratorcp.dtb dtb-$(CONFIG_ARCH_IXP4XX) += \ intel-ixp42x-linksys-nslu2.dtb \ + intel-ixp42x-welltech-epbx100.dtb \ intel-ixp43x-gateworks-gw2358.dtb dtb-$(CONFIG_ARCH_KEYSTONE) += \ keystone-k2hk-evm.dtb \ @@ -513,8 +515,14 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-display5-tianma-tm070-1280x768.dtb \ imx6q-dmo-edmqmx6.dtb \ imx6q-dms-ba16.dtb \ + imx6q-ds.dtb \ imx6q-emcon-avari.dtb \ imx6q-evi.dtb \ + imx6dl-b105pv2.dtb \ + imx6dl-b105v2.dtb \ + imx6dl-b125v2.dtb \ + imx6dl-b125pv2.dtb \ + imx6dl-b155v2.dtb \ imx6q-gk802.dtb \ imx6q-gw51xx.dtb \ imx6q-gw52xx.dtb \ @@ -725,7 +733,8 @@ dtb-$(CONFIG_ARCH_MXS) += \ imx28-m28evk.dtb \ imx28-sps1.dtb \ imx28-ts4600.dtb \ - imx28-tx28.dtb + imx28-tx28.dtb \ + imx28-xea.dtb dtb-$(CONFIG_ARCH_NOMADIK) += \ ste-nomadik-s8815.dtb \ ste-nomadik-nhk15.dtb @@ -1234,6 +1243,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \ sun8i-r16-nintendo-super-nes-classic.dtb \ sun8i-r16-parrot.dtb \ sun8i-r40-bananapi-m2-ultra.dtb \ + sun8i-r40-oka40i-c.dtb \ sun8i-s3-elimo-initium.dtb \ sun8i-s3-lichee-zero-plus.dtb \ sun8i-s3-pinecube.dtb \ @@ -1415,6 +1425,7 @@ dtb-$(CONFIG_ARCH_MSTARV7) += \ mstar-mercury5-ssc8336n-midrived08.dtb dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-ast2500-evb.dtb \ + aspeed-ast2600-evb-a1.dtb \ aspeed-ast2600-evb.dtb \ aspeed-bmc-amd-ethanolx.dtb \ aspeed-bmc-ampere-mtjade.dtb \ diff --git a/arch/arm/boot/dts/am335x-baltos.dtsi b/arch/arm/boot/dts/am335x-baltos.dtsi index 3ea286180382..1103a2cb836f 100644 --- a/arch/arm/boot/dts/am335x-baltos.dtsi +++ b/arch/arm/boot/dts/am335x-baltos.dtsi @@ -393,10 +393,10 @@ status = "okay"; }; -&gpio0 { +&gpio0_target { ti,no-reset-on-init; }; -&gpio3 { +&gpio3_target { ti,no-reset-on-init; }; diff --git a/arch/arm/boot/dts/am335x-boneblack-wireless.dts b/arch/arm/boot/dts/am335x-boneblack-wireless.dts index 86cad9912906..80116646a3fe 100644 --- a/arch/arm/boot/dts/am335x-boneblack-wireless.dts +++ b/arch/arm/boot/dts/am335x-boneblack-wireless.dts @@ -101,7 +101,7 @@ }; &gpio3 { - ls_buf_en { + ls-buf-en-hog { gpio-hog; gpios = <10 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts index 69acaf4ea0f3..0afcc2ee0b63 100644 --- a/arch/arm/boot/dts/am335x-boneblue.dts +++ b/arch/arm/boot/dts/am335x-boneblue.dts @@ -436,7 +436,7 @@ }; &gpio3 { - ls_buf_en { + ls-buf-en-hog { gpio-hog; gpios = <10 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm/boot/dts/am335x-bonegreen-wireless.dts b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts index 7615327d906a..74db0fc39397 100644 --- a/arch/arm/boot/dts/am335x-bonegreen-wireless.dts +++ b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts @@ -101,7 +101,7 @@ }; &gpio1 { - ls_buf_en { + ls-buf-en-hog { gpio-hog; gpios = <29 GPIO_ACTIVE_HIGH>; output-high; @@ -118,7 +118,7 @@ /* an external pulldown on U21 pin 4. */ &gpio3 { - bt_aud_in { + bt-aud-in-hog { gpio-hog; gpios = <16 GPIO_ACTIVE_HIGH>; output-low; diff --git a/arch/arm/boot/dts/am335x-cm-t335.dts b/arch/arm/boot/dts/am335x-cm-t335.dts index 36d963db4026..688e14e82eba 100644 --- a/arch/arm/boot/dts/am335x-cm-t335.dts +++ b/arch/arm/boot/dts/am335x-cm-t335.dts @@ -333,7 +333,7 @@ status = "okay"; &epwmss0 { status = "okay"; - ecap0: ecap@100 { + ecap0: pwm@100 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&ecap0_pins>; @@ -496,7 +496,7 @@ status = "okay"; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&spi0_pins>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; /* WLS1271 WiFi */ wlcore: wlcore@1 { compatible = "ti,wl1271"; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 902e295b309e..9cf39c93defb 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -495,7 +495,7 @@ &epwmss0 { status = "okay"; - ecap0: ecap@100 { + ecap0: pwm@100 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&ecap0_pins>; diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index d5f8d5e2eb5d..001657be0381 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -510,7 +510,7 @@ &epwmss2 { status = "okay"; - ecap2: ecap@100 { + ecap2: pwm@100 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&ecap2_pins>; @@ -646,7 +646,7 @@ status = "okay"; }; -&gpio0 { +&gpio0_target { ti,no-reset-on-init; }; diff --git a/arch/arm/boot/dts/am335x-icev2.dts b/arch/arm/boot/dts/am335x-icev2.dts index e923d065304d..5e598ac96dcc 100644 --- a/arch/arm/boot/dts/am335x-icev2.dts +++ b/arch/arm/boot/dts/am335x-icev2.dts @@ -458,14 +458,14 @@ }; &gpio3 { - p4 { + pr1-mii-ctl-hog { gpio-hog; gpios = <4 GPIO_ACTIVE_HIGH>; output-high; line-name = "PR1_MII_CTRL"; }; - p10 { + mux-mii-hog { gpio-hog; gpios = <10 GPIO_ACTIVE_HIGH>; /* ETH1 mux: Low for MII-PRU, high for RMII-CPSW */ diff --git a/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi b/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi index 4e90f9c23d2e..8121a199607c 100644 --- a/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi +++ b/arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi @@ -150,7 +150,7 @@ status = "okay"; }; -&gpio0 { +&gpio0_target { ti,no-reset-on-init; }; diff --git a/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi b/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi index 98d8ed4ad967..39e5d2ce600a 100644 --- a/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi +++ b/arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi @@ -353,7 +353,7 @@ status = "okay"; }; -&gpio0 { +&gpio0_target { ti,no-reset-on-init; }; diff --git a/arch/arm/boot/dts/am335x-osd3358-sm-red.dts b/arch/arm/boot/dts/am335x-osd3358-sm-red.dts index f841afb27844..5403e47c07e2 100644 --- a/arch/arm/boot/dts/am335x-osd3358-sm-red.dts +++ b/arch/arm/boot/dts/am335x-osd3358-sm-red.dts @@ -25,10 +25,6 @@ regulator-always-on; }; -&mmc1 { - vmmc-supply = <&vmmcsd_fixed>; -}; - &mmc2 { vmmc-supply = <&vmmcsd_fixed>; pinctrl-names = "default"; @@ -37,68 +33,6 @@ status = "okay"; }; -&am33xx_pinmux { - nxp_hdmi_bonelt_pins: nxp-hdmi-bonelt-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - >; - }; - - nxp_hdmi_bonelt_off_pins: nxp-hdmi-bonelt-off-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) - >; - }; - - mcasp0_pins: mcasp0-pins { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/ - AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0) - AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */ - >; - }; - - flash_enable: flash-enable { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* rmii1_ref_clk.gpio0_29 */ - >; - }; - - imu_interrupt: imu-interrupt { - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mii1_rx_er.gpio3_2 */ - >; - }; - - ethernet_interrupt: ethernet-interrupt{ - pinctrl-single,pins = < - AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mii1_col.gpio3_0 */ - >; - }; -}; - &lcdc { status = "okay"; @@ -167,10 +101,6 @@ }; }; -&rtc { - system-power-controller; -}; - &mcasp0 { #sound-dai-cells = <0>; pinctrl-names = "default"; @@ -267,6 +197,66 @@ pinctrl-names = "default"; pinctrl-0 = <&clkout2_pin>; + nxp_hdmi_bonelt_pins: nxp-hdmi-bonelt-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + >; + }; + + nxp_hdmi_bonelt_off_pins: nxp-hdmi-bonelt-off-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3) + >; + }; + + mcasp0_pins: mcasp0-pins { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/ + AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0) + AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */ + >; + }; + + flash_enable: flash-enable { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* rmii1_ref_clk.gpio0_29 */ + >; + }; + + imu_interrupt: imu-interrupt { + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mii1_rx_er.gpio3_2 */ + >; + }; + + ethernet_interrupt: ethernet-interrupt{ + pinctrl-single,pins = < + AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mii1_col.gpio3_0 */ + >; + }; + user_leds_s0: user-leds-s0 { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a5.gpio1_21 */ @@ -427,6 +417,7 @@ &mmc1 { status = "okay"; + vmmc-supply = <&vmmcsd_fixed>; bus-width = <0x4>; pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins>; @@ -434,6 +425,7 @@ }; &rtc { + system-power-controller; clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am335x-shc.dts b/arch/arm/boot/dts/am335x-shc.dts index 1eaa26533466..2bfe60d32783 100644 --- a/arch/arm/boot/dts/am335x-shc.dts +++ b/arch/arm/boot/dts/am335x-shc.dts @@ -140,14 +140,14 @@ }; &gpio1 { - hmtc_rst { + hmtc-rst-hog { gpio-hog; gpios = <24 GPIO_ACTIVE_LOW>; output-high; line-name = "homematic_reset"; }; - hmtc_prog { + hmtc-prog-hog { gpio-hog; gpios = <27 GPIO_ACTIVE_LOW>; output-high; @@ -156,14 +156,14 @@ }; &gpio3 { - zgb_rst { + zgb-rst-hog { gpio-hog; gpios = <18 GPIO_ACTIVE_LOW>; output-low; line-name = "zigbee_reset"; }; - zgb_boot { + zgb-boot-hog { gpio-hog; gpios = <19 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi index 039a9ab4c7ea..859e760df4c8 100644 --- a/arch/arm/boot/dts/am33xx-l4.dtsi +++ b/arch/arm/boot/dts/am33xx-l4.dtsi @@ -1486,7 +1486,7 @@ #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <8>; - mbox_wkupm3: wkup_m3 { + mbox_wkupm3: mbox-wkup-m3 { ti,mbox-send-noirq; ti,mbox-tx = <0 0 0>; ti,mbox-rx = <0 0 3>; @@ -1789,7 +1789,7 @@ }; }; - target-module@ae000 { /* 0x481ae000, ap 56 3a.0 */ + gpio3_target: target-module@ae000 { /* 0x481ae000, ap 56 3a.0 */ compatible = "ti,sysc-omap2", "ti,sysc"; reg = <0xae000 0x4>, <0xae010 0x4>, @@ -1995,15 +1995,12 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap0: ecap@100 { - compatible = "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap0: pwm@100 { + compatible = "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; clock-names = "fck"; - interrupts = <31>; - interrupt-names = "ecap0"; status = "disabled"; }; @@ -2017,8 +2014,7 @@ }; ehrpwm0: pwm@200 { - compatible = "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + compatible = "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; @@ -2056,15 +2052,12 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap1: ecap@100 { - compatible = "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap1: pwm@100 { + compatible = "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; clock-names = "fck"; - interrupts = <47>; - interrupt-names = "ecap1"; status = "disabled"; }; @@ -2078,8 +2071,7 @@ }; ehrpwm1: pwm@200 { - compatible = "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + compatible = "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm1_tbclk>, <&l4ls_gclk>; @@ -2117,15 +2109,12 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap2: ecap@100 { - compatible = "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap2: pwm@100 { + compatible = "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; clock-names = "fck"; - interrupts = <61>; - interrupt-names = "ecap2"; status = "disabled"; }; @@ -2139,8 +2128,7 @@ }; ehrpwm2: pwm@200 { - compatible = "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + compatible = "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm2_tbclk>, <&l4ls_gclk>; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 6e4d05d649e9..e2677682b540 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -786,7 +786,7 @@ pinctrl-0 = <&gpio0_pins>; status = "okay"; - p23 { + sel-emmc-nand-hog { gpio-hog; gpios = <23 GPIO_ACTIVE_HIGH>; /* SelEMMCorNAND selects between eMMC and NAND: @@ -813,13 +813,16 @@ status = "okay"; }; +&gpio5_target { + ti,no-reset-on-init; +}; + &gpio5 { pinctrl-names = "default"; pinctrl-0 = <&display_mux_pins>; status = "okay"; - ti,no-reset-on-init; - p8 { + sel-lcd-hdmi-hog { /* * SelLCDorHDMI selects between display and audio paths: * Low: HDMI display with audio via HDMI diff --git a/arch/arm/boot/dts/am437x-l4.dtsi b/arch/arm/boot/dts/am437x-l4.dtsi index e217ffc09770..40ef3973f2a9 100644 --- a/arch/arm/boot/dts/am437x-l4.dtsi +++ b/arch/arm/boot/dts/am437x-l4.dtsi @@ -194,7 +194,7 @@ ranges = <0x0 0x9000 0x1000>; uart0: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; }; @@ -712,7 +712,7 @@ ranges = <0x0 0x22000 0x1000>; uart1: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; status = "disabled"; @@ -740,7 +740,7 @@ ranges = <0x0 0x24000 0x1000>; uart2: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; status = "disabled"; @@ -1168,7 +1168,7 @@ #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <8>; - mbox_wkupm3: wkup_m3 { + mbox_wkupm3: mbox-wkup-m3 { ti,mbox-send-noirq; ti,mbox-tx = <0 0 0>; ti,mbox-rx = <0 0 3>; @@ -1399,7 +1399,7 @@ ranges = <0x0 0xa6000 0x1000>; uart3: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; status = "disabled"; @@ -1427,7 +1427,7 @@ ranges = <0x0 0xa8000 0x1000>; uart4: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; status = "disabled"; @@ -1455,7 +1455,7 @@ ranges = <0x0 0xaa000 0x1000>; uart5: serial@0 { - compatible = "ti,am4372-uart","ti,omap2-uart"; + compatible = "ti,am4372-uart"; reg = <0x0 0x2000>; interrupts = ; status = "disabled"; @@ -1747,10 +1747,9 @@ ranges = <0 0 0x1000>; status = "disabled"; - ecap0: ecap@100 { + ecap0: pwm@100 { compatible = "ti,am4372-ecap", - "ti,am3352-ecap", - "ti,am33xx-ecap"; + "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; @@ -1760,8 +1759,7 @@ ehrpwm0: pwm@200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; @@ -1799,10 +1797,9 @@ ranges = <0 0 0x1000>; status = "disabled"; - ecap1: ecap@100 { + ecap1: pwm@100 { compatible = "ti,am4372-ecap", - "ti,am3352-ecap", - "ti,am33xx-ecap"; + "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; @@ -1812,8 +1809,7 @@ ehrpwm1: pwm@200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm1_tbclk>, <&l4ls_gclk>; @@ -1851,10 +1847,9 @@ ranges = <0 0 0x1000>; status = "disabled"; - ecap2: ecap@100 { + ecap2: pwm@100 { compatible = "ti,am4372-ecap", - "ti,am3352-ecap", - "ti,am33xx-ecap"; + "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x100 0x80>; clocks = <&l4ls_gclk>; @@ -1864,8 +1859,7 @@ ehrpwm2: pwm@200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm2_tbclk>, <&l4ls_gclk>; @@ -1905,8 +1899,7 @@ ehrpwm3: pwm@200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm3_tbclk>, <&l4ls_gclk>; @@ -1946,8 +1939,7 @@ ehrpwm4: pwm@48308200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm4_tbclk>, <&l4ls_gclk>; @@ -1987,8 +1979,7 @@ ehrpwm5: pwm@200 { compatible = "ti,am4372-ehrpwm", - "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x200 0x80>; clocks = <&ehrpwm5_tbclk>, <&l4ls_gclk>; @@ -2070,7 +2061,7 @@ }; }; - target-module@22000 { /* 0x48322000, ap 116 64.0 */ + gpio5_target: target-module@22000 { /* 0x48322000, ap 116 64.0 */ compatible = "ti,sysc-omap2", "ti,sysc"; reg = <0x22000 0x4>, <0x22010 0x4>, diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index f517d1e843cf..aae0af10a5b1 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -725,7 +725,7 @@ pinctrl-0 = <&display_mux_pins>; status = "okay"; - p1 { + sel-lcd-hdmi-hog { /* * SelLCDorHDMI selects between display and audio paths: * Low: HDMI display with audio via HDMI @@ -860,7 +860,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&spi0_pins_default>; pinctrl-1 = <&spi0_pins_sleep>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; }; &spi1 { @@ -868,7 +868,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&spi1_pins_default>; pinctrl-1 = <&spi1_pins_sleep>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; }; &usb2_phy1 { diff --git a/arch/arm/boot/dts/am5718.dtsi b/arch/arm/boot/dts/am5718.dtsi index ebf4d3cc1cfb..6d7530a48c73 100644 --- a/arch/arm/boot/dts/am5718.dtsi +++ b/arch/arm/boot/dts/am5718.dtsi @@ -17,17 +17,13 @@ * VCP1, VCP2 * MLB * ISS - * USB3, USB4 + * USB3 */ &usb3_tm { status = "disabled"; }; -&usb4_tm { - status = "disabled"; -}; - &atl_tm { status = "disabled"; }; diff --git a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts index 0d5fe2bfb683..aed81568a297 100644 --- a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts +++ b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts @@ -454,20 +454,20 @@ &mailbox5 { status = "okay"; - mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { + mbox_ipu1_ipc3x: mbox-ipu1-ipc3x { status = "okay"; }; - mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { + mbox_dsp1_ipc3x: mbox-dsp1-ipc3x { status = "okay"; }; }; &mailbox6 { status = "okay"; - mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { + mbox_ipu2_ipc3x: mbox-ipu2-ipc3x { status = "okay"; }; - mbox_dsp2_ipc3x: mbox_dsp2_ipc3x { + mbox_dsp2_ipc3x: mbox-dsp2-ipc3x { status = "okay"; }; }; @@ -610,12 +610,11 @@ >; }; -&gpio3 { - status = "okay"; +&gpio3_target { ti,no-reset-on-init; }; -&gpio2 { +&gpio2_target { status = "okay"; ti,no-reset-on-init; }; diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts index 8bec21ed0de5..583a241f1151 100644 --- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts @@ -13,7 +13,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + bootargs = "console=tty0 console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts b/arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts new file mode 100644 index 000000000000..dd7148060c4a --- /dev/null +++ b/arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2021 IBM Corp. + +#include "aspeed-ast2600-evb.dts" + +/ { + model = "AST2600 A1 EVB"; + + /delete-node/regulator-vcc-sdhci0; + /delete-node/regulator-vcc-sdhci1; + /delete-node/regulator-vccq-sdhci0; + /delete-node/regulator-vccq-sdhci1; +}; + +/delete-node/ &sdc; diff --git a/arch/arm/boot/dts/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed-ast2600-evb.dts index 2772796e215e..b7eb552640cb 100644 --- a/arch/arm/boot/dts/aspeed-ast2600-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2600-evb.dts @@ -4,6 +4,7 @@ /dts-v1/; #include "aspeed-g6.dtsi" +#include / { model = "AST2600 EVB"; @@ -21,6 +22,46 @@ device_type = "memory"; reg = <0x80000000 0x80000000>; }; + + vcc_sdhci0: regulator-vcc-sdhci0 { + compatible = "regulator-fixed"; + regulator-name = "SDHCI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio0 ASPEED_GPIO(V, 0) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhci0: regulator-vccq-sdhci0 { + compatible = "regulator-gpio"; + regulator-name = "SDHCI0 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio0 ASPEED_GPIO(V, 1) GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1>, + <1800000 0>; + }; + + vcc_sdhci1: regulator-vcc-sdhci1 { + compatible = "regulator-fixed"; + regulator-name = "SDHCI1 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio0 ASPEED_GPIO(V, 2) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhci1: regulator-vccq-sdhci1 { + compatible = "regulator-gpio"; + regulator-name = "SDHCI1 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio0 ASPEED_GPIO(V, 3) GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1>, + <1800000 0>; + }; }; &mdio0 { @@ -107,7 +148,8 @@ &emmc { non-removable; bus-width = <4>; - max-frequency = <52000000>; + max-frequency = <100000000>; + clk-phase-mmc-hs200 = <9>, <225>; }; &rtc { @@ -121,37 +163,7 @@ m25p,fast-read; label = "bmc"; spi-max-frequency = <50000000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - u-boot@0 { - reg = <0x0 0xe0000>; // 896KB - label = "u-boot"; - }; - - u-boot-env@e0000 { - reg = <0xe0000 0x20000>; // 128KB - label = "u-boot-env"; - }; - - kernel@100000 { - reg = <0x100000 0x900000>; // 9MB - label = "kernel"; - }; - - rofs@a00000 { - reg = <0xa00000 0x2000000>; // 32MB - label = "rofs"; - }; - - rwfs@6000000 { - reg = <0x2a00000 0x1600000>; // 22MB - label = "rwfs"; - }; - }; +#include "openbmc-flash-layout-64.dtsi" }; }; @@ -245,3 +257,46 @@ &uhci { status = "okay"; }; + +&sdc { + status = "okay"; +}; + +/* + * The signal voltage of sdhci0 and sdhci1 on AST2600-A2 EVB is able to be + * toggled by GPIO pins. + * In the reference design, GPIOV0 of AST2600-A2 EVB is connected to the + * power load switch that provides 3.3v to sdhci0 vdd, GPIOV1 is connected to + * a 1.8v and a 3.3v power load switch that provides signal voltage to + * sdhci0 bus. + * If GPIOV0 is active high, sdhci0 is enabled, otherwise, sdhci0 is disabled. + * If GPIOV1 is active high, 3.3v power load switch is enabled, sdhci0 signal + * voltage is 3.3v, otherwise, 1.8v power load switch will be enabled, + * sdhci0 signal voltage becomes 1.8v. + * AST2600-A2 EVB also supports toggling signal voltage for sdhci1. + * The design is the same as sdhci0, it uses GPIOV2 as power-gpio and GPIOV3 + * as power-switch-gpio. + */ +&sdhci0 { + status = "okay"; + bus-width = <4>; + max-frequency = <100000000>; + sdhci-drive-type = /bits/ 8 <3>; + sdhci-caps-mask = <0x7 0x0>; + sdhci,wp-inverted; + vmmc-supply = <&vcc_sdhci0>; + vqmmc-supply = <&vccq_sdhci0>; + clk-phase-sd-hs = <7>, <200>; +}; + +&sdhci1 { + status = "okay"; + bus-width = <4>; + max-frequency = <100000000>; + sdhci-drive-type = /bits/ 8 <3>; + sdhci-caps-mask = <0x7 0x0>; + sdhci,wp-inverted; + vmmc-supply = <&vcc_sdhci1>; + vqmmc-supply = <&vccq_sdhci1>; + clk-phase-sd-hs = <7>, <200>; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts b/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts index 6aeb47c44eba..79d17841b3d7 100644 --- a/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts +++ b/arch/arm/boot/dts/aspeed-bmc-amd-ethanolx.dts @@ -34,7 +34,7 @@ }; chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; leds { compatible = "gpio-leds"; diff --git a/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts b/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts index 8f5ec22e51c2..57b0c45a2298 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts @@ -9,7 +9,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { @@ -110,6 +110,30 @@ linux,code = ; }; + psu1_vin_good { + label = "PSU1_VIN_GOOD"; + gpios = <&gpio ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + psu2_vin_good { + label = "PSU2_VIN_GOOD"; + gpios = <&gpio ASPEED_GPIO(H, 5) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + psu1_present { + label = "PSU1_PRESENT"; + gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + psu2_present { + label = "PSU2_PRESENT"; + gpios = <&gpio ASPEED_GPIO(I, 1) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; gpioA0mux: mux-controller { @@ -280,7 +304,7 @@ m25p,fast-read; label = "bmc"; /* spi-max-frequency = <50000000>; */ -#include "openbmc-flash-layout.dtsi" +#include "openbmc-flash-layout-64.dtsi" }; }; @@ -332,6 +356,16 @@ status = "okay"; }; +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>, + <&syscon ASPEED_CLK_MAC1RCLK>; + clock-names = "MACCLK", "RCLK"; + use-ncsi; +}; + &mac1 { status = "okay"; pinctrl-names = "default"; @@ -426,6 +460,19 @@ status = "okay"; }; +&i2c10 { + status = "okay"; + adm1278@10 { + compatible = "adi,adm1278"; + reg = <0x10>; + }; + + adm1278@11 { + compatible = "adi,adm1278"; + reg = <0x11>; + }; +}; + &gfx { status = "okay"; memory-region = <&gfx_memory>; @@ -529,8 +576,9 @@ "S1_DDR_SAVE","","", /*G0-G7*/ "S0_FW_BOOT_OK","SHD_REQ_L","","S0_OVERTEMP_L","","", "","", - /*H0-H7*/ "","","","","","","","", - /*I0-I7*/ "","","S1_BMC_SPECIAL_BOOT","","","","","", + /*H0-H7*/ "","","","","PSU1_VIN_GOOD","PSU2_VIN_GOOD","","", + /*I0-I7*/ "PSU1_PRESENT","PSU2_PRESENT","S1_BMC_SPECIAL_BOOT", + "","","","","", /*J0-J7*/ "S0_HIGHTEMP_L","S0_FAULT_L","S0_SCP_AUTH_FAIL_L","", "","","","", /*K0-K7*/ "","","","","","","","", @@ -540,7 +588,8 @@ /*O0-O7*/ "","","","","","","","", /*P0-P7*/ "","","","","","","","", /*Q0-Q7*/ "","","","","","UID_BUTTON","","", - /*R0-R7*/ "","","BMC_EXT_HIGHTEMP_L","","","RESET_BUTTON","","", + /*R0-R7*/ "","","BMC_EXT_HIGHTEMP_L","OCP_AUX_PWREN", + "OCP_MAIN_PWREN","RESET_BUTTON","","", /*S0-S7*/ "","","","","","","","", /*T0-T7*/ "","","","","","","","", /*U0-U7*/ "","","","","","","","", diff --git a/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts b/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts index c2ece0b91885..3395de96ee11 100644 --- a/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts +++ b/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts b/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts index 2c29ac037d32..7c6af7f226e7 100644 --- a/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts +++ b/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts b/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts index dcab6e78dfa4..33e413ca07e4 100644 --- a/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts +++ b/arch/arm/boot/dts/aspeed-bmc-asrock-e3c246d4i.dts @@ -15,7 +15,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + bootargs = "console=tty0 console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-bytedance-g220a.dts b/arch/arm/boot/dts/aspeed-bmc-bytedance-g220a.dts index 5ef88c377358..01dace8f5e5f 100644 --- a/arch/arm/boot/dts/aspeed-bmc-bytedance-g220a.dts +++ b/arch/arm/boot/dts/aspeed-bmc-bytedance-g220a.dts @@ -55,7 +55,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts index 2fb8b147f489..90a3f485c67a 100644 --- a/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts @@ -280,7 +280,7 @@ chosen { stdout-path = &uart1; - bootargs = "console=ttyS1,9600n8 root=/dev/ram rw earlyprintk"; + bootargs = "console=ttyS1,9600n8 root=/dev/ram rw earlycon"; }; ast-adc-hwmon { diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts index 7b4b2b126ad8..b6b16356f571 100644 --- a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts +++ b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts @@ -37,7 +37,7 @@ }; chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts index 3295c8c7c05c..d26a9e16ff7c 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts @@ -202,6 +202,35 @@ linux,code = <12>; }; }; + + leds { + compatible = "gpio-leds"; + + /* RTC battery fault LED at the back */ + led-rtc-battery { + gpios = <&gpio0 ASPEED_GPIO(H, 0) GPIO_ACTIVE_LOW>; + }; + + /* BMC Card fault LED at the back */ + led-bmc { + gpios = <&gpio0 ASPEED_GPIO(H, 1) GPIO_ACTIVE_LOW>; + }; + + /* Enclosure Identify LED at the back */ + led-rear-enc-id0 { + gpios = <&gpio0 ASPEED_GPIO(H, 2) GPIO_ACTIVE_LOW>; + }; + + /* Enclosure fault LED at the back */ + led-rear-enc-fault0 { + gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>; + }; + + /* PCIE slot power LED */ + led-pcieslot-power { + gpios = <&gpio0 ASPEED_GPIO(P, 4) GPIO_ACTIVE_LOW>; + }; + }; }; &gpio0 { @@ -214,7 +243,7 @@ /*F0-F7*/ "PIN_HOLE_RESET_IN_N","","", "PIN_HOLE_RESET_OUT_N","","","","", /*G0-G7*/ "","","","","","","","", - /*H0-H7*/ "","","","","","","","", + /*H0-H7*/ "led-rtc-battery","led-bmc","led-rear-enc-id0","led-rear-enc-fault0","","","","", /*I0-I7*/ "","","","","","","","", /*J0-J7*/ "","","","","","","","", /*K0-K7*/ "","","","","","","","", @@ -222,7 +251,7 @@ /*M0-M7*/ "","","","","","","","", /*N0-N7*/ "","","","","","","","", /*O0-O7*/ "","","","","","","","", - /*P0-P7*/ "","","","","","","","", + /*P0-P7*/ "","","","","led-pcieslot-power","","","", /*Q0-Q7*/ "","","","","","","","", /*R0-R7*/ "","","","","","I2C_FLASH_MICRO_N","","", /*S0-S7*/ "","","","","","","","", @@ -353,10 +382,47 @@ &i2c1 { status = "okay"; +}; - pca2: pca9552@61 { +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; + + eeprom@54 { + compatible = "atmel,24c128"; + reg = <0x54>; + }; + + power-supply@68 { + compatible = "ibm,cffps"; + reg = <0x68>; + }; + + power-supply@69 { + compatible = "ibm,cffps"; + reg = <0x69>; + }; + + power-supply@6a { + compatible = "ibm,cffps"; + reg = <0x6a>; + }; + + power-supply@6b { + compatible = "ibm,cffps"; + reg = <0x6b>; + }; +}; + +&i2c4 { + status = "okay"; + + pca2: pca9552@65 { compatible = "nxp,pca9552"; - reg = <0x61>; + reg = <0x65>; #address-cells = <1>; #size-cells = <0>; @@ -424,12 +490,222 @@ reg = <9>; type = ; }; - }; - pca3: pca9552@62 { + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + i2c-mux-idle-disconnect; + + i2c4mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + + pca_cable_card_c01: pca9551@62 { + compatible = "nxp,pca9551"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c01-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c01-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; + }; + + i2c4mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + pca_cable_card_c02: pca9551@60 { + compatible = "nxp,pca9551"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c02-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c02-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; + }; + + i2c4mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + + pca_cable_card_c03: pca9551@61 { + compatible = "nxp,pca9551"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c03-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c03-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; + }; + }; +}; + +&i2c5 { + status = "okay"; + + pca3: pca9552@66 { compatible = "nxp,pca9552"; - reg = <0x62>; + reg = <0x66>; #address-cells = <1>; #size-cells = <0>; @@ -512,87 +788,6 @@ }; -}; - -&i2c2 { - status = "okay"; -}; - -&i2c3 { - status = "okay"; - - eeprom@54 { - compatible = "atmel,24c128"; - reg = <0x54>; - }; - - power-supply@68 { - compatible = "ibm,cffps"; - reg = <0x68>; - }; - - power-supply@69 { - compatible = "ibm,cffps"; - reg = <0x69>; - }; - - power-supply@6a { - compatible = "ibm,cffps"; - reg = <0x6a>; - }; - - power-supply@6b { - compatible = "ibm,cffps"; - reg = <0x6b>; - }; -}; - -&i2c4 { - status = "okay"; - - i2c-switch@70 { - compatible = "nxp,pca9546"; - reg = <0x70>; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - i2c-mux-idle-disconnect; - - i2c4mux0chn0: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - eeprom@52 { - compatible = "atmel,24c64"; - reg = <0x52>; - }; - }; - - i2c4mux0chn1: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; - }; - - i2c4mux0chn2: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - eeprom@51 { - compatible = "atmel,24c64"; - reg = <0x51>; - }; - }; - }; -}; - -&i2c5 { - status = "okay"; - i2c-switch@70 { compatible = "nxp,pca9546"; reg = <0x70>; @@ -609,6 +804,62 @@ compatible = "atmel,24c64"; reg = <0x50>; }; + + pca_cable_card_c04: pca9551@60 { + compatible = "nxp,pca9551"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c04-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c04-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; i2c5mux0chn1: i2c@1 { @@ -619,6 +870,62 @@ compatible = "atmel,24c64"; reg = <0x51>; }; + + pca_cable_card_c05: pca9551@61 { + compatible = "nxp,pca9551"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c05-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c05-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; i2c5mux0chn2: i2c@2 { @@ -629,6 +936,62 @@ compatible = "atmel,24c64"; reg = <0x52>; }; + + pca_cable_card_c06: pca9551@62 { + compatible = "nxp,pca9551"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c06-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c06-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; i2c5mux0chn3: i2c@3 { @@ -639,6 +1002,62 @@ compatible = "atmel,24c64"; reg = <0x53>; }; + + pca_cable_card_c07: pca9551@63 { + compatible = "nxp,pca9551"; + reg = <0x63>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c07-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c07-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; }; }; @@ -659,8 +1078,64 @@ #size-cells = <0>; reg = <0>; eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + pca_cable_card_c08: pca9551@60 { + compatible = "nxp,pca9551"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c08-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c08-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; }; }; @@ -672,6 +1147,62 @@ compatible = "atmel,24c64"; reg = <0x52>; }; + + pca_cable_card_c09: pca9551@62 { + compatible = "nxp,pca9551"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c09-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c09-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; i2c6mux0chn2: i2c@2 { @@ -682,6 +1213,62 @@ compatible = "atmel,24c64"; reg = <0x53>; }; + + pca_cable_card_c10: pca9551@63 { + compatible = "nxp,pca9551"; + reg = <0x63>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c10-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c10-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; }; i2c6mux0chn3: i2c@3 { @@ -692,12 +1279,1013 @@ compatible = "atmel,24c64"; reg = <0x51>; }; + + pca_cable_card_c11: pca9551@61 { + compatible = "nxp,pca9551"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "cablecard-c11-cxp-top"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "cablecard-c11-cxp-bot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + }; + }; + }; + + pca_pcie_slot: pca9552@65 { + compatible = "nxp,pca9552"; + reg = <0x65>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio@0 { + reg = <0>; + type = ; + }; + + led@1 { + label = "pcieslot-c01"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "pcieslot-c02"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "pcieslot-c03"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "pcieslot-c04"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "pcieslot-c05"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "pcieslot-c06"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "pcieslot-c07"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "pcieslot-c08"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "pcieslot-c09"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "pcieslot-c10"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "pcieslot-c11"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@12 { + reg = <12>; + type = ; + }; + + gpio@13 { + reg = <13>; + type = ; + }; + + gpio@14 { + reg = <14>; + type = ; + }; + + gpio@15 { + reg = <15>; + type = ; }; }; }; &i2c7 { status = "okay"; + + pic0_dimm: pca9552@31 { + compatible = "ibm,pca9552"; + reg = <0x31>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "ddimm0"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "ddimm1"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "ddimm2"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "ddimm3"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "ddimm4"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "ddimm5"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "ddimm6"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "ddimm7"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "ddimm8"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "ddimm9"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "ddimm10"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "ddimm11"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "ddimm12"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "ddimm13"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "ddimm14"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "ddimm15"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + pic1_dimm: pca9552@32 { + compatible = "ibm,pca9552"; + reg = <0x32>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "ddimm16"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "ddimm17"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "ddimm18"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "ddimm19"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "ddimm20"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "ddimm21"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "ddimm22"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "ddimm23"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "ddimm24"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "ddimm25"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "ddimm26"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "ddimm27"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "ddimm28"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "ddimm29"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "ddimm30"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "ddimm31"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + pic2_dimm: pca9552@33 { + compatible = "ibm,pca9552"; + reg = <0x33>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "ddimm32"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "ddimm33"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "ddimm34"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "ddimm35"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "ddimm36"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "ddimm37"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "ddimm38"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "ddimm39"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "ddimm40"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "ddimm41"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "ddimm42"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "ddimm43"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "ddimm44"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "ddimm45"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "ddimm46"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "ddimm47"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + pic3_dimm: pca9552@30 { + compatible = "ibm,pca9552"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "ddimm48"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "ddimm49"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "ddimm50"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "ddimm51"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "ddimm52"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "ddimm53"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "ddimm54"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "ddimm55"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "ddimm56"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "ddimm57"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "ddimm58"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "ddimm59"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "ddimm60"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "ddimm61"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "ddimm62"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "ddimm63"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + pic0_vrm_misc: pca9552@34 { + compatible = "ibm,pca9552"; + reg = <0x34>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "planar"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "tpm"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "cpu3-c61"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "cpu0-c14"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "opencapi-connector3"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "opencapi-connector4"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "opencapi-connector5"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + + led@8 { + label = "vrm4"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "vrm5"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "vrm6"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "vrm7"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "vrm12"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "vrm13"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "vrm14"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "vrm15"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + pic1_vrm_misc: pca9552@35 { + compatible = "ibm,pca9552"; + reg = <0x35>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "dasd-backplane"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "power-distribution"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "cpu1-c19"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "cpu2-c56"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "opencapi-connector0"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "opencapi-connector1"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "opencapi-connector2"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + + led@8 { + label = "vrm0"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "vrm1"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "vrm2"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "vrm3"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "vrm8"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "vrm9"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "vrm10"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "vrm11"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; }; &i2c8 { @@ -863,6 +2451,48 @@ compatible = "atmel,24c32"; reg = <0x50>; }; + + pca_oppanel: pca9551@60 { + compatible = "nxp,pca9551"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "front-sys-id0"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "front-check-log0"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "front-enc-fault1"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "front-sys-pwron0"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; }; i2c14mux0chn3: i2c@3 { @@ -901,6 +2531,138 @@ }; }; + pca_fan_nvme: pca9552@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "nvme0"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "nvme1"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "nvme2"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "nvme3"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "nvme4"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "nvme5"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "nvme6"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "nvme7"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "nvme8"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "nvme9"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "fan0"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "fan1"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "fan2"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "fan3"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + gpio@14 { + reg = <14>; + type = ; + }; + + gpio@15 { + reg = <15>; + type = ; + }; + }; + pca0: pca9552@61 { compatible = "nxp,pca9552"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts index f7fd3b3c90d0..342546a3c0f5 100644 --- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts +++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier-4u.dts @@ -19,33 +19,3 @@ reg = <0x6b>; }; }; - -&fan0 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; - -&fan1 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; - -&fan2 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; - -&fan3 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; - -&fan4 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; - -&fan5 { - tach-pulses = <4>; - /delete-property/ maxim,fan-dual-tach; -}; diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts index 07593897fc9a..1752f3250e44 100644 --- a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts +++ b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts index 80c92e065a10..5a98a19f445e 100644 --- a/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts +++ b/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "earlyprintk"; + bootargs = "earlycon"; }; memory { diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts index 6e9baf3bba53..d5b7d28cda88 100644 --- a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts +++ b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "earlyprintk"; + bootargs = "earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts index c29e5f4d86ad..8f543cca7c21 100644 --- a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts +++ b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts @@ -27,7 +27,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + bootargs = "console=tty0 console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts index 084c455ad4cb..bcc1820f5c07 100644 --- a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts +++ b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts @@ -27,7 +27,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=tty0 console=ttyS4,115200 earlyprintk"; + bootargs = "console=tty0 console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts b/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts index 73319917cb74..3ef8358ff764 100644 --- a/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts +++ b/arch/arm/boot/dts/aspeed-bmc-microsoft-olympus.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@40000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts b/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts index 42b37a204241..c0847636f20b 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts index 15c1f0ac81dc..a52a289cee85 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts @@ -57,7 +57,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mowgli.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mowgli.dts index 8503152faaf0..7d38d121ec6d 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-mowgli.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-mowgli.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts b/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts index 91dced7e7849..3d4bdad27c2d 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts index eb4e93a57ff4..cd660c1ff3f5 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@40000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts index fd2e014dae75..084f54866f38 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts @@ -9,7 +9,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts index d56b5ed09b37..4816486c0c9e 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts index c1478d2db602..e863ec088970 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts @@ -13,7 +13,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200n8"; + bootargs = "console=ttyS4,115200n8 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts index 01074b6e3e03..328ef472c479 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@40000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts index 85d58a63ae90..230f3584bcab 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts @@ -10,7 +10,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts index 4bcc82046362..7ae4ea0d2931 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts @@ -17,7 +17,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts b/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts index 03c161493ffc..61bc74b423cf 100644 --- a/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts +++ b/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts @@ -14,7 +14,7 @@ }; chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts b/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts index a68ff0675c28..9605e53f5bbf 100644 --- a/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts +++ b/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts @@ -28,7 +28,7 @@ chosen { stdout-path = &uart5; - bootargs = "console=ttyS4,115200 earlyprintk"; + bootargs = "console=ttyS4,115200 earlycon"; }; memory@40000000 { diff --git a/arch/arm/boot/dts/aspeed-bmc-supermicro-x11spi.dts b/arch/arm/boot/dts/aspeed-bmc-supermicro-x11spi.dts index bc16ad2b5c80..50f3c6a5c0c8 100644 --- a/arch/arm/boot/dts/aspeed-bmc-supermicro-x11spi.dts +++ b/arch/arm/boot/dts/aspeed-bmc-supermicro-x11spi.dts @@ -11,7 +11,7 @@ chosen { stdout-path = &uart5; - bootargs = "earlyprintk"; + bootargs = "earlycon"; }; memory@80000000 { diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index d733c1f161c1..329eaeef66fb 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -264,6 +264,7 @@ reg-io-width = <4>; clocks = <&syscon ASPEED_CLK_GATE_D1CLK>; resets = <&syscon ASPEED_RESET_CRT1>; + syscon = <&syscon>; status = "disabled"; interrupts = <0x19>; }; diff --git a/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi b/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi index 7028e21bdd98..7e90d713f5e5 100644 --- a/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi +++ b/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi @@ -862,11 +862,21 @@ groups = "SGPM1"; }; + pinctrl_sgpm2_default: sgpm2_default { + function = "SGPM2"; + groups = "SGPM2"; + }; + pinctrl_sgps1_default: sgps1_default { function = "SGPS1"; groups = "SGPS1"; }; + pinctrl_sgps2_default: sgps2_default { + function = "SGPS2"; + groups = "SGPS2"; + }; + pinctrl_sioonctrl_default: sioonctrl_default { function = "SIOONCTRL"; groups = "SIOONCTRL"; diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 0025c88f660c..8ecb7861ce10 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -460,7 +460,7 @@ status = "disabled"; }; - nand: nand@18046000 { + nand_controller: nand-controller@18046000 { compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1"; reg = <0x18046000 0x600>, <0xf8105408 0x600>, <0x18046f00 0x20>; diff --git a/arch/arm/boot/dts/bcm-hr2.dtsi b/arch/arm/boot/dts/bcm-hr2.dtsi index e8df458aad39..84cda16f68a2 100644 --- a/arch/arm/boot/dts/bcm-hr2.dtsi +++ b/arch/arm/boot/dts/bcm-hr2.dtsi @@ -179,7 +179,7 @@ status = "disabled"; }; - nand: nand@26000 { + nand_controller: nand-controller@26000 { compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1"; reg = <0x26000 0x600>, <0x11b408 0x600>, diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi index b4d2cc70afb1..748df7955ae6 100644 --- a/arch/arm/boot/dts/bcm-nsp.dtsi +++ b/arch/arm/boot/dts/bcm-nsp.dtsi @@ -269,7 +269,7 @@ dma-coherent; }; - nand: nand@26000 { + nand_controller: nand-controller@26000 { compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1"; reg = <0x026000 0x600>, <0x11b408 0x600>, diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 3b4ab947492a..f24bdd0870a5 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -1,11 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /dts-v1/; #include "bcm2711.dtsi" -#include "bcm2835-rpi.dtsi" +#include "bcm2711-rpi.dtsi" #include "bcm283x-rpi-usb-peripheral.dtsi" -#include - / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; model = "Raspberry Pi 4 Model B"; @@ -15,25 +13,12 @@ stdout-path = "serial1:115200n8"; }; - /* Will be filled by the bootloader */ - memory@0 { - device_type = "memory"; - reg = <0 0 0>; - }; - - aliases { - emmc2bus = &emmc2bus; - ethernet0 = &genet; - pcie0 = &pcie0; - blconfig = &blconfig; - }; - leds { - act { + led-act { gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; default-state = "keep"; @@ -79,31 +64,15 @@ status = "okay"; }; -&firmware { - firmware_clocks: clocks { - compatible = "raspberrypi,firmware-clocks"; - #clock-cells = <1>; - }; - - expgpio: gpio { - compatible = "raspberrypi,firmware-gpio"; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "BT_ON", - "WL_ON", - "PWR_LED_OFF", - "GLOBAL_RESET", - "VDD_SD_IO_SEL", - "CAM_GPIO", - "SD_PWR_ON", - ""; - status = "okay"; - }; - - reset: reset { - compatible = "raspberrypi,firmware-reset"; - #reset-cells = <1>; - }; +&expgpio { + gpio-line-names = "BT_ON", + "WL_ON", + "PWR_LED_OFF", + "GLOBAL_RESET", + "VDD_SD_IO_SEL", + "CAM_GPIO", + "SD_PWR_ON", + ""; }; &gpio { @@ -180,23 +149,13 @@ }; &hdmi0 { - clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; - clock-names = "hdmi", "bvb", "audio", "cec"; - wifi-2.4ghz-coexistence; status = "okay"; }; &hdmi1 { - clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; - clock-names = "hdmi", "bvb", "audio", "cec"; - wifi-2.4ghz-coexistence; status = "okay"; }; -&hvs { - clocks = <&firmware_clocks 4>; -}; - &pixelvalve0 { status = "okay"; }; @@ -219,22 +178,6 @@ status = "okay"; }; -&rmem { - /* - * RPi4's co-processor will copy the board's bootloader configuration - * into memory for the OS to consume. It'll also update this node with - * its placement information. - */ - blconfig: nvram@0 { - compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x0 0x0 0x0>; - no-map; - status = "disabled"; - }; -}; - /* SDHCI is used to control the SDIO for wireless */ &sdhci { #address-cells = <1>; @@ -309,10 +252,6 @@ status = "okay"; }; -&vchiq { - interrupts = ; -}; - &vc4 { status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm2711-rpi-400.dts b/arch/arm/boot/dts/bcm2711-rpi-400.dts new file mode 100644 index 000000000000..f4d2fc20397c --- /dev/null +++ b/arch/arm/boot/dts/bcm2711-rpi-400.dts @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#include "bcm2711-rpi-4-b.dts" + +/ { + compatible = "raspberrypi,400", "brcm,bcm2711"; + model = "Raspberry Pi 400"; + + chosen { + /* 8250 auxiliary UART instead of pl011 */ + stdout-path = "serial1:115200n8"; + }; + + leds { + /delete-node/ led-act; + + led-pwr { + gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&expgpio 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&expgpio { + gpio-line-names = "BT_ON", + "WL_ON", + "", + "GLOBAL_RESET", + "VDD_SD_IO_SEL", + "CAM_GPIO", + "SD_PWR_ON", + "SD_OC_N"; +}; + +&genet_mdio { + clock-frequency = <1950000>; +}; + +&pm { + /delete-property/ system-power-controller; +}; diff --git a/arch/arm/boot/dts/bcm2711-rpi.dtsi b/arch/arm/boot/dts/bcm2711-rpi.dtsi new file mode 100644 index 000000000000..ca266c5d9f9b --- /dev/null +++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "bcm2835-rpi.dtsi" + +#include + +/ { + /* Will be filled by the bootloader */ + memory@0 { + device_type = "memory"; + reg = <0 0 0>; + }; + + aliases { + emmc2bus = &emmc2bus; + ethernet0 = &genet; + pcie0 = &pcie0; + blconfig = &blconfig; + }; +}; + +&firmware { + firmware_clocks: clocks { + compatible = "raspberrypi,firmware-clocks"; + #clock-cells = <1>; + }; + + expgpio: gpio { + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; +}; + +&hdmi0 { + clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; + clock-names = "hdmi", "bvb", "audio", "cec"; + wifi-2.4ghz-coexistence; +}; + +&hdmi1 { + clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; + clock-names = "hdmi", "bvb", "audio", "cec"; + wifi-2.4ghz-coexistence; +}; + +&hvs { + clocks = <&firmware_clocks 4>; +}; + +&rmem { + /* + * RPi4's co-processor will copy the board's bootloader configuration + * into memory for the OS to consume. It'll also update this node with + * its placement information. + */ + blconfig: nvram@0 { + compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x0 0x0>; + no-map; + status = "disabled"; + }; +}; + +&vchiq { + interrupts = ; +}; diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index 720beec54d61..b8a4096192aa 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -413,7 +413,7 @@ ranges = <0x0 0x7e000000 0x0 0xfe000000 0x01800000>; dma-ranges = <0x0 0xc0000000 0x0 0x00000000 0x40000000>; - emmc2: emmc2@7e340000 { + emmc2: mmc@7e340000 { compatible = "brcm,bcm2711-emmc2"; reg = <0x0 0x7e340000 0x100>; interrupts = ; @@ -1087,5 +1087,6 @@ }; &vec { + compatible = "brcm,bcm2711-vec"; interrupts = ; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts index 6c8ce39833bf..40b9405f1a8e 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts @@ -14,11 +14,11 @@ }; leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts index 17fdd48346ff..11edb581dbaf 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts @@ -14,7 +14,7 @@ }; leds { - act { + led-act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts index b0355c229cdc..1b435c64bd9c 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts @@ -15,11 +15,11 @@ }; leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts index 33b3b5c02521..a23c25c00eea 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts @@ -15,7 +15,7 @@ }; leds { - act { + led-act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts index 2b69957e0113..1b63d6b19750 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts @@ -15,7 +15,7 @@ }; leds { - act { + led-act { gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi index 58059c2ce129..e4e6b6abbfc1 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi-cm1.dtsi @@ -5,7 +5,7 @@ / { leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts index f65448c01e31..33b2b77aa47d 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w.dts @@ -23,7 +23,7 @@ }; leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero.dts b/arch/arm/boot/dts/bcm2835-rpi-zero.dts index 6dd93c6f4966..6f9b3a908f28 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts @@ -18,7 +18,7 @@ }; leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi index d94357b21f7e..87ddcad76083 100644 --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi @@ -4,7 +4,7 @@ leds { compatible = "gpio-leds"; - act { + led-act { label = "ACT"; default-state = "keep"; linux,default-trigger = "heartbeat"; diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index 0455a680394a..d8af8eeac7b6 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -15,11 +15,11 @@ }; leds { - act { + led-act { gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts index 28be0332c1c8..77099a7871b0 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts @@ -19,11 +19,11 @@ }; leds { - act { + led-act { gpios = <&gpio 29 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; default-state = "keep"; diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts index 37343148643d..61010266ca9a 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts @@ -20,11 +20,11 @@ }; leds { - act { + led-act { gpios = <&gpio 29 GPIO_ACTIVE_HIGH>; }; - pwr { + led-pwr { label = "PWR"; gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; default-state = "keep"; diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts index 054ecaa355c9..dd4a48604097 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts @@ -20,7 +20,7 @@ }; leds { - act { + led-act { gpios = <&expgpio 2 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi index 925cb37c22f0..828a20561b96 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi +++ b/arch/arm/boot/dts/bcm2837-rpi-cm3.dtsi @@ -14,7 +14,7 @@ * Since there is no upstream GPIO driver yet, * remove the incomplete node. */ - /delete-node/ act; + /delete-node/ led-act; }; reg_3v3: fixed-regulator { diff --git a/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi b/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi index 20322de2f8bf..e2fd9610e125 100644 --- a/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi +++ b/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 &usb { dr_mode = "otg"; - g-rx-fifo-size = <558>; + g-rx-fifo-size = <256>; g-np-tx-fifo-size = <32>; /* * According to dwc2 the sum of all device EP diff --git a/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi index 1409d1b559c1..0ff0e9e25327 100644 --- a/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi +++ b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 &usb { dr_mode = "peripheral"; - g-rx-fifo-size = <558>; + g-rx-fifo-size = <256>; g-np-tx-fifo-size = <32>; g-tx-fifo-size = <256 256 512 512 512 768 768>; }; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index b83a864e2e8b..0f3be55201a5 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -420,7 +420,7 @@ status = "disabled"; }; - sdhci: sdhci@7e300000 { + sdhci: mmc@7e300000 { compatible = "brcm,bcm2835-sdhci"; reg = <0x7e300000 0x100>; interrupts = <2 30>; diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts index 8636600385fd..c81944cd6d0b 100644 --- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts +++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts @@ -24,8 +24,8 @@ reg = <0x00000000 0x08000000>; }; - nand: nand@18028000 { - nandcs@0 { + nand_controller: nand-controller@18028000 { + nand@0 { partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts index e635a15041dd..a6e2aeb28675 100644 --- a/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts +++ b/arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts @@ -25,8 +25,8 @@ <0x88000000 0x08000000>; }; - nand: nand@18028000 { - nandcs@0 { + nand_controller: nand-controller@18028000 { + nand@0 { partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/bcm47094.dtsi b/arch/arm/boot/dts/bcm47094.dtsi index 2a8f7312d1be..6282363313e1 100644 --- a/arch/arm/boot/dts/bcm47094.dtsi +++ b/arch/arm/boot/dts/bcm47094.dtsi @@ -11,7 +11,7 @@ &pinctrl { compatible = "brcm,bcm4709-pinmux"; - pinmux_mdio: mdio { + pinmux_mdio: mdio-pins { groups = "mdio_grp"; function = "mdio"; }; diff --git a/arch/arm/boot/dts/bcm5301x-nand-cs0.dtsi b/arch/arm/boot/dts/bcm5301x-nand-cs0.dtsi index 925a7c9ce5b7..be9a00ff752d 100644 --- a/arch/arm/boot/dts/bcm5301x-nand-cs0.dtsi +++ b/arch/arm/boot/dts/bcm5301x-nand-cs0.dtsi @@ -6,8 +6,8 @@ */ / { - nand@18028000 { - nandcs: nandcs@0 { + nand-controller@18028000 { + nandcs: nand@0 { compatible = "brcm,nandcs"; reg = <0>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi index 7db72a2f1020..f92089290ccd 100644 --- a/arch/arm/boot/dts/bcm5301x.dtsi +++ b/arch/arm/boot/dts/bcm5301x.dtsi @@ -458,18 +458,18 @@ function = "spi"; }; - pinmux_i2c: i2c { + pinmux_i2c: i2c-pins { groups = "i2c_grp"; function = "i2c"; }; - pinmux_pwm: pwm { + pinmux_pwm: pwm-pins { groups = "pwm0_grp", "pwm1_grp", "pwm2_grp", "pwm3_grp"; function = "pwm"; }; - pinmux_uart1: uart1 { + pinmux_uart1: uart1-pins { groups = "uart1_grp"; function = "uart1"; }; @@ -501,7 +501,7 @@ reg = <0x18004000 0x14>; }; - nand: nand@18028000 { + nand_controller: nand-controller@18028000 { compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand"; reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 0x20>; reg-names = "nand", "iproc-idm", "iproc-ext"; @@ -520,27 +520,27 @@ <0x1811b408 0x004>, <0x180293a0 0x01c>; reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg"; - interrupts = , + interrupts = , + , + , , , , - , - , - ; - interrupt-names = "spi_lr_fullness_reached", + ; + interrupt-names = "mspi_done", + "mspi_halted", + "spi_lr_fullness_reached", "spi_lr_session_aborted", "spi_lr_impatient", "spi_lr_session_done", - "spi_lr_overhead", - "mspi_done", - "mspi_halted"; + "spi_lr_overread"; clocks = <&iprocmed>; clock-names = "iprocmed"; num-cs = <2>; #address-cells = <1>; #size-cells = <0>; - spi_nor: spi-nor@0 { + spi_nor: flash@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <20000000>; diff --git a/arch/arm/boot/dts/bcm63138.dtsi b/arch/arm/boot/dts/bcm63138.dtsi index 9c0325cf9e22..cca49a2e2d62 100644 --- a/arch/arm/boot/dts/bcm63138.dtsi +++ b/arch/arm/boot/dts/bcm63138.dtsi @@ -203,7 +203,7 @@ status = "disabled"; }; - nand: nand@2000 { + nand_controller: nand-controller@2000 { #address-cells = <1>; #size-cells = <0>; compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.0", "brcm,brcmnand"; diff --git a/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts b/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts index 8313b7cad542..f92d2cf85972 100644 --- a/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts +++ b/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts @@ -14,10 +14,10 @@ }; }; -&nand { +&nand_controller { status = "okay"; - nandcs@1 { + nand@1 { compatible = "brcm,nandcs"; reg = <1>; nand-ecc-step-size = <512>; diff --git a/arch/arm/boot/dts/bcm7445.dtsi b/arch/arm/boot/dts/bcm7445.dtsi index 58f67c9b830b..5ac2042515b8 100644 --- a/arch/arm/boot/dts/bcm7445.dtsi +++ b/arch/arm/boot/dts/bcm7445.dtsi @@ -148,7 +148,7 @@ reg-names = "aon-ctrl", "aon-sram"; }; - nand: nand@3e2800 { + nand_controller: nand-controller@3e2800 { status = "disabled"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts index b2d323f4a5ab..a76c74b44bba 100644 --- a/arch/arm/boot/dts/bcm911360_entphn.dts +++ b/arch/arm/boot/dts/bcm911360_entphn.dts @@ -82,8 +82,8 @@ status = "okay"; }; -&nand { - nandcs@1 { +&nand_controller { + nand@1 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts index 046c59fb4846..de40bd59a5fa 100644 --- a/arch/arm/boot/dts/bcm953012k.dts +++ b/arch/arm/boot/dts/bcm953012k.dts @@ -49,8 +49,8 @@ }; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958300k.dts b/arch/arm/boot/dts/bcm958300k.dts index b4a1392bd5a6..dda3e11b711f 100644 --- a/arch/arm/boot/dts/bcm958300k.dts +++ b/arch/arm/boot/dts/bcm958300k.dts @@ -60,8 +60,8 @@ status = "okay"; }; -&nand { - nandcs@1 { +&nand_controller { + nand@1 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958305k.dts b/arch/arm/boot/dts/bcm958305k.dts index 3378683321d3..ea3c6b88b313 100644 --- a/arch/arm/boot/dts/bcm958305k.dts +++ b/arch/arm/boot/dts/bcm958305k.dts @@ -68,8 +68,8 @@ status = "okay"; }; -&nand { - nandcs@1 { +&nand_controller { + nand@1 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts index 5443fc079e6e..1f73885ec274 100644 --- a/arch/arm/boot/dts/bcm958522er.dts +++ b/arch/arm/boot/dts/bcm958522er.dts @@ -74,8 +74,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts index e1e3c26cef19..b6b9ca8b0972 100644 --- a/arch/arm/boot/dts/bcm958525er.dts +++ b/arch/arm/boot/dts/bcm958525er.dts @@ -74,8 +74,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts index f161ba2e7e5e..ecf426f6ad5d 100644 --- a/arch/arm/boot/dts/bcm958525xmc.dts +++ b/arch/arm/boot/dts/bcm958525xmc.dts @@ -90,8 +90,8 @@ }; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts index 83cb877d63db..8ca18da981ad 100644 --- a/arch/arm/boot/dts/bcm958622hr.dts +++ b/arch/arm/boot/dts/bcm958622hr.dts @@ -78,8 +78,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts index 4e106ce1384a..9747378db531 100644 --- a/arch/arm/boot/dts/bcm958623hr.dts +++ b/arch/arm/boot/dts/bcm958623hr.dts @@ -78,8 +78,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts index cda6cc281e18..0f92b773afb8 100644 --- a/arch/arm/boot/dts/bcm958625hr.dts +++ b/arch/arm/boot/dts/bcm958625hr.dts @@ -89,8 +89,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts index ffbff0014c65..9e984ca0e6df 100644 --- a/arch/arm/boot/dts/bcm958625k.dts +++ b/arch/arm/boot/dts/bcm958625k.dts @@ -68,8 +68,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/bcm963138dvt.dts b/arch/arm/boot/dts/bcm963138dvt.dts index 5b177274f182..df5c8ab90627 100644 --- a/arch/arm/boot/dts/bcm963138dvt.dts +++ b/arch/arm/boot/dts/bcm963138dvt.dts @@ -31,10 +31,10 @@ status = "okay"; }; -&nand { +&nand_controller { status = "okay"; - nandcs@0 { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-ecc-strength = <4>; diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts index 3fd39c479a3c..5475dab8181d 100644 --- a/arch/arm/boot/dts/bcm988312hr.dts +++ b/arch/arm/boot/dts/bcm988312hr.dts @@ -74,8 +74,8 @@ status = "okay"; }; -&nand { - nandcs@0 { +&nand_controller { + nand@0 { compatible = "brcm,nandcs"; reg = <0>; nand-on-flash-bbt; diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index 7cf31b6e48b7..c3942b4e82ad 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -574,8 +574,7 @@ status = "disabled"; }; ehrpwm0: pwm@300000 { - compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x300000 0x2000>; clocks = <&psc1 17>, <&ehrpwm_tbclk>; @@ -584,8 +583,7 @@ status = "disabled"; }; ehrpwm1: pwm@302000 { - compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", - "ti,am33xx-ehrpwm"; + compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm"; #pwm-cells = <3>; reg = <0x302000 0x2000>; clocks = <&psc1 17>, <&ehrpwm_tbclk>; @@ -593,9 +591,8 @@ power-domains = <&psc1 17>; status = "disabled"; }; - ecap0: ecap@306000 { - compatible = "ti,da850-ecap", "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap0: pwm@306000 { + compatible = "ti,da850-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x306000 0x80>; clocks = <&psc1 20>; @@ -603,9 +600,8 @@ power-domains = <&psc1 20>; status = "disabled"; }; - ecap1: ecap@307000 { - compatible = "ti,da850-ecap", "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap1: pwm@307000 { + compatible = "ti,da850-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x307000 0x80>; clocks = <&psc1 20>; @@ -613,9 +609,8 @@ power-domains = <&psc1 20>; status = "disabled"; }; - ecap2: ecap@308000 { - compatible = "ti,da850-ecap", "ti,am3352-ecap", - "ti,am33xx-ecap"; + ecap2: pwm@308000 { + compatible = "ti,da850-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; reg = <0x308000 0x80>; clocks = <&psc1 20>; diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index 3551a64963f8..a9e7274806f4 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -314,8 +314,6 @@ #address-cells = <1>; #size-cells = <0>; interrupts = <70>; - dmas = <&edma 58 0 &edma 59 0>; - dma-names = "tx", "rx"; }; i2c2: i2c@4802a000 { @@ -325,8 +323,6 @@ #address-cells = <1>; #size-cells = <0>; interrupts = <71>; - dmas = <&edma 60 0 &edma 61 0>; - dma-names = "tx", "rx"; }; intc: interrupt-controller@48200000 { @@ -351,7 +347,7 @@ #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <12>; - mbox_dsp: mbox_dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <3 0 0>; ti,mbox-rx = <0 0 0>; }; diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index 38530dbb89a0..87deb6a76eff 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -319,7 +319,7 @@ }; pcf_lcd: gpio@20 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x20>; gpio-controller; #gpio-cells = <2>; @@ -330,7 +330,7 @@ }; pcf_gpio_21: gpio@21 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x21>; lines-initial-states = <0x1408>; gpio-controller; @@ -362,11 +362,11 @@ clock-frequency = <400000>; pcf_hdmi: gpio@26 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x26>; gpio-controller; #gpio-cells = <2>; - p1 { + hdmi-audio-hog { /* vin6_sel_s0: high: VIN6, low: audio */ gpio-hog; gpios = <1 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/dra7-ipu-dsp-common.dtsi b/arch/arm/boot/dts/dra7-ipu-dsp-common.dtsi index a25749a1c365..a5bdc6431d8d 100644 --- a/arch/arm/boot/dts/dra7-ipu-dsp-common.dtsi +++ b/arch/arm/boot/dts/dra7-ipu-dsp-common.dtsi @@ -5,17 +5,17 @@ &mailbox5 { status = "okay"; - mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { + mbox_ipu1_ipc3x: mbox-ipu1-ipc3x { status = "okay"; }; - mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { + mbox_dsp1_ipc3x: mbox-dsp1-ipc3x { status = "okay"; }; }; &mailbox6 { status = "okay"; - mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { + mbox_ipu2_ipc3x: mbox-ipu2-ipc3x { status = "okay"; }; }; diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index 149144cdff35..956a26d52a4c 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -1159,7 +1159,7 @@ ranges = <0x0 0x20000 0x1000>; uart3: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -1343,7 +1343,7 @@ }; }; - target-module@55000 { /* 0x48055000, ap 13 0e.0 */ + gpio2_target: target-module@55000 { /* 0x48055000, ap 13 0e.0 */ compatible = "ti,sysc-omap2", "ti,sysc"; reg = <0x55000 0x4>, <0x55010 0x4>, @@ -1376,7 +1376,7 @@ }; }; - target-module@57000 { /* 0x48057000, ap 15 06.0 */ + gpio3_target: target-module@57000 { /* 0x48057000, ap 15 06.0 */ compatible = "ti,sysc-omap2", "ti,sysc"; reg = <0x57000 0x4>, <0x57010 0x4>, @@ -1562,7 +1562,7 @@ ranges = <0x0 0x66000 0x1000>; uart5: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -1594,7 +1594,7 @@ ranges = <0x0 0x68000 0x1000>; uart6: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -1626,7 +1626,7 @@ ranges = <0x0 0x6a000 0x1000>; uart1: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; clock-frequency = <48000000>; @@ -1658,7 +1658,7 @@ ranges = <0x0 0x6c000 0x1000>; uart2: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -1690,7 +1690,7 @@ ranges = <0x0 0x6e000 0x1000>; uart4: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -2424,7 +2424,7 @@ ranges = <0x0 0x20000 0x1000>; uart7: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -2454,7 +2454,7 @@ ranges = <0x0 0x22000 0x1000>; uart8: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -2484,7 +2484,7 @@ ranges = <0x0 0x24000 0x1000>; uart9: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; @@ -2561,7 +2561,7 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap0: ecap@100 { + ecap0: pwm@100 { compatible = "ti,dra746-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; @@ -2607,7 +2607,7 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap1: ecap@100 { + ecap1: pwm@100 { compatible = "ti,dra746-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; @@ -2653,7 +2653,7 @@ status = "disabled"; ranges = <0 0 0x1000>; - ecap2: ecap@100 { + ecap2: pwm@100 { compatible = "ti,dra746-ecap", "ti,am3352-ecap"; #pwm-cells = <3>; @@ -4129,28 +4129,6 @@ }; }; - usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */ - compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x140000 0x4>, - <0x140010 0x4>; - reg-names = "rev", "sysc"; - ti,sysc-mask = ; - ti,sysc-midle = , - , - , - ; - ti,sysc-sidle = , - , - , - ; - /* Domains (P, C): l3init_pwrdm, l3init_clkdm */ - clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; - clock-names = "fck"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x140000 0x20000>; - }; - target-module@170000 { /* 0x48970000, ap 21 0a.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; reg = <0x170010 0x4>; @@ -4530,7 +4508,7 @@ ranges = <0x0 0xb000 0x1000>; uart10: serial@0 { - compatible = "ti,dra742-uart", "ti,omap4-uart"; + compatible = "ti,dra742-uart"; reg = <0x0 0x100>; interrupts = ; clock-frequency = <48000000>; diff --git a/arch/arm/boot/dts/dra71-evm.dts b/arch/arm/boot/dts/dra71-evm.dts index 6d2cca6b4488..a64364443031 100644 --- a/arch/arm/boot/dts/dra71-evm.dts +++ b/arch/arm/boot/dts/dra71-evm.dts @@ -187,7 +187,7 @@ }; &pcf_hdmi { - p0 { + hdmi-i2c-disable-hog { /* * PM_OEn to High: Disable routing I2C3 to PM_I2C * With this PM_SEL(p3) should not matter diff --git a/arch/arm/boot/dts/dra71x.dtsi b/arch/arm/boot/dts/dra71x.dtsi index cad0e4a2bd8d..9c270d8f75d5 100644 --- a/arch/arm/boot/dts/dra71x.dtsi +++ b/arch/arm/boot/dts/dra71x.dtsi @@ -11,7 +11,3 @@ &rtctarget { status = "disabled"; }; - -&usb4_tm { - status = "disabled"; -}; diff --git a/arch/arm/boot/dts/dra72-evm-common.dtsi b/arch/arm/boot/dts/dra72-evm-common.dtsi index b65b2dd094d0..f12825268188 100644 --- a/arch/arm/boot/dts/dra72-evm-common.dtsi +++ b/arch/arm/boot/dts/dra72-evm-common.dtsi @@ -226,7 +226,7 @@ }; pcf_gpio_21: gpio@21 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x21>; lines-initial-states = <0x1408>; gpio-controller; @@ -256,7 +256,7 @@ clock-frequency = <400000>; pcf_hdmi: pcf8575@26 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x26>; gpio-controller; #gpio-cells = <2>; @@ -268,7 +268,7 @@ */ lines-initial-states = <0x0f2b>; - p1 { + hdmi-audio-hog { /* vin6_sel_s0: high: VIN6, low: audio */ gpio-hog; gpios = <1 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi index d403acc754b6..90617261373c 100644 --- a/arch/arm/boot/dts/dra72x.dtsi +++ b/arch/arm/boot/dts/dra72x.dtsi @@ -77,12 +77,12 @@ }; &mailbox5 { - mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { + mbox_ipu1_ipc3x: mbox-ipu1-ipc3x { ti,mbox-tx = <6 2 2>; ti,mbox-rx = <4 2 2>; status = "disabled"; }; - mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { + mbox_dsp1_ipc3x: mbox-dsp1-ipc3x { ti,mbox-tx = <5 2 2>; ti,mbox-rx = <1 2 2>; status = "disabled"; @@ -90,7 +90,7 @@ }; &mailbox6 { - mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { + mbox_ipu2_ipc3x: mbox-ipu2-ipc3x { ti,mbox-tx = <6 2 2>; ti,mbox-rx = <4 2 2>; status = "disabled"; @@ -108,7 +108,3 @@ &pcie2_rc { compatible = "ti,dra726-pcie-rc", "ti,dra7-pcie"; }; - -&usb4_tm { - status = "disabled"; -}; diff --git a/arch/arm/boot/dts/dra74-ipu-dsp-common.dtsi b/arch/arm/boot/dts/dra74-ipu-dsp-common.dtsi index b1147a4b77f9..3256631510c5 100644 --- a/arch/arm/boot/dts/dra74-ipu-dsp-common.dtsi +++ b/arch/arm/boot/dts/dra74-ipu-dsp-common.dtsi @@ -6,7 +6,7 @@ #include "dra7-ipu-dsp-common.dtsi" &mailbox6 { - mbox_dsp2_ipc3x: mbox_dsp2_ipc3x { + mbox_dsp2_ipc3x: mbox-dsp2-ipc3x { status = "okay"; }; }; diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi index e1850d6c841a..cfb39dde4930 100644 --- a/arch/arm/boot/dts/dra74x.dtsi +++ b/arch/arm/boot/dts/dra74x.dtsi @@ -49,49 +49,6 @@ reg = <0x41500000 0x100>; }; - target-module@48940000 { - compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x48940000 0x4>, - <0x48940010 0x4>; - reg-names = "rev", "sysc"; - ti,sysc-mask = ; - ti,sysc-midle = , - , - , - ; - ti,sysc-sidle = , - , - , - ; - clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; - clock-names = "fck"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x48940000 0x20000>; - - omap_dwc3_4: omap_dwc3_4@0 { - compatible = "ti,dwc3"; - reg = <0 0x10000>; - interrupts = ; - #address-cells = <1>; - #size-cells = <1>; - utmi-mode = <2>; - ranges; - status = "disabled"; - usb4: usb@10000 { - compatible = "snps,dwc3"; - reg = <0x10000 0x17000>; - interrupts = , - , - ; - interrupt-names = "peripheral", - "host", - "otg"; - maximum-speed = "high-speed"; - dr_mode = "otg"; - }; - }; - }; target-module@41501000 { compatible = "ti,sysc-omap2", "ti,sysc"; @@ -188,12 +145,12 @@ }; &mailbox5 { - mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { + mbox_ipu1_ipc3x: mbox-ipu1-ipc3x { ti,mbox-tx = <6 2 2>; ti,mbox-rx = <4 2 2>; status = "disabled"; }; - mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { + mbox_dsp1_ipc3x: mbox-dsp1-ipc3x { ti,mbox-tx = <5 2 2>; ti,mbox-rx = <1 2 2>; status = "disabled"; @@ -201,12 +158,12 @@ }; &mailbox6 { - mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { + mbox_ipu2_ipc3x: mbox-ipu2-ipc3x { ti,mbox-tx = <6 2 2>; ti,mbox-rx = <4 2 2>; status = "disabled"; }; - mbox_dsp2_ipc3x: mbox_dsp2_ipc3x { + mbox_dsp2_ipc3x: mbox-dsp2-ipc3x { ti,mbox-tx = <5 2 2>; ti,mbox-rx = <1 2 2>; status = "disabled"; @@ -224,3 +181,52 @@ &pcie2_rc { compatible = "ti,dra746-pcie-rc", "ti,dra7-pcie"; }; + +&l4_per3 { + segment@0 { + usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */ + compatible = "ti,sysc-omap4", "ti,sysc"; + reg = <0x140000 0x4>, + <0x140010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-mask = ; + ti,sysc-midle = , + , + , + ; + ti,sysc-sidle = , + , + , + ; + /* Domains (P, C): l3init_pwrdm, l3init_clkdm */ + clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x140000 0x20000>; + + omap_dwc3_4: omap_dwc3_4@0 { + compatible = "ti,dwc3"; + reg = <0 0x10000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <1>; + utmi-mode = <2>; + ranges; + status = "disabled"; + usb4: usb@10000 { + compatible = "snps,dwc3"; + reg = <0x10000 0x17000>; + interrupts = , + , + ; + interrupt-names = "peripheral", + "host", + "otg"; + maximum-speed = "high-speed"; + dr_mode = "otg"; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/dra76-evm.dts b/arch/arm/boot/dts/dra76-evm.dts index 9bd01ae40b1d..e2b7fcb061cf 100644 --- a/arch/arm/boot/dts/dra76-evm.dts +++ b/arch/arm/boot/dts/dra76-evm.dts @@ -158,12 +158,6 @@ regulator-max-microvolt = <1800000>; }; - clk_ov5640_fixed: clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; - hdmi0: connector { compatible = "hdmi-connector"; label = "hdmi"; @@ -355,7 +349,7 @@ }; pcf_lcd: pcf8757@20 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x20>; gpio-controller; #gpio-cells = <2>; @@ -366,7 +360,7 @@ }; pcf_gpio_21: pcf8757@21 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x21>; gpio-controller; #gpio-cells = <2>; @@ -377,11 +371,11 @@ }; pcf_hdmi: pcf8575@26 { - compatible = "ti,pcf8575", "nxp,pcf8575"; + compatible = "nxp,pcf8575"; reg = <0x26>; gpio-controller; #gpio-cells = <2>; - p1 { + hdmi-audio-hog { /* vin6_sel_s0: high: VIN6, low: audio */ gpio-hog; gpios = <1 GPIO_ACTIVE_HIGH>; @@ -406,27 +400,6 @@ }; }; -&i2c5 { - status = "okay"; - clock-frequency = <400000>; - - ov5640@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - - clocks = <&clk_ov5640_fixed>; - clock-names = "xclk"; - - port { - csi2_cam0: endpoint { - remote-endpoint = <&csi2_phy0>; - clock-lanes = <0>; - data-lanes = <1 2>; - }; - }; - }; -}; - &cpu0 { vdd-supply = <&buck10_reg>; }; @@ -573,14 +546,6 @@ }; }; -&csi2_0 { - csi2_phy0: endpoint { - remote-endpoint = <&csi2_cam0>; - clock-lanes = <0>; - data-lanes = <1 2>; - }; -}; - &ipu2 { status = "okay"; memory-region = <&ipu2_cma_pool>; diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts index c52b9cf4f74c..f6ba5e426040 100644 --- a/arch/arm/boot/dts/exynos3250-rinato.dts +++ b/arch/arm/boot/dts/exynos3250-rinato.dts @@ -653,7 +653,7 @@ mmc-pwrseq = <&wlan_pwrseq>; brcmf: wifi@1 { - compatible = "brcm,bcm4334-fmac"; + compatible = "brcm,bcm4334-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpx1>; diff --git a/arch/arm/boot/dts/exynos4210-i9100.dts b/arch/arm/boot/dts/exynos4210-i9100.dts index 525ff3d2fac3..55922176807e 100644 --- a/arch/arm/boot/dts/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/exynos4210-i9100.dts @@ -314,7 +314,8 @@ }; &fimc_1 { - status = "okay"; + /* Back camera not implemented */ + status = "disabled"; assigned-clocks = <&clock CLK_MOUT_FIMC1>, <&clock CLK_SCLK_FIMC1>; assigned-clock-parents = <&clock CLK_SCLK_MPLL>; @@ -330,7 +331,8 @@ }; &fimc_3 { - status = "okay"; + /* Back camera not implemented */ + status = "disabled"; assigned-clocks = <&clock CLK_MOUT_FIMC3>, <&clock CLK_SCLK_FIMC3>; assigned-clock-parents = <&clock CLK_SCLK_MPLL>; @@ -806,7 +808,7 @@ pinctrl-0 = <&sd3_clk>, <&sd3_cmd>, <&sd3_bus4>; brcmf: wifi@1 { - compatible = "brcm,bcm4330-fmac"; + compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpx2>; diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index d2406c9146b8..3eb8df319246 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -521,7 +521,7 @@ pinctrl-0 = <&sd3_clk>, <&sd3_cmd>, <&sd3_bus4>; brcmf: wifi@1 { - compatible = "brcm,bcm4330-fmac"; + compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpx2>; diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts index dd44ad2c6ad6..f052853244a4 100644 --- a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -614,7 +614,7 @@ pinctrl-0 = <&sd3_clk>, <&sd3_cmd>, <&sd3_bus4>; brcmf: wifi@1 { - compatible = "brcm,bcm4330-fmac"; + compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpx2>; interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi index 4583d342af39..b3726d4d7d93 100644 --- a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi +++ b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi @@ -163,6 +163,7 @@ <1025000>, <950000>, <918750>, <900000>, <875000>, <831250>; + wakeup-source; regulators { ldo1_reg: LDO1 { diff --git a/arch/arm/boot/dts/exynos4412-midas.dtsi b/arch/arm/boot/dts/exynos4412-midas.dtsi index fc77c1bfd844..968c7943653e 100644 --- a/arch/arm/boot/dts/exynos4412-midas.dtsi +++ b/arch/arm/boot/dts/exynos4412-midas.dtsi @@ -668,6 +668,7 @@ interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&max77686_irq>; pinctrl-names = "default"; + wakeup-source; reg = <0x09>; #clock-cells = <1>; diff --git a/arch/arm/boot/dts/exynos4412-n710x.dts b/arch/arm/boot/dts/exynos4412-n710x.dts index c49dbb7847b8..2c792142605c 100644 --- a/arch/arm/boot/dts/exynos4412-n710x.dts +++ b/arch/arm/boot/dts/exynos4412-n710x.dts @@ -50,8 +50,8 @@ reg = <0x48>; interrupt-parent = <&gpm2>; interrupts = <3 IRQ_TYPE_EDGE_FALLING>; - x-size = <720>; - y-size = <1280>; + touchscreen-size-x = <720>; + touchscreen-size-y = <1280>; avdd-supply = <&ldo23_reg>; vdd-supply = <&ldo24_reg>; }; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 5bd05866d7a3..5b1d4591b35c 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -282,6 +282,7 @@ interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&max77686_irq>; + wakeup-source; reg = <0x09>; #clock-cells = <1>; diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts index e1f6de53e20e..5479ef09f9f3 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -144,6 +144,7 @@ <1200000>, <1200000>, <1200000>, <1200000>, <1200000>, <1200000>; + wakeup-source; s5m8767_osc: clocks { compatible = "samsung,s5m8767-clk"; diff --git a/arch/arm/boot/dts/exynos4412-p4note.dtsi b/arch/arm/boot/dts/exynos4412-p4note.dtsi index 9e750890edb8..22c3086e0076 100644 --- a/arch/arm/boot/dts/exynos4412-p4note.dtsi +++ b/arch/arm/boot/dts/exynos4412-p4note.dtsi @@ -325,6 +325,7 @@ interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&max77686_irq>; pinctrl-names = "default"; + wakeup-source; reg = <0x09>; #clock-cells = <1>; diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index a161f6237c7f..a771542e28b8 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -218,6 +218,7 @@ interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&s5m8767_irq>; + wakeup-source; vinb1-supply = <&main_dc_reg>; vinb2-supply = <&main_dc_reg>; diff --git a/arch/arm/boot/dts/exynos5410-odroidxu.dts b/arch/arm/boot/dts/exynos5410-odroidxu.dts index 949c0721cdb4..884fef55836c 100644 --- a/arch/arm/boot/dts/exynos5410-odroidxu.dts +++ b/arch/arm/boot/dts/exynos5410-odroidxu.dts @@ -190,6 +190,7 @@ pinctrl-names = "default"; pinctrl-0 = <&max77802_irq>, <&pmic_dvs_1>, <&pmic_dvs_2>, <&pmic_dvs_3>; + wakeup-source; #clock-cells = <1>; inl1-supply = <&buck5_reg>; diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index 1aad4859c5f1..dfc7f14f5772 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -352,6 +352,7 @@ interrupts = <2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&s2mps11_irq>; + wakeup-source; s2mps11_osc: clocks { compatible = "samsung,s2mps11-clk"; diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index d506da9fa661..a4f0e3ffedbd 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -132,6 +132,7 @@ pmic@66 { compatible = "samsung,s2mps11-pmic"; reg = <0x66>; + wakeup-source; s2mps11_osc: clocks { compatible = "samsung,s2mps11-clk"; diff --git a/arch/arm/boot/dts/exynos5422-odroid-core.dtsi b/arch/arm/boot/dts/exynos5422-odroid-core.dtsi index 6d690b1db099..e7958dbecfd2 100644 --- a/arch/arm/boot/dts/exynos5422-odroid-core.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroid-core.dtsi @@ -512,6 +512,7 @@ interrupts = <4 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&s2mps11_irq>; + wakeup-source; s2mps11_osc: clocks { compatible = "samsung,s2mps11-clk"; diff --git a/arch/arm/boot/dts/exynos5422-odroidhc1.dts b/arch/arm/boot/dts/exynos5422-odroidhc1.dts index 20c222b33f98..d91f7fa2cf80 100644 --- a/arch/arm/boot/dts/exynos5422-odroidhc1.dts +++ b/arch/arm/boot/dts/exynos5422-odroidhc1.dts @@ -22,7 +22,7 @@ label = "blue:heartbeat"; pwms = <&pwm 2 2000000 0>; pwm-names = "pwm2"; - max_brightness = <255>; + max-brightness = <255>; linux,default-trigger = "heartbeat"; }; }; diff --git a/arch/arm/boot/dts/exynos5422-odroidxu4.dts b/arch/arm/boot/dts/exynos5422-odroidxu4.dts index ede782257643..1c24f9b35973 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu4.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu4.dts @@ -24,7 +24,7 @@ label = "blue:heartbeat"; pwms = <&pwm 2 2000000 0>; pwm-names = "pwm2"; - max_brightness = <255>; + max-brightness = <255>; linux,default-trigger = "heartbeat"; }; }; diff --git a/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi b/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi index 2fc3e86dc5f7..982752e1df24 100644 --- a/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi +++ b/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi @@ -22,7 +22,7 @@ * Green LED is much brighter than the others * so limit its max brightness */ - max_brightness = <127>; + max-brightness = <127>; linux,default-trigger = "mmc0"; }; @@ -30,7 +30,7 @@ label = "blue:heartbeat"; pwms = <&pwm 2 2000000 0>; pwm-names = "pwm2"; - max_brightness = <255>; + max-brightness = <255>; linux,default-trigger = "heartbeat"; }; }; diff --git a/arch/arm/boot/dts/gemini-dlink-dir-685.dts b/arch/arm/boot/dts/gemini-dlink-dir-685.dts index cc39289e99dd..c79a2a02dd6b 100644 --- a/arch/arm/boot/dts/gemini-dlink-dir-685.dts +++ b/arch/arm/boot/dts/gemini-dlink-dir-685.dts @@ -61,9 +61,9 @@ #size-cells = <0>; /* Collides with IDE pins, that's cool (we do not use them) */ - gpio-sck = <&gpio1 5 GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio1 8 GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio1 7 GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; cs-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; num-chipselects = <1>; @@ -169,7 +169,7 @@ * The touchpad input is connected to a GPIO bit-banged * I2C bus. */ - gpio-i2c { + i2c { compatible = "i2c-gpio"; /* Collides with ICE */ sda-gpios = <&gpio0 5 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; @@ -492,8 +492,7 @@ display-controller@6a000000 { status = "okay"; - port@0 { - reg = <0>; + port { display_out: endpoint { remote-endpoint = <&panel_in>; }; diff --git a/arch/arm/boot/dts/gemini-dlink-dns-313.dts b/arch/arm/boot/dts/gemini-dlink-dns-313.dts index c6f3d90e3e90..eba1c94ed7f7 100644 --- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts +++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts @@ -82,7 +82,7 @@ /* Global Mixed-Mode Technology G751 mounted on GPIO I2C */ - gpio-i2c { + i2c { compatible = "i2c-gpio"; sda-gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; scl-gpios = <&gpio0 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; @@ -140,7 +140,7 @@ }; }; - mdio0: ethernet-phy { + mdio0: mdio { compatible = "virtual,mdio-gpio"; /* Uses MDC and MDIO */ gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ diff --git a/arch/arm/boot/dts/gemini-nas4220b.dts b/arch/arm/boot/dts/gemini-nas4220b.dts index 43c45f7e1e0a..13112a8a5dd8 100644 --- a/arch/arm/boot/dts/gemini-nas4220b.dts +++ b/arch/arm/boot/dts/gemini-nas4220b.dts @@ -62,7 +62,7 @@ }; }; - mdio0: ethernet-phy { + mdio0: mdio { compatible = "virtual,mdio-gpio"; gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ diff --git a/arch/arm/boot/dts/gemini-rut1xx.dts b/arch/arm/boot/dts/gemini-rut1xx.dts index 9611ddf06792..0ebda4efd9d0 100644 --- a/arch/arm/boot/dts/gemini-rut1xx.dts +++ b/arch/arm/boot/dts/gemini-rut1xx.dts @@ -56,7 +56,7 @@ }; }; - mdio0: ethernet-phy { + mdio0: mdio { compatible = "virtual,mdio-gpio"; gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ @@ -125,18 +125,6 @@ }; }; - ethernet@60000000 { - status = "okay"; - - ethernet-port@0 { - phy-mode = "rgmii"; - phy-handle = <&phy0>; - }; - ethernet-port@1 { - /* Not used in this platform */ - }; - }; - usb@68000000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/gemini-sl93512r.dts b/arch/arm/boot/dts/gemini-sl93512r.dts index a0916d3c1059..c78e55fd2562 100644 --- a/arch/arm/boot/dts/gemini-sl93512r.dts +++ b/arch/arm/boot/dts/gemini-sl93512r.dts @@ -87,9 +87,9 @@ #address-cells = <1>; #size-cells = <0>; /* Check pin collisions */ - gpio-sck = <&gpio1 28 GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio1 30 GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio1 29 GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>; cs-gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>; num-chipselects = <1>; diff --git a/arch/arm/boot/dts/gemini-sq201.dts b/arch/arm/boot/dts/gemini-sq201.dts index 0c6e6d35bfaa..1b64cc80b55a 100644 --- a/arch/arm/boot/dts/gemini-sq201.dts +++ b/arch/arm/boot/dts/gemini-sq201.dts @@ -72,9 +72,9 @@ #address-cells = <1>; #size-cells = <0>; /* Check pin collisions */ - gpio-sck = <&gpio1 28 GPIO_ACTIVE_HIGH>; - gpio-miso = <&gpio1 30 GPIO_ACTIVE_HIGH>; - gpio-mosi = <&gpio1 29 GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + miso-gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>; cs-gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>; num-chipselects = <1>; diff --git a/arch/arm/boot/dts/gemini-wbd111.dts b/arch/arm/boot/dts/gemini-wbd111.dts index 3a2761dd460f..5602ba8f30f2 100644 --- a/arch/arm/boot/dts/gemini-wbd111.dts +++ b/arch/arm/boot/dts/gemini-wbd111.dts @@ -68,7 +68,7 @@ }; }; - mdio0: ethernet-phy { + mdio0: mdio { compatible = "virtual,mdio-gpio"; gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ diff --git a/arch/arm/boot/dts/gemini-wbd222.dts b/arch/arm/boot/dts/gemini-wbd222.dts index 52b4dbc0c072..a4a260c36d75 100644 --- a/arch/arm/boot/dts/gemini-wbd222.dts +++ b/arch/arm/boot/dts/gemini-wbd222.dts @@ -67,7 +67,7 @@ }; }; - mdio0: ethernet-phy { + mdio0: mdio { compatible = "virtual,mdio-gpio"; gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ diff --git a/arch/arm/boot/dts/gemini.dtsi b/arch/arm/boot/dts/gemini.dtsi index 065ed10a79fa..cc053af3c347 100644 --- a/arch/arm/boot/dts/gemini.dtsi +++ b/arch/arm/boot/dts/gemini.dtsi @@ -191,7 +191,7 @@ }; rtc@45000000 { - compatible = "cortina,gemini-rtc"; + compatible = "cortina,gemini-rtc", "faraday,ftrtc010"; reg = <0x45000000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; resets = <&syscon GEMINI_RESET_RTC>; @@ -286,6 +286,7 @@ clock-names = "PCLK", "PCICLK"; pinctrl-names = "default"; pinctrl-0 = <&pci_default_pins>; + device_type = "pci"; #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; @@ -356,6 +357,14 @@ }; }; + crypto: crypto@62000000 { + compatible = "cortina,sl3516-crypto"; + reg = <0x62000000 0x10000>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + resets = <&syscon GEMINI_RESET_SECURITY>; + clocks = <&syscon GEMINI_CLK_GATE_SECURITY>; + }; + ide@63000000 { compatible = "cortina,gemini-pata", "faraday,ftide010"; reg = <0x63000000 0x1000>; @@ -409,8 +418,6 @@ clock-names = "PCLK", "TVE"; pinctrl-names = "default"; pinctrl-0 = <&tvc_default_pins>; - #address-cells = <1>; - #size-cells = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index 905900bf3e82..cf48ec14af43 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Hisilicon Ltd. Hi3620 SoC + * HiSilicon Ltd. Hi3620 SoC * - * Copyright (C) 2012-2013 Hisilicon Ltd. + * Copyright (C) 2012-2013 HiSilicon Ltd. * Copyright (C) 2012-2013 Linaro Ltd. * * Author: Haojian Zhuang diff --git a/arch/arm/boot/dts/hip01-ca9x2.dts b/arch/arm/boot/dts/hip01-ca9x2.dts index 031476304d94..f3faf247cd61 100644 --- a/arch/arm/boot/dts/hip01-ca9x2.dts +++ b/arch/arm/boot/dts/hip01-ca9x2.dts @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Hisilicon Ltd. HiP01 SoC + * HiSilicon Ltd. HiP01 SoC * - * Copyright (C) 2014 Hisilicon Ltd. + * Copyright (C) 2014 HiSilicon Ltd. * Copyright (C) 2014 Huawei Ltd. * * Author: Wang Long diff --git a/arch/arm/boot/dts/hip01.dtsi b/arch/arm/boot/dts/hip01.dtsi index 2a7963605390..e17f36bd9006 100644 --- a/arch/arm/boot/dts/hip01.dtsi +++ b/arch/arm/boot/dts/hip01.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Hisilicon Ltd. HiP01 SoC + * HiSilicon Ltd. HiP01 SoC * - * Copyright (c) 2014 Hisilicon Ltd. + * Copyright (c) 2014 HiSilicon Ltd. * Copyright (c) 2014 Huawei Ltd. * * Author: Wang Long diff --git a/arch/arm/boot/dts/hip04.dtsi b/arch/arm/boot/dts/hip04.dtsi index bccf5ba3d855..2424cc545c9c 100644 --- a/arch/arm/boot/dts/hip04.dtsi +++ b/arch/arm/boot/dts/hip04.dtsi @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Hisilicon Ltd. HiP04 SoC + * HiSilicon Ltd. HiP04 SoC * - * Copyright (C) 2013-2014 Hisilicon Ltd. + * Copyright (C) 2013-2014 HiSilicon Ltd. * Copyright (C) 2013-2014 Linaro Ltd. * * Author: Haojian Zhuang diff --git a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts index 22b122d3f514..7758c19038f0 100644 --- a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts +++ b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014 Linaro Ltd. - * Copyright (c) 2013-2014 Hisilicon Limited. + * Copyright (c) 2013-2014 HiSilicon Limited. */ /dts-v1/; diff --git a/arch/arm/boot/dts/hisi-x5hd2.dtsi b/arch/arm/boot/dts/hisi-x5hd2.dtsi index 97211385dc89..dc991ba2a9fb 100644 --- a/arch/arm/boot/dts/hisi-x5hd2.dtsi +++ b/arch/arm/boot/dts/hisi-x5hd2.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014 Linaro Ltd. - * Copyright (c) 2013-2014 Hisilicon Limited. + * Copyright (c) 2013-2014 HiSilicon Limited. */ #include diff --git a/arch/arm/boot/dts/imx25-pinfunc.h b/arch/arm/boot/dts/imx25-pinfunc.h index f984b702efc5..908caf810351 100644 --- a/arch/arm/boot/dts/imx25-pinfunc.h +++ b/arch/arm/boot/dts/imx25-pinfunc.h @@ -563,15 +563,15 @@ #define MX25_PAD_DE_B__DE_B 0x1f0 0x3ec 0x000 0x00 0x000 #define MX25_PAD_DE_B__GPIO_2_20 0x1f0 0x3ec 0x000 0x05 0x000 -#define MX25_PAD_GPIO_A__GPIO_A 0x1f4 0x3f0 0x000 0x00 0x000 +#define MX25_PAD_GPIO_A__GPIO_1_0 0x1f4 0x3f0 0x000 0x00 0x000 #define MX25_PAD_GPIO_A__CAN1_TX 0x1f4 0x3f0 0x000 0x06 0x000 #define MX25_PAD_GPIO_A__USBOTG_PWR 0x1f4 0x3f0 0x000 0x02 0x000 -#define MX25_PAD_GPIO_B__GPIO_B 0x1f8 0x3f4 0x000 0x00 0x000 +#define MX25_PAD_GPIO_B__GPIO_1_1 0x1f8 0x3f4 0x000 0x00 0x000 #define MX25_PAD_GPIO_B__USBOTG_OC 0x1f8 0x3f4 0x57c 0x02 0x001 #define MX25_PAD_GPIO_B__CAN1_RX 0x1f8 0x3f4 0x480 0x06 0x001 -#define MX25_PAD_GPIO_C__GPIO_C 0x1fc 0x3f8 0x000 0x00 0x000 +#define MX25_PAD_GPIO_C__GPIO_1_2 0x1fc 0x3f8 0x000 0x00 0x000 #define MX25_PAD_GPIO_C__PWM4_PWMO 0x1fc 0x3f8 0x000 0x01 0x000 #define MX25_PAD_GPIO_C__I2C2_SCL 0x1fc 0x3f8 0x51c 0x02 0x001 #define MX25_PAD_GPIO_C__KPP_COL4 0x1fc 0x3f8 0x52c 0x03 0x001 @@ -580,18 +580,18 @@ #define MX25_PAD_GPIO_C__CAN2_TX 0x1fc 0x3f8 0x000 0x06 0x000 #define MX25_PAD_GPIO_C__CSPI2_SS2 0x1fc 0x3f8 0x000 0x07 0x000 -#define MX25_PAD_GPIO_D__GPIO_D 0x200 0x3fc 0x000 0x00 0x000 +#define MX25_PAD_GPIO_D__GPIO_1_3 0x200 0x3fc 0x000 0x00 0x000 #define MX25_PAD_GPIO_D__I2C2_SDA 0x200 0x3fc 0x520 0x02 0x001 #define MX25_PAD_GPIO_D__CAN2_RX 0x200 0x3fc 0x484 0x06 0x001 #define MX25_PAD_GPIO_D__CSPI3_SS2 0x200 0x3fc 0x4c4 0x07 0x001 -#define MX25_PAD_GPIO_E__GPIO_E 0x204 0x400 0x000 0x00 0x000 +#define MX25_PAD_GPIO_E__GPIO_1_4 0x204 0x400 0x000 0x00 0x000 #define MX25_PAD_GPIO_E__I2C3_CLK 0x204 0x400 0x524 0x01 0x002 #define MX25_PAD_GPIO_E__LD16 0x204 0x400 0x000 0x02 0x000 #define MX25_PAD_GPIO_E__AUD7_TXD 0x204 0x400 0x000 0x04 0x000 #define MX25_PAD_GPIO_E__UART4_RXD 0x204 0x400 0x570 0x06 0x002 -#define MX25_PAD_GPIO_F__GPIO_F 0x208 0x404 0x000 0x00 0x000 +#define MX25_PAD_GPIO_F__GPIO_1_5 0x208 0x404 0x000 0x00 0x000 #define MX25_PAD_GPIO_F__LD17 0x208 0x404 0x000 0x02 0x000 #define MX25_PAD_GPIO_F__AUD7_TXC 0x208 0x404 0x000 0x04 0x000 #define MX25_PAD_GPIO_F__UART4_TXD 0x208 0x404 0x000 0x06 0x000 diff --git a/arch/arm/boot/dts/imx28-lwe.dtsi b/arch/arm/boot/dts/imx28-lwe.dtsi new file mode 100644 index 000000000000..bb971e660db8 --- /dev/null +++ b/arch/arm/boot/dts/imx28-lwe.dtsi @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2021 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de + */ + +/dts-v1/; +#include "imx28.dtsi" + +/ { + aliases { + spi2 = &ssp3; + }; + + chosen { + bootargs = "root=/dev/mmcblk0p2 rootfstype=ext4 ro rootwait console=ttyAMA0,115200 panic=1"; + }; + + memory@40000000 { + reg = <0x40000000 0x08000000>; + }; + + reg_3v3: regulator-reg-3v3 { + compatible = "regulator-fixed"; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_usb_5v: regulator-reg-usb-5v { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_fec_3v3: regulator-reg-fec-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fec-phy"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&duart { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; +}; + +&saif0 { + pinctrl-names = "default"; + pinctrl-0 = <&saif0_pins_a>; + #sound-dai-cells = <0>; + assigned-clocks = <&clks 53>; + assigned-clock-rates = <12000000>; + status = "okay"; +}; + +&saif1 { + pinctrl-names = "default"; + pinctrl-0 = <&saif1_pins_a>; + fsl,saif-master = <&saif0>; + #sound-dai-cells = <0>; + status = "okay"; +}; + +&spi3_pins_a { + fsl,pinmux-ids = < + MX28_PAD_AUART2_RX__SSP3_D4 + MX28_PAD_AUART2_TX__SSP3_D5 + MX28_PAD_SSP3_SCK__SSP3_SCK + MX28_PAD_SSP3_MOSI__SSP3_CMD + MX28_PAD_SSP3_MISO__SSP3_D0 + MX28_PAD_SSP3_SS0__SSP3_D3 + MX28_PAD_AUART2_TX__GPIO_3_9 + >; +}; + +&ssp0 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a>; + bus-width = <8>; + vmmc-supply = <®_3v3>; + non-removable; + status = "okay"; +}; + +&ssp2 { + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_a>; + status = "okay"; +}; + +&ssp3 { + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi3_pins_a>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <40000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0 0x80000>; + read-only; + }; + + partition@80000 { + label = "env0"; + reg = <0x80000 0x10000>; + }; + + partition@90000 { + label = "env1"; + reg = <0x90000 0x10000>; + }; + + partition@100000 { + label = "kernel"; + reg = <0x100000 0x400000>; + }; + + partition@500000 { + label = "swupdate"; + reg = <0x500000 0x800000>; + }; + }; + }; +}; + +&usb0 { + vbus-supply = <®_usb_5v>; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_pins_b>, <&usb0_id_pins_a>; + dr_mode = "host"; + status = "okay"; +}; + +&usbphy0 { + status = "okay"; +}; + +&usb1 { + vbus-supply = <®_usb_5v>; + pinctrl-names = "default"; + pinctrl-0 = <&usb1_pins_b>; + dr_mode = "host"; + status = "okay"; +}; + +&usbphy1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx28-xea.dts b/arch/arm/boot/dts/imx28-xea.dts new file mode 100644 index 000000000000..a400c108f66a --- /dev/null +++ b/arch/arm/boot/dts/imx28-xea.dts @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2021 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de + */ + +/dts-v1/; +#include "imx28-lwe.dtsi" + +/ { + compatible = "lwn,imx28-xea", "fsl,imx28"; +}; + +&can0 { + pinctrl-names = "default"; + pinctrl-0 = <&can1_pins_a>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_b>; + status = "okay"; +}; + +&pinctrl { + pinctrl-names = "default"; + pinctrl-0 = <&hog_pins_a &hog_pins_tiva>; + + hog_pins_a: hog@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D00__GPIO_0_0 + MX28_PAD_GPMI_D02__GPIO_0_2 + MX28_PAD_GPMI_D05__GPIO_0_5 + MX28_PAD_GPMI_CE1N__GPIO_0_17 + MX28_PAD_GPMI_RDY0__GPIO_0_20 + MX28_PAD_GPMI_RDY1__GPIO_0_21 + MX28_PAD_GPMI_RDY2__GPIO_0_22 + MX28_PAD_GPMI_RDN__GPIO_0_24 + MX28_PAD_GPMI_CLE__GPIO_0_27 + MX28_PAD_LCD_VSYNC__GPIO_1_28 + MX28_PAD_SSP1_SCK__GPIO_2_12 + MX28_PAD_SSP1_CMD__GPIO_2_13 + MX28_PAD_SSP2_SS1__GPIO_2_20 + MX28_PAD_SSP2_SS2__GPIO_2_21 + MX28_PAD_LCD_D00__GPIO_1_0 + MX28_PAD_LCD_D01__GPIO_1_1 + MX28_PAD_LCD_D02__GPIO_1_2 + MX28_PAD_LCD_D03__GPIO_1_3 + MX28_PAD_LCD_D04__GPIO_1_4 + MX28_PAD_LCD_D05__GPIO_1_5 + MX28_PAD_LCD_D06__GPIO_1_6 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + hog_pins_tiva: hog@1 { + reg = <1>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_RDY3__GPIO_0_23 + MX28_PAD_GPMI_WRN__GPIO_0_25 + >; + fsl,voltage = ; + fsl,pull-up = ; + }; + + hog_pins_coding: hog@2 { + reg = <2>; + fsl,pinmux-ids = < + MX28_PAD_GPMI_D01__GPIO_0_1 + MX28_PAD_GPMI_D03__GPIO_0_3 + MX28_PAD_GPMI_D04__GPIO_0_4 + MX28_PAD_GPMI_D06__GPIO_0_6 + MX28_PAD_GPMI_D07__GPIO_0_7 + >; + fsl,voltage = ; + fsl,pull-up = ; + }; +}; + +®_fec_3v3 { + gpio = <&gpio0 0 0>; +}; + +®_usb_5v { + gpio = <&gpio0 2 0>; +}; + +&spi2_pins_a { + fsl,pinmux-ids = < + MX28_PAD_SSP2_SCK__SSP2_SCK + MX28_PAD_SSP2_MOSI__SSP2_CMD + MX28_PAD_SSP2_MISO__SSP2_D0 + MX28_PAD_SSP2_SS0__GPIO_2_19 + >; +}; diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi index 16addb3a2a1b..7d4970417dce 100644 --- a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi +++ b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi @@ -206,7 +206,7 @@ pinctrl-0 = <&pinctrl_weim>; status = "okay"; - lan9221: lan9221@5,0 { + lan9221: ethernet@5,0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lan9221>; compatible = "smsc,lan9221", "smsc,lan9115"; diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts index 9a2e1fde7128..6208fbb2e741 100644 --- a/arch/arm/boot/dts/imx53-ard.dts +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -24,7 +24,7 @@ reg = <0xf4000000 0x3ff0000>; ranges; - lan9220@f4000000 { + ethernet@f4000000 { compatible = "smsc,lan9220", "smsc,lan9115"; reg = <0xf4000000 0x2000000>; phy-mode = "mii"; diff --git a/arch/arm/boot/dts/imx6dl-b105pv2.dts b/arch/arm/boot/dts/imx6dl-b105pv2.dts new file mode 100644 index 000000000000..411aa72d344b --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b105pv2.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B105Pv2 +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +/dts-v1/; +#include "imx6dl-b1x5pv2.dtsi" + +/ { + model = "General Electric B105Pv2"; + compatible = "ge,imx6dl-b105pv2", "congatec,qmx6", "fsl,imx6dl"; + + panel { + compatible = "auo,g101evn010"; + }; +}; + +&i2c3 { + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 =<&pinctrl_q7_gpio0>; + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1280>; + touchscreen-size-y = <800>; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-b105v2.dts b/arch/arm/boot/dts/imx6dl-b105v2.dts new file mode 100644 index 000000000000..d011127c635b --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b105v2.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B105v2 +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +/dts-v1/; +#include "imx6dl-b1x5v2.dtsi" + +/ { + model = "General Electric B105v2"; + compatible = "ge,imx6dl-b105v2", "congatec,qmx6", "fsl,imx6dl"; + + panel { + compatible = "auo,g101evn010"; + }; +}; + +&i2c3 { + touchscreen@41 { + compatible = "ilitek,ili251x"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 =<&pinctrl_q7_gpio0>; + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1280>; + touchscreen-size-y = <800>; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-b125pv2.dts b/arch/arm/boot/dts/imx6dl-b125pv2.dts new file mode 100644 index 000000000000..ca840fa84052 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b125pv2.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B125Pv2 +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +/dts-v1/; +#include "imx6dl-b1x5pv2.dtsi" + +/ { + model = "General Electric B125Pv2"; + compatible = "ge,imx6dl-b125pv2", "congatec,qmx6", "fsl,imx6dl"; + + panel { + compatible = "auo,g121ean01"; + }; +}; + +&i2c3 { + touchscreen@2a { + compatible = "eeti,exc80h60"; + reg = <0x2a>; + pinctrl-names = "default"; + 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/imx6dl-b125v2.dts b/arch/arm/boot/dts/imx6dl-b125v2.dts new file mode 100644 index 000000000000..81e5a9cb8900 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b125v2.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B125v2 +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +/dts-v1/; +#include "imx6dl-b1x5v2.dtsi" + +/ { + model = "General Electric B125v2"; + compatible = "ge,imx6dl-b125v2", "congatec,qmx6", "fsl,imx6dl"; + + panel { + compatible = "auo,g121ean01"; + }; +}; + +&i2c3 { + touchscreen@2a { + compatible = "eeti,exc80h60"; + reg = <0x2a>; + pinctrl-names = "default"; + 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/imx6dl-b155v2.dts b/arch/arm/boot/dts/imx6dl-b155v2.dts new file mode 100644 index 000000000000..c861937b30f6 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b155v2.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B155v2 +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +/dts-v1/; +#include "imx6dl-b1x5v2.dtsi" + +/ { + model = "General Electric B155v2"; + compatible = "ge,imx6dl-b155v2", "congatec,qmx6", "fsl,imx6dl"; + + panel { + compatible = "auo,g156xtn01"; + }; +}; + +&i2c3 { + touchscreen@2a { + compatible = "eeti,exc80h84"; + reg = <0x2a>; + pinctrl-names = "default"; + pinctrl-0 =<&pinctrl_q7_gpio0>; + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + touchscreen-inverted-x; + touchscreen-inverted-y; + reset-gpios = <&tca6424a 21 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-b1x5pv2.dtsi b/arch/arm/boot/dts/imx6dl-b1x5pv2.dtsi new file mode 100644 index 000000000000..ec5b66453156 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b1x5pv2.dtsi @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B1x5Pv2 +// patient monitor series +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +#include +#include "imx6dl-qmx6.dtsi" + +/ { + chosen { + stdout-path = &uart3; + }; + + /* Do not allow frequencies above 800MHz */ + cpus { + cpu@0 { + operating-points = < + /* kHz uV */ + 792000 1175000 + 396000 1150000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC-PU uV */ + 792000 1175000 + 396000 1175000 + >; + }; + + cpu@1 { + operating-points = < + /* kHz uV */ + 792000 1175000 + 396000 1150000 + >; + fsl,soc-operating-points = < + /* ARM kHz SOC-PU uV */ + 792000 1175000 + 396000 1175000 + >; + }; + }; + + reg_syspwr: regulator-12v { + compatible = "regulator-fixed"; + regulator-name = "SYS_PWR"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + reg_5v_pmc: regulator-5v-pmc { + compatible = "regulator-fixed"; + regulator-name = "5V PMC"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_syspwr>; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_syspwr>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_syspwr>; + }; + + reg_5v0_audio: regulator-5v0-audio { + compatible = "regulator-fixed"; + regulator-name = "5V0_AUDIO"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_5v>; + gpio = <&tca6424a 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + /* + * This must be always-on for da7212, which has some not + * properly documented dependencies for it's speaker supply + * pin. The issue manifests as speaker volume being very low. + */ + regulator-always-on; + }; + + + reg_3v3_audio: regulator-3v3-audio { + compatible = "regulator-fixed"; + regulator-name = "3V3_AUDIO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_3v3>; + pinctrl-0 = <&pinctrl_q7_hda_reset>; + pinctrl-names = "default"; + gpio = <&gpio6 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_2v5_audio: regulator-2v5-audio { + compatible = "regulator-fixed"; + regulator-name = "2V5_AUDIO"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + vin-supply = <®_3v3_audio>; + + }; + + reg_wlan: regulator-wlan { + compatible = "regulator-fixed"; + regulator-name = "WLAN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_3v3>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_sdio_power>; + gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>; + enable-active-high; + startup-delay-us = <70000>; + }; + + reg_bl: regulator-backlight { + compatible = "regulator-fixed"; + regulator-name = "LED_VCC"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + vin-supply = <®_syspwr>; + pinctrl-0 = <&pinctrl_q7_lcd_power>; + pinctrl-names = "default"; + gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_lcd: regulator-lcd { + compatible = "regulator-fixed"; + regulator-name = "LCD_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_5v>; + }; + + usb_power: regulator-usb-power { + compatible = "regulator-fixed"; + regulator-name = "USB POWER"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_5v>; + }; + + charger: battery-charger { + compatible = "gpio-charger"; /* ti,bq24172 */ + charger-type = "mains"; + gpios = <&tca6424a 3 GPIO_ACTIVE_LOW>; + charge-current-limit-gpios = <&tca6424a 11 GPIO_ACTIVE_HIGH>, + <&tca6424a 12 GPIO_ACTIVE_HIGH>; + charge-current-limit-mapping = <1300000 0x0>, + <700000 0x1>, + <0 0x2>; + charge-status-gpios = <&tca6424a 6 GPIO_ACTIVE_HIGH>; + }; + + poweroff { + compatible = "gpio-poweroff"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_spi_cs1>; + gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + }; + + power-button-key { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_sleep_button>; + + power-button { + label = "power button"; + gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + rotary-encoder-key { + compatible = "gpio-keys"; + + rotary-encoder-press { + label = "rotary-encoder press"; + gpios = <&tca6424a 0 GPIO_ACTIVE_HIGH>; + linux,code = ; + linux,can-disable; + }; + }; + + rotary-encoder { + compatible = "rotary-encoder"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_gpio2 &pinctrl_q7_gpio4>; + gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio1 0 GPIO_ACTIVE_LOW>; + rotary-encoder,relative-axis; + rotary-encoder,steps-per-period = <2>; + wakeup-source; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_gpio1 &pinctrl_q7_gpio3 &pinctrl_q7_gpio5>; + + alarm1 { + label = "alarm:red"; + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + }; + + alarm2 { + label = "alarm:yellow"; + gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>; + }; + + alarm3 { + label = "alarm:blue"; + gpios = <&gpio4 15 GPIO_ACTIVE_HIGH>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_backlight_enable>; + power-supply = <®_bl>; + pwms = <&pwm4 0 5000000 0>; + brightness-levels = <0 255>; + num-interpolated-steps = <255>; + default-brightness-level = <179>; + enable-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + + panel { + backlight = <&backlight>; + power-supply = <®_lcd>; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&dailink_master>; + simple-audio-card,frame-master = <&dailink_master>; + simple-audio-card,widgets = "Speaker", "Ext Spk"; + simple-audio-card,audio-routing = "Ext Spk", "LINE"; + + simple-audio-card,cpu { + sound-dai = <&ssi1>; + }; + + dailink_master: simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; + + clk_ext_audio_codec: clock-codec { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12288000>; + }; +}; + +&audmux { + status = "okay"; +}; + +&fec { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + battery: battery@b { + compatible = "ti,bq20z65", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&tca6424a 5 GPIO_ACTIVE_LOW>; + sbs,i2c-retry-count = <5>; + power-supplies = <&charger>; + }; + + codec: audio-codec@1a { + compatible = "dlg,da7212"; + reg = <0x1a>; + #sound-dai-cells = <0>; + VDDA-supply = <®_2v5_audio>; + VDDSP-supply = <®_5v0_audio>; + VDDMIC-supply = <®_3v3_audio>; + VDDIO-supply = <®_3v3_audio>; + clocks = <&clk_ext_audio_codec>; + clock-names = "mclk"; + }; +}; + +&i2c5 { + tca6424a: gpio-controller@22 { + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3v3>; + interrupt-parent = <&gpio7>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_gpio6>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-line-names = "GPIO_ROTOR#", "ACM_IO_INT", "TMP_SENSOR_IRQ", "AC_IN", + "TF_S", "BATT_T", "LED_INC_CHAR", "ACM1_OCF", + "ACM2_OCF", "ACM_IO_RST", "USB1_POWER_EN", "EGPIO_CC_CTL0", + "EGPIO_CC_CTL1", "12V_OEMNBP_EN", "CP2105_RST", "", + "SPEAKER_PA_EN", "ARM7_UPI_RESET", "ARM7_PWR_RST", "NURSE_CALL", + "MARKER_EN", "EGPIO_TOUCH_RST", "PRESSURE_INT1", "PRESSURE_INT2"; + + }; + + tmp75: temperature-sensor@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + vs-supply = <®_3v3>; + interrupt-parent = <&tca6424a>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + }; +}; + +&ldb { + status = "okay"; + + lvds0: lvds-channel@0 { + status = "okay"; + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + + port@4 { + reg = <4>; + + lvds0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&pwm4 { + status = "okay"; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&usbotg { + vbus-supply = <&usb_power>; + disable-over-current; + dr_mode = "host"; + status = "okay"; + + /* + * TPS2051BDGN fault-gpio is connected to Q7[86] USB_0_1_OC_N. + * On QMX6 this is not connceted to the i.MX6, but to the USB Hub + * from &usbh1. This means, that we cannot easily detect and handle + * over-current events. Fortunately the regulator limits the current + * automatically, so the hardware is still protected. + */ +}; + +&usdhc4 { + /* WiFi module */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4>; + bus-width = <4>; + no-1-8-v; + non-removable; + wakeup-source; + keep-power-in-suspend; + cap-power-off-card; + max-frequency = <25000000>; + vmmc-supply = <®_wlan>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + wlcore: wlcore@2 { + compatible = "ti,wl1837"; + reg = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_q7_gpio7>; + + interrupt-parent = <&gpio4>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + + tcxo-clock-frequency = <26000000>; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-b1x5v2.dtsi b/arch/arm/boot/dts/imx6dl-b1x5v2.dtsi new file mode 100644 index 000000000000..a326a331508e --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-b1x5v2.dtsi @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for General Electric B1x5v2 +// patient monitor series +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora + +#include +#include "imx6dl-b1x5pv2.dtsi" + +/ { + reg_3v3_acm: regulator-3v3-acm { + compatible = "regulator-fixed"; + regulator-name = "3V3 ACM"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + vin-supply = <®_3v3>; + }; +}; + +&i2c1 { + tca6416: gpio-controller@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + reset-gpios = <&tca6424a 9 GPIO_ACTIVE_LOW>; + vcc-supply = <®_3v3_acm>; + gpio-line-names = "ACM1_EN", "ACM1_CL0", "ACM1_CL1", "ACM1_CL2", + "", "ACM2_EN", "ACM2_CL0", "ACM2_CL1", + "ACM2_CL2", "", "", "", + "", "", "", ""; + + /* + * The interrupt pin is connected to &tca6424a pin 1, but the Linux + * TCA6424 driver cannot handle low type interrupts at the moment + * (and support cannot be added without some ugly hacks). Since this + * controller does not have any input type GPIOs, just pretend + * that the interrupt pin is unconnected. + */ + }; +}; + +&i2c5 { + mpl3115a2: pressure-sensor@60 { + compatible = "fsl,mpl3115"; + reg = <0x60>; + vcc-supply = <®_3v3_acm>; + + /* + * The MPL3115 interrupts are connected to pin 22 and 23 + * of &tca6424a, but the binding does not yet support + * interrupts. + */ + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-plym2m.dts b/arch/arm/boot/dts/imx6dl-plym2m.dts index 4d0d3d3386af..60fe5f14666e 100644 --- a/arch/arm/boot/dts/imx6dl-plym2m.dts +++ b/arch/arm/boot/dts/imx6dl-plym2m.dts @@ -138,8 +138,6 @@ interrupts-extended = <&gpio3 20 IRQ_TYPE_EDGE_FALLING>; pendown-gpio = <&gpio3 20 GPIO_ACTIVE_LOW>; - touchscreen-size-x = <800>; - touchscreen-size-y = <480>; touchscreen-inverted-x; touchscreen-inverted-y; touchscreen-max-pressure = <4095>; @@ -147,7 +145,9 @@ ti,vref-delay-usecs = /bits/ 16 <100>; ti,x-plate-ohms = /bits/ 16 <800>; ti,y-plate-ohms = /bits/ 16 <300>; - + ti,debounce-max = /bits/ 16 <3>; + ti,debounce-tol = /bits/ 16 <70>; + ti,debounce-rep = /bits/ 16 <3>; wakeup-source; }; }; diff --git a/arch/arm/boot/dts/imx6dl-prtvt7.dts b/arch/arm/boot/dts/imx6dl-prtvt7.dts index ae6da241f13e..190d26642bc8 100644 --- a/arch/arm/boot/dts/imx6dl-prtvt7.dts +++ b/arch/arm/boot/dts/imx6dl-prtvt7.dts @@ -21,14 +21,11 @@ backlight_lcd: backlight-lcd { compatible = "pwm-backlight"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_backlight>; - pwms = <&pwm1 0 500000>; + pwms = <&pwm1 0 500000 0>; brightness-levels = <0 20 81 248 1000>; default-brightness-level = <20>; num-interpolated-steps = <21>; power-supply = <®_bl_12v0>; - enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>; }; keys { @@ -223,6 +220,24 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi2>; status = "okay"; + + touchscreen@0 { + compatible = "ti,tsc2046"; + reg = <0>; + pinctrl-0 = <&pinctrl_tsc>; + pinctrl-names ="default"; + spi-max-frequency = <100000>; + interrupts-extended = <&gpio3 20 IRQ_TYPE_EDGE_FALLING>; + pendown-gpio = <&gpio3 20 GPIO_ACTIVE_LOW>; + touchscreen-max-pressure = <4095>; + ti,vref-delay-usecs = /bits/ 16 <100>; + ti,x-plate-ohms = /bits/ 16 <800>; + ti,y-plate-ohms = /bits/ 16 <300>; + ti,debounce-max = /bits/ 16 <3>; + ti,debounce-tol = /bits/ 16 <70>; + ti,debounce-rep = /bits/ 16 <3>; + wakeup-source; + }; }; &i2c1 { @@ -261,7 +276,6 @@ }; &pwm1 { - #pwm-cells = <2>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm1>; status = "okay"; @@ -276,8 +290,6 @@ }; &ssi1 { - #sound-dai-cells = <0>; - fsl,mode = "ac97-slave"; status = "okay"; }; @@ -285,10 +297,6 @@ status = "disabled"; }; -&vpu { - status = "disabled"; -}; - &iomuxc { pinctrl_audmux: audmuxgrp { fsl,pins = < @@ -300,12 +308,6 @@ >; }; - pinctrl_backlight: backlightgrp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x1b0b0 - >; - }; - pinctrl_can1phy: can1phy { fsl,pins = < /* CAN1_SR */ diff --git a/arch/arm/boot/dts/imx6dl-qmx6.dtsi b/arch/arm/boot/dts/imx6dl-qmx6.dtsi new file mode 100644 index 000000000000..150d69858255 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-qmx6.dtsi @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT +// +// Device Tree Source for i.MX6DL based congatec QMX6 +// System on Module +// +// Copyright 2018-2021 General Electric Company +// Copyright 2018-2021 Collabora +// Copyright 2016 congatec AG + +#include "imx6dl.dtsi" +#include +#include + +/ { + memory@10000000 { + reg = <0x10000000 0x40000000>; + }; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; + i2c-parent = <&i2c2>; + + i2c5: i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c6: i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + + audmux_ssi1 { + fsl,audmux-port = ; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(MX51_AUDMUX_PORT6) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(MX51_AUDMUX_PORT6) | + IMX_AUDMUX_V2_PTCR_SYN) + IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT6) + >; + }; + + audmux_aud6 { + fsl,audmux-port = ; + fsl,port-config = < + IMX_AUDMUX_V2_PTCR_SYN + IMX_AUDMUX_V2_PDCR_RXDSEL(MX51_AUDMUX_PORT1_SSI0) + >; + }; +}; + +&clks { + clocks = <&rtc_sqw>; + clock-names = "ckil"; + assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, + <&clks IMX6QDL_CLK_LDB_DI1_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL2_PFD0_352M>, + <&clks IMX6QDL_CLK_PLL2_PFD0_352M>; +}; + +&ecspi1 { + cs-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1>; + status = "okay"; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "sst,sst25vf032b", "jedec,spi-nor"; + spi-max-frequency = <20000000>; + reg = <0>; + + partition@0 { + label = "bootloader"; + reg = <0x0000000 0x100000>; + }; + + partition@100000 { + label = "user"; + reg = <0x0100000 0x2fc000>; + }; + + partition@3fc000 { + label = "reserved"; + reg = <0x03fc000 0x4000>; + read-only; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet &pinctrl_phy_reset>; + phy-mode = "rgmii-id"; + phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; + fsl,magic-packet; + phy-handle = <&phy0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@6 { + reg = <6>; + qca,clk-out-frequency = <125000000>; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio3 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio3 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; + + rtc: m41t62@68 { + compatible = "st,m41t62"; + reg = <0x68>; + + rtc_sqw: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; +}; + +&i2c6 { + pmic@8 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + /* + * keep VGEN3, VGEN4 and VGEN5 enabled in order to + * maintain backward compatibility with hw-rev. A.0 + */ + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + /* supply voltage for eMMC */ + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&pcie { + reset-gpio = <&gpio1 20 0>; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; +}; + +®_arm { + vin-supply = <&sw1a_reg>; +}; + +®_pu { + vin-supply = <&sw1c_reg>; +}; + +®_soc { + vin-supply = <&sw1c_reg>; +}; + +&snvs_poweroff { + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&usbh1 { + /* Connected to USB-Hub SMSC USB2514, provides P0, P2, P3, P4 on Qseven connector */ + vbus-supply = <®_5v>; + status = "okay"; +}; + +&usbotg { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; +}; + +&usdhc2 { + /* MicroSD card slot */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + no-1-8-v; + keep-power-in-suspend; + wakeup-source; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&usdhc3 { + /* eMMC module */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + non-removable; + bus-width = <8>; + no-1-8-v; + keep-power-in-suspend; + wakeup-source; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + qmx6mux: imx6qdl-qmx6 { + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x110b0 /* Q7[67] HDA_SDO */ + MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x30b0 /* Q7[59] HDA_SYNC */ + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x30b0 /* Q7[65] HDA_SDI */ + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x30b0 /* Q7[63] HDA_BITCLK */ + >; + }; + + /* PHY is on System on Module, Q7[3-15] have Ethernet lines */ + pinctrl_enet: enet { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + >; + }; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* PCIE_WAKE_B */ + MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x80000000 /* I2C multiplexer */ + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 /* SD4_CD# */ + MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 /* SD4_WP */ + MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x80000000 /* Camera MCLK */ + >; + }; + + pinctrl_i2c1: i2c1 { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 /* Q7[66] I2C_CLK */ + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 /* Q7[68] I2C_DAT */ + >; + }; + + pinctrl_i2c1_gpio: i2c1-gpio { + fsl,pins = < + MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x1b0b0 /* Q7[66] I2C_CLK */ + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x1b0b0 /* Q7[68] I2C_DAT */ + >; + }; + + pinctrl_i2c2: i2c2 { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 /* Q7[152] SDVO_CTRL_CLK */ + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 /* Q7[150] SDVO_CTRL_DAT */ + >; + }; + + pinctrl_i2c2_gpio: i2c2-gpio { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b0b0 /* Q7[152] SDVO_CTRL_CLK */ + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x1b0b0 /* Q7[150] SDVO_CTRL_DAT */ + >; + }; + + pinctrl_i2c3: i2c3 { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 /* Q7[60] SMB_CLK */ + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 /* Q7[62] SMB_DAT */ + >; + }; + + pinctrl_i2c3_gpio: i2c3-gpio { + fsl,pins = < + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b0b0 /* Q7[60] SMB_CLK */ + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 /* Q7[62] SMB_DAT */ + >; + }; + + pinctrl_phy_reset: phy-reset { + fsl,pins = < + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b0 /* RGMII Phy Reset */ + >; + }; + + pinctrl_pwm4: pwm4 { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 /* Q7[123] LVDS_BLT_CTRL */ + >; + }; + + pinctrl_q7_backlight_enable: q7-backlight-enable { + fsl,pins = < + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 /* Q7[112] LVDS_BLEN */ + >; + }; + + pinctrl_q7_gpio0: q7-gpio0 { + fsl,pins = < + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 /* Q7[185] GPIO0 */ + >; + }; + + pinctrl_q7_gpio1: q7-gpio1 { + fsl,pins = < + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 /* Q7[186] GPIO1 */ + >; + }; + + pinctrl_q7_gpio2: q7-gpio2 { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b0b0 /* Q7[187] GPIO2 */ + >; + }; + + pinctrl_q7_gpio3: q7-gpio3 { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b0 /* Q7[188] GPIO3 */ + >; + }; + + pinctrl_q7_gpio4: q7-gpio4 { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* Q7[189] GPIO4 */ + >; + }; + + pinctrl_q7_gpio5: q7-gpio5 { + fsl,pins = < + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b0 /* Q7[190] GPIO5 */ + >; + }; + + pinctrl_q7_gpio6: q7-gpio6 { + fsl,pins = < + MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x1b0b0 /* Q7[191] GPIO6 */ + >; + }; + + pinctrl_q7_gpio7: q7-gpio7 { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 /* Q7[192] GPIO7 */ + >; + }; + + pinctrl_q7_hda_reset: q7-hda-reset { + fsl,pins = < + MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 /* Q7[61] HDA_RST_N */ + >; + }; + + pinctrl_q7_lcd_power: lcd-power { + fsl,pins = < + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 /* Q7[111] LVDS_PPEN */ + >; + }; + + pinctrl_q7_sdio_power: q7-sdio-power { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 /* Q7[47] SDIO_PWR# */ + >; + }; + + pinctrl_q7_sleep_button: q7-sleep-button { + fsl,pins = < + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 /* Q7[21] SLP_BTN# */ + >; + }; + + pinctrl_q7_spi_cs1: spi-cs1 { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b0b0 /* Q7[202] SPI_CS1# */ + >; + }; + + /* SPI1 bus does not leave System on Module */ + pinctrl_spi1: spi1 { + fsl,pins = < + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x1b0b0 + >; + }; + + /* Debug connector on Q7 module */ + pinctrl_uart2: uart2 { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3 { + fsl,pins = < + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 /* Q7[177] UART0_RX */ + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 /* Q7[171] UART0_TX */ + >; + }; + + pinctrl_usbotg: usbotg { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 /* Q7[92] USB_ID */ + >; + }; + + /* µSD card slot on Q7 module */ + pinctrl_usdhc2: usdhc2 { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* SD2_CD */ + >; + }; + + /* eMMC module on Q7 module */ + pinctrl_usdhc3: usdhc3 { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4 { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 /* Q7[45] SDIO_CMD */ + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x17059 /* Q7[42] SDIO_CLK */ + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 /* Q7[48] SDIO_DAT1 */ + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 /* Q7[49] SDIO_DAT0 */ + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 /* Q7[50] SDIO_DAT3 */ + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 /* Q7[51] SDIO_DAT2 */ + >; + }; + + pinctrl_wdog: wdog { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0 /* Watchdog output signal */ + >; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6dl-riotboard.dts b/arch/arm/boot/dts/imx6dl-riotboard.dts index 065d3ab0f50a..e7d9bfbfd0e4 100644 --- a/arch/arm/boot/dts/imx6dl-riotboard.dts +++ b/arch/arm/boot/dts/imx6dl-riotboard.dts @@ -106,6 +106,8 @@ reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; reset-assert-us = <10000>; reset-deassert-us = <1000>; + qca,smarteee-tw-us-1g = <24>; + qca,clk-out-frequency = <125000000>; }; }; }; diff --git a/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi b/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi index 9148a01ed6d9..cb8b539eb29d 100644 --- a/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi +++ b/arch/arm/boot/dts/imx6dl-yapp4-common.dtsi @@ -11,6 +11,8 @@ aliases: aliases { ethernet1 = ð1; ethernet2 = ð2; + mmc0 = &usdhc3; + mmc1 = &usdhc4; }; backlight: backlight { @@ -345,6 +347,7 @@ solomon,height = <64>; solomon,width = <128>; solomon,page-offset = <0>; + solomon,col-offset = <4>; solomon,prechargep2 = <15>; reset-gpios = <&gpio_oled 1 GPIO_ACTIVE_LOW>; vbat-supply = <&sw2_reg>; diff --git a/arch/arm/boot/dts/imx6q-dhcom-som.dtsi b/arch/arm/boot/dts/imx6q-dhcom-som.dtsi index d0768ae429fa..4bf51f3ce003 100644 --- a/arch/arm/boot/dts/imx6q-dhcom-som.dtsi +++ b/arch/arm/boot/dts/imx6q-dhcom-som.dtsi @@ -12,10 +12,20 @@ / { aliases { + i2c0 = &i2c2; + i2c1 = &i2c1; + i2c2 = &i2c3; mmc0 = &usdhc2; mmc1 = &usdhc3; mmc2 = &usdhc4; mmc3 = &usdhc1; + rtc0 = &rtc_i2c; + rtc1 = &snvs_rtc; + serial0 = &uart1; + serial1 = &uart5; + serial2 = &uart4; + serial3 = &uart2; + serial4 = &uart3; }; memory@10000000 { @@ -23,6 +33,19 @@ reg = <0x10000000 0x40000000>; }; + reg_eth_vio: regulator-eth-vio { + compatible = "regulator-fixed"; + gpio = <&gpio1 7 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pinctrl_enet_vio>; + pinctrl-names = "default"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "eth_vio"; + vin-supply = <&sw2_reg>; + }; + reg_usb_otg_vbus: regulator-usb-otg-vbus { compatible = "regulator-fixed"; regulator-name = "usb_otg_vbus"; @@ -96,30 +119,40 @@ reg = <0>; max-speed = <100>; reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; - reset-delay-us = <1000>; - reset-post-delay-us = <1000>; + reset-assert-us = <1000>; + reset-deassert-us = <1000>; + smsc,disable-energy-detect; /* Make plugin detection reliable */ }; }; }; &i2c1 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio3 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio3 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; }; &i2c2 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; }; &i2c3 { clock-frequency = <100000>; - pinctrl-names = "default"; + pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; ltc3676: pmic@3c { @@ -203,7 +236,7 @@ pagesize = <16>; }; - rtc@56 { + rtc_i2c: rtc@56 { compatible = "microcrystal,rv3029"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rtc_hw300>; @@ -260,6 +293,11 @@ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x000b0 MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b1 + >; + }; + + pinctrl_enet_vio: enet-vio-grp { + fsl,pins = < MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x120b0 >; }; @@ -285,6 +323,13 @@ >; }; + pinctrl_i2c1_gpio: i2c1-gpio-grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x4001b8b1 + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x4001b8b1 + >; + }; + pinctrl_i2c2: i2c2-grp { fsl,pins = < MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 @@ -292,6 +337,13 @@ >; }; + pinctrl_i2c2_gpio: i2c2-gpio-grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b1 + >; + }; + pinctrl_i2c3: i2c3-grp { fsl,pins = < MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 @@ -299,6 +351,13 @@ >; }; + pinctrl_i2c3_gpio: i2c3-gpio-grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x4001b8b1 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x4001b8b1 + >; + }; + pinctrl_pmic_hw300: pmic-hw300-grp { fsl,pins = < MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1B0B0 diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts index fa2307d8ce86..c713ac03b3b9 100644 --- a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts +++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts @@ -112,7 +112,7 @@ &fec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; phy-supply = <&vgen2_1v2_eth>; status = "okay"; diff --git a/arch/arm/boot/dts/imx6q-ds.dts b/arch/arm/boot/dts/imx6q-ds.dts new file mode 100644 index 000000000000..b0a63a133977 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-ds.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2021 Dillon Min +// +// Based on imx6qdl-sabresd.dtsi which is: +// Copyright 2012 Freescale Semiconductor, Inc. +// Copyright 2011 Linaro Ltd. + +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-ds.dtsi" + +/ { + model = "DaSheng i.MX6 Quad Com-9xx Board"; + compatible = "ds,imx6q-sbc", "fsl,imx6q"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-ds.dtsi b/arch/arm/boot/dts/imx6qdl-ds.dtsi new file mode 100644 index 000000000000..f7e517555697 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-ds.dtsi @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2021 Dillon Min +// +// Based on imx6qdl-sabresd.dtsi which is: +// Copyright 2012 Freescale Semiconductor, Inc. +// Copyright 2011 Linaro Ltd. + +#include +#include +#include + +/ { + chosen { + stdout-path = &uart4; + }; + + memory@10000000 { + device_type = "memory"; + reg = <0x10000000 0x80000000>; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_usb_h1_vbus: regulator-usb-h1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led-0 { + gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&ipu1_csi0_from_ipu1_csi0_mux { + bus-width = <8>; + data-shift = <12>; /* Lines 19:12 used */ + hsync-active = <1>; + vsync-active = <1>; +}; + +&ipu1_csi0_mux_from_parallel_sensor { + remote-endpoint = <&ov2659_to_ipu1_csi0_mux>; +}; + +&ipu1_csi0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu1_csi0>; + status = "okay"; +}; + +&ecspi1 { + cs-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>, <&pinctrl_ecspi1_gpio>; + status = "okay"; + + m25p80: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p80", "jedec,spi-nor"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii-id"; + phy-handle = <&phy>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy: ethernet-phy@1 { + reg = <1>; + qca,clk-out-frequency = <125000000>; + reset-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + }; + }; +}; + +&hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi_cec>; + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pfuze100: pmic@8 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + ov2659: camera@30 { + compatible = "ovti,ov2659"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov2659>; + clocks = <&clks IMX6QDL_CLK_CKO>; + clock-names = "xvclk"; + reg = <0x30>; + powerdown-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + status = "okay"; + + port { + ov2659_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + link-frequencies = /bits/ 64 <70000000>; + bus-width = <8>; + hsync-active = <1>; + vsync-active = <1>; + }; + }; + }; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + >; + }; + + pinctrl_ecspi1_gpio: ecspi1grpgpiogrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x1b0b0 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0 + >; + }; + + pinctrl_hdmi_cec: hdmicecgrp { + fsl,pins = < + MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_ipu1_csi0: ipu1csi0grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 + >; + }; + + pinctrl_ov2659: ov2659grp { + fsl,pins = < + MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x1b0b0 + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc1_gpio: usdhc1grpgpiogrp { + fsl,pins = < + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2grpgpiogrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__WDOG2_B 0x1b0b0 + >; + }; + + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x1b0b0 + >; + }; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + bus-width = <4>; + cd-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + bus-width = <4>; + cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + bus-width = <8>; + non-removable; + no-1-8-v; + status = "okay"; +}; + +&wdog1 { + status = "disabled"; +}; + +&wdog2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi index 7bd658b7bdda..f3236204cb5a 100644 --- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi @@ -322,8 +322,8 @@ fsl,pins = < MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b0b1 - MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 >; }; @@ -410,6 +410,7 @@ &uart3 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3>; + uart-has-rtscts; status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index f824c9abd11a..0c0105468a2f 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -97,8 +97,11 @@ compatible = "fsl,imx6q-sabresd-wm8962", "fsl,imx-audio-wm8962"; model = "wm8962-audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hp>; ssi-controller = <&ssi2>; audio-codec = <&codec>; + audio-asrc = <&asrc>; audio-routing = "Headphone Jack", "HPOUTL", "Headphone Jack", "HPOUTR", @@ -545,6 +548,13 @@ >; }; + pinctrl_hp: hpgrp { + fsl,pins = < + MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x1b0b0 + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 diff --git a/arch/arm/boot/dts/imx6qdl-vicut1.dtsi b/arch/arm/boot/dts/imx6qdl-vicut1.dtsi index eb25d21a2ace..b9e305774fed 100644 --- a/arch/arm/boot/dts/imx6qdl-vicut1.dtsi +++ b/arch/arm/boot/dts/imx6qdl-vicut1.dtsi @@ -40,6 +40,27 @@ }; }; + counter-0 { + compatible = "interrupt-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_counter0>; + gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; + }; + + counter-1 { + compatible = "interrupt-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_counter1>; + gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + }; + + counter-2 { + compatible = "interrupt-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_counter2>; + gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; + }; + gpio-keys { compatible = "gpio-keys"; autorepeat; @@ -254,7 +275,7 @@ &gpio2 { gpio-line-names = - "", "", "", "", "", "", "", "", + "count0", "count1", "count2", "", "", "", "", "", "REV_ID0", "REV_ID1", "REV_ID2", "REV_ID3", "REV_ID4", "BOARD_ID0", "BOARD_ID1", "BOARD_ID2", "", "", "", "", "", "", "", "ON_SWITCH", @@ -572,6 +593,24 @@ >; }; + pinctrl_counter0: counter0grp { + fsl,pins = < + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b000 + >; + }; + + pinctrl_counter1: counter1grp { + fsl,pins = < + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b000 + >; + }; + + pinctrl_counter2: counter2grp { + fsl,pins = < + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b000 + >; + }; + pinctrl_ecspi1: ecspi1grp { fsl,pins = < MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi index b9b698f72b26..bf86b639fdac 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi @@ -142,7 +142,6 @@ imx6qdl-wandboard { pinctrl_hog: hoggrp { fsl,pins = < - MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x80000000 /* USB Power Enable */ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* USDHC1 CD */ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1f0b1 /* RGMII PHY reset */ diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi index 5a1e10def6ef..779cc536566d 100644 --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi @@ -60,38 +60,26 @@ gpios = <&gpio_spi 3 GPIO_ACTIVE_LOW>; }; - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "mx6ul-wm8960"; - simple-audio-card,format = "i2s"; - simple-audio-card,bitclock-master = <&dailink_master>; - simple-audio-card,frame-master = <&dailink_master>; - simple-audio-card,widgets = - "Microphone", "Mic Jack", - "Line", "Line In", - "Line", "Line Out", - "Speaker", "Speaker", - "Headphone", "Headphone Jack"; - simple-audio-card,routing = + sound-wm8960 { + compatible = "fsl,imx-audio-wm8960"; + model = "wm8960-audio"; + audio-cpu = <&sai2>; + audio-codec = <&codec>; + audio-asrc = <&asrc>; + hp-det-gpio = <&gpio5 4 0>; + audio-routing = "Headphone Jack", "HP_L", "Headphone Jack", "HP_R", - "Speaker", "SPK_LP", - "Speaker", "SPK_LN", - "Speaker", "SPK_RP", - "Speaker", "SPK_RN", - "LINPUT1", "Mic Jack", + "Ext Spk", "SPK_LP", + "Ext Spk", "SPK_LN", + "Ext Spk", "SPK_RP", + "Ext Spk", "SPK_RN", + "LINPUT2", "Mic Jack", "LINPUT3", "Mic Jack", - "RINPUT1", "Mic Jack", - "RINPUT2", "Mic Jack"; - - simple-audio-card,cpu { - sound-dai = <&sai2>; - }; - - dailink_master: simple-audio-card,codec { - sound-dai = <&codec>; - clocks = <&clks IMX6UL_CLK_SAI2>; - }; + "RINPUT1", "AMIC", + "RINPUT2", "AMIC", + "Mic Jack", "MICB", + "AMIC", "MICB"; }; spi4 { @@ -145,6 +133,10 @@ compatible = "wlf,wm8960"; reg = <0x1a>; wlf,shared-lrclk; + wlf,hp-cfg = <3 2 3>; + wlf,gpio-cfg = <1 3>; + clocks = <&clks IMX6UL_CLK_SAI2>; + clock-names = "mclk"; }; camera@3c { diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index ac0751bc1177..4a0d83784d7d 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -164,6 +164,13 @@ "LINPUT1", "AMIC", "AMIC", "MICB"; }; + + sound-hdmi { + compatible = "fsl,imx-audio-sii902x"; + model = "sii902x-audio"; + audio-cpu = <&sai3>; + hdmi-out; + }; }; &adc1 { diff --git a/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts b/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts index 8fcd95805ff4..5b8dcc19deee 100644 --- a/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts +++ b/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts @@ -90,20 +90,71 @@ timeout-ms = <5000>; }; - /* The first 16MB region on the expansion bus */ - flash@50000000 { - compatible = "intel,ixp4xx-flash", "cfi-flash"; - bank-width = <2>; - /* - * 8 MB of Flash in 0x20000 byte blocks - * mapped in at 0x50000000 - */ - reg = <0x50000000 0x800000>; + gpio-beeper { + compatible = "gpio-beeper"; + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + }; - partitions { - compatible = "redboot-fis"; - /* Eraseblock at 0x7e0000 */ - fis-index-block = <0x3f>; + soc { + bus@50000000 { + /* The first 16MB region at CS0 on the expansion bus */ + flash@0 { + compatible = "intel,ixp4xx-flash", "cfi-flash"; + bank-width = <2>; + /* + * 8 MB of Flash in 0x20000 byte blocks + * mapped in at CS0. + */ + reg = <0x00000000 0x800000>; + + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0x7e0000 */ + fis-index-block = <0x3f>; + }; + }; + }; + + pci@c0000000 { + status = "ok"; + + /* + * Taken from NSLU2 PCI boardfile, INT A, B, C swizzled D constant + * We have slots (IDSEL) 1, 2 and 3. + */ + interrupt-map = + /* IDSEL 1 */ + <0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */ + <0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */ + <0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */ + <0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */ + /* IDSEL 2 */ + <0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */ + <0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */ + <0x1000 0 0 3 &gpio0 11 3>, /* INT C on slot 2 is irq 11 */ + <0x1000 0 0 4 &gpio0 8 3>, /* INT D on slot 2 is irq 8 */ + /* IDSEL 3 */ + <0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */ + <0x1800 0 0 2 &gpio0 11 3>, /* INT B on slot 3 is irq 11 */ + <0x1800 0 0 3 &gpio0 10 3>, /* INT C on slot 3 is irq 10 */ + <0x1800 0 0 4 &gpio0 8 3>; /* INT D on slot 3 is irq 8 */ + }; + + ethernet@c8009000 { + status = "ok"; + queue-rx = <&qmgr 3>; + queue-txready = <&qmgr 20>; + phy-mode = "rgmii"; + phy-handle = <&phy1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; }; }; }; diff --git a/arch/arm/boot/dts/intel-ixp42x-welltech-epbx100.dts b/arch/arm/boot/dts/intel-ixp42x-welltech-epbx100.dts new file mode 100644 index 000000000000..84158503be2a --- /dev/null +++ b/arch/arm/boot/dts/intel-ixp42x-welltech-epbx100.dts @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Corentin Labbe + */ + +/dts-v1/; + +#include "intel-ixp42x.dtsi" + +/ { + model = "Welltech EPBX100"; + compatible = "welltech,epbx100", "intel,ixp42x"; + #address-cells = <1>; + #size-cells = <1>; + + memory@0 { + /* 64 MB SDRAM */ + device_type = "memory"; + reg = <0x00000000 0x4000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 root=/dev/ram0 initrd=0x00800000,9M"; + stdout-path = "uart0:115200n8"; + }; + + aliases { + serial0 = &uart0; + }; + + flash@50000000 { + compatible = "intel,ixp4xx-flash", "cfi-flash"; + bank-width = <2>; + /* + * 16 MB of Flash + */ + reg = <0x50000000 0x1000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00080000>; + read-only; + }; + partition@80000 { + label = "zImage"; + reg = <0x00080000 0x00100000>; + read-only; + }; + partition@180000 { + label = "ramdisk"; + reg = <0x00180000 0x00300000>; + read-only; + }; + partition@480000 { + label = "User"; + reg = <0x00480000 0x00b60000>; + read-only; + }; + partition@fe0000 { + label = "FIS directory"; + reg = <0x00fe0000 0x001f000>; + read-only; + }; + partition@fff000 { + label = "RedBoot config"; + reg = <0x00fff000 0x0001000>; + read-only; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/intel-ixp42x.dtsi b/arch/arm/boot/dts/intel-ixp42x.dtsi index a9622ca850cc..5fa063ed396c 100644 --- a/arch/arm/boot/dts/intel-ixp42x.dtsi +++ b/arch/arm/boot/dts/intel-ixp42x.dtsi @@ -7,6 +7,10 @@ / { soc { + pci@c0000000 { + compatible = "intel,ixp42x-pci"; + }; + interrupt-controller@c8003000 { compatible = "intel,ixp42x-interrupt"; }; diff --git a/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts b/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts index ba1163a1e1e7..60a1228a970f 100644 --- a/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts +++ b/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts @@ -76,19 +76,97 @@ }; }; - flash@50000000 { - compatible = "intel,ixp4xx-flash", "cfi-flash"; - bank-width = <2>; - /* - * 32 MB of Flash in 0x20000 byte blocks - * mapped in at 0x50000000 - */ - reg = <0x50000000 0x2000000>; + soc { + bus@50000000 { + flash@0 { + compatible = "intel,ixp4xx-flash", "cfi-flash"; + bank-width = <2>; + /* + * 32 MB of Flash in 0x20000 byte blocks + * mapped in at CS0. + */ + reg = <0x00000000 0x2000000>; - partitions { - compatible = "redboot-fis"; - /* Eraseblock at 0x1fe0000 */ - fis-index-block = <0xff>; + partitions { + compatible = "redboot-fis"; + /* Eraseblock at 0x1fe0000 */ + fis-index-block = <0xff>; + }; + }; + }; + + pci@c0000000 { + status = "ok"; + + /* + * In the boardfile for the Cambria from OpenWRT the interrupts + * are assigned one per IDSEL, so all 4 interrupts from IDSEL + * 1 are connected to IRQ 11, all 4 interrupts from IDSEL 2 + * connected to IRQ 10 etc. I find this highly unlikely so I + * have instead assumed that they are rotated (swizzled) like + * this with 11, 10, 9, 8 for the 4 pins on IDSEL 1 etc. + */ + interrupt-map = + /* IDSEL 1 */ + <0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */ + <0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */ + <0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */ + <0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */ + /* IDSEL 2 */ + <0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */ + <0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */ + <0x1000 0 0 3 &gpio0 8 3>, /* INT C on slot 2 is irq 8 */ + <0x1000 0 0 4 &gpio0 11 3>, /* INT D on slot 2 is irq 11 */ + /* IDSEL 3 */ + <0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */ + <0x1800 0 0 2 &gpio0 8 3>, /* INT B on slot 3 is irq 8 */ + <0x1800 0 0 3 &gpio0 11 3>, /* INT C on slot 3 is irq 11 */ + <0x1800 0 0 4 &gpio0 10 3>, /* INT D on slot 3 is irq 10 */ + /* IDSEL 4 */ + <0x2000 0 0 1 &gpio0 8 3>, /* INT A on slot 3 is irq 8 */ + <0x2000 0 0 2 &gpio0 11 3>, /* INT B on slot 3 is irq 11 */ + <0x2000 0 0 3 &gpio0 10 3>, /* INT C on slot 3 is irq 10 */ + <0x2000 0 0 4 &gpio0 9 3>, /* INT D on slot 3 is irq 9 */ + /* IDSEL 6 */ + <0x3000 0 0 1 &gpio0 10 3>, /* INT A on slot 3 is irq 10 */ + <0x3000 0 0 2 &gpio0 9 3>, /* INT B on slot 3 is irq 9 */ + <0x3000 0 0 3 &gpio0 8 3>, /* INT C on slot 3 is irq 8 */ + <0x3000 0 0 4 &gpio0 11 3>, /* INT D on slot 3 is irq 11 */ + /* IDSEL 15 */ + <0x7800 0 0 1 &gpio0 8 3>, /* INT A on slot 3 is irq 8 */ + <0x7800 0 0 2 &gpio0 11 3>, /* INT B on slot 3 is irq 11 */ + <0x7800 0 0 3 &gpio0 10 3>, /* INT C on slot 3 is irq 10 */ + <0x7800 0 0 4 &gpio0 9 3>; /* INT D on slot 3 is irq 9 */ + }; + + ethernet@c800a000 { + status = "ok"; + queue-rx = <&qmgr 4>; + queue-txready = <&qmgr 21>; + phy-mode = "rgmii"; + phy-handle = <&phy1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + }; + }; + }; + + ethernet@c800c000 { + status = "ok"; + queue-rx = <&qmgr 2>; + queue-txready = <&qmgr 19>; + phy-mode = "rgmii"; + phy-handle = <&phy2>; + intel,npe-handle = <&npe 0>; }; }; }; diff --git a/arch/arm/boot/dts/intel-ixp43x.dtsi b/arch/arm/boot/dts/intel-ixp43x.dtsi index 494fb2ff57a0..1d0817c6e3f9 100644 --- a/arch/arm/boot/dts/intel-ixp43x.dtsi +++ b/arch/arm/boot/dts/intel-ixp43x.dtsi @@ -8,6 +8,10 @@ / { soc { + pci@c0000000 { + compatible = "intel,ixp43x-pci"; + }; + interrupt-controller@c8003000 { compatible = "intel,ixp43x-interrupt"; }; diff --git a/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi b/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi index f8cd506659dc..cce49e809043 100644 --- a/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi +++ b/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi @@ -30,5 +30,38 @@ interrupts = <33 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; + + /* This is known as EthB1 */ + ethernet@c800d000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc800d000 0x1000>; + status = "disabled"; + intel,npe = <1>; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 0>; + queue-txready = <&qmgr 0>; + }; + + /* This is known as EthB2 */ + ethernet@c800e000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc800e000 0x1000>; + status = "disabled"; + intel,npe = <2>; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 0>; + queue-txready = <&qmgr 0>; + }; + + /* This is known as EthB3 */ + ethernet@c800f000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc800f000 0x1000>; + status = "disabled"; + intel,npe = <3>; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 0>; + queue-txready = <&qmgr 0>; + }; }; }; diff --git a/arch/arm/boot/dts/intel-ixp4xx.dtsi b/arch/arm/boot/dts/intel-ixp4xx.dtsi index d4a09584f417..a50427ad05e7 100644 --- a/arch/arm/boot/dts/intel-ixp4xx.dtsi +++ b/arch/arm/boot/dts/intel-ixp4xx.dtsi @@ -14,12 +14,61 @@ compatible = "simple-bus"; interrupt-parent = <&intcon>; + /* + * The IXP4xx expansion bus is a set of 16 or 32MB + * windows in the 256MB space from 0x50000000 to + * 0x5fffffff. + */ + bus@50000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00000000 0x50000000 0x10000000>; + dma-ranges = <0x00000000 0x50000000 0x10000000>; + }; + qmgr: queue-manager@60000000 { compatible = "intel,ixp4xx-ahb-queue-manager"; reg = <0x60000000 0x4000>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>, <4 IRQ_TYPE_LEVEL_HIGH>; }; + pci@c0000000 { + /* compatible filled in by per-soc device tree */ + reg = <0xc0000000 0x1000>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>, + <9 IRQ_TYPE_LEVEL_HIGH>, + <10 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x00 0xff>; + status = "disabled"; + + ranges = + /* + * 64MB 32bit non-prefetchable memory 0x48000000-0x4bffffff + * done in 4 chunks of 16MB each. + */ + <0x02000000 0 0x48000000 0x48000000 0 0x04000000>, + /* 64KB I/O space at 0x4c000000 */ + <0x01000000 0 0x00000000 0x4c000000 0 0x00010000>; + + /* + * This needs to map to the start of physical memory so + * PCI devices can see all (hopefully) memory. This is done + * using 4 1:1 16MB windows, so the RAM should not be more than + * 64 MB for this to work. If your memory is anywhere else + * than at 0x0 you need to alter this. + */ + dma-ranges = + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + /* Each unique DTS using PCI must specify the swizzling */ + }; + uart0: serial@c8000000 { compatible = "intel,xscale-uart"; reg = <0xc8000000 0x1000>; @@ -61,9 +110,50 @@ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; }; - npe@c8006000 { + npe: npe@c8006000 { compatible = "intel,ixp4xx-network-processing-engine"; reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>; + + /* NPE-C contains a crypto accelerator */ + crypto { + compatible = "intel,ixp4xx-crypto"; + intel,npe-handle = <&npe 2>; + queue-rx = <&qmgr 30>; + queue-txready = <&qmgr 29>; + }; + }; + + /* This is known as EthB */ + ethernet@c8009000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc8009000 0x1000>; + status = "disabled"; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 3>; + queue-txready = <&qmgr 20>; + intel,npe-handle = <&npe 1>; + }; + + /* This is known as EthC */ + ethernet@c800a000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc800a000 0x1000>; + status = "disabled"; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 0>; + queue-txready = <&qmgr 0>; + intel,npe-handle = <&npe 2>; + }; + + /* This is known as EthA */ + ethernet@c800c000 { + compatible = "intel,ixp4xx-ethernet"; + reg = <0xc800c000 0x1000>; + status = "disabled"; + intel,npe = <0>; + /* Dummy values that depend on firmware */ + queue-rx = <&qmgr 0>; + queue-txready = <&qmgr 0>; }; }; }; diff --git a/arch/arm/boot/dts/keystone-k2g-evm.dts b/arch/arm/boot/dts/keystone-k2g-evm.dts index 14e26a4fd62a..d800f26b6275 100644 --- a/arch/arm/boot/dts/keystone-k2g-evm.dts +++ b/arch/arm/boot/dts/keystone-k2g-evm.dts @@ -544,20 +544,15 @@ }; }; -&k2g_clks { - /* on the board 22.5792MHz is connected to AUDOSC_IN */ - assigned-clocks = <&k2g_clks 0x4c 2>; - assigned-clock-rates = <22579200>; -}; - &mcasp2 { #sound-dai-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&mcasp2_pins>; - assigned-clocks = <&k2g_clks 0x6 1>; - assigned-clock-parents = <&k2g_clks 0x6 2>; + assigned-clocks = <&k2g_clks 0x4c 2>, <&k2g_clks 0x6 1>; + assigned-clock-parents = <0>, <&k2g_clks 0x6 2>; + assigned-clock-rates = <22579200>, <0>; status = "okay"; diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi index 05a75019275e..37198294f4b2 100644 --- a/arch/arm/boot/dts/keystone-k2g.dtsi +++ b/arch/arm/boot/dts/keystone-k2g.dtsi @@ -242,7 +242,7 @@ status = "disabled"; }; - msgmgr: msgmgr@2a00000 { + msgmgr: mailbox@2a00000 { compatible = "ti,k2g-message-manager"; #mbox-cells = <2>; reg-names = "queue_proxy_region", @@ -254,7 +254,7 @@ ; }; - pmmc: pmmc@2921c00 { + pmmc: system-controller@2921c00 { compatible = "ti,k2g-sci"; /* * In case of rare platforms that does not use k2g as @@ -272,7 +272,7 @@ #power-domain-cells = <1>; }; - k2g_clks: clocks { + k2g_clks: clock-controller { compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; }; diff --git a/arch/arm/boot/dts/meson.dtsi b/arch/arm/boot/dts/meson.dtsi index 8bae6ed0abb2..bd0e864964e9 100644 --- a/arch/arm/boot/dts/meson.dtsi +++ b/arch/arm/boot/dts/meson.dtsi @@ -50,6 +50,7 @@ compatible = "amlogic,meson6-uart", "amlogic,meson-uart"; reg = <0x84c0 0x18>; interrupts = ; + fifo-size = <128>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/mstar-v7.dtsi b/arch/arm/boot/dts/mstar-v7.dtsi index 075d583d6f40..2273295e140f 100644 --- a/arch/arm/boot/dts/mstar-v7.dtsi +++ b/arch/arm/boot/dts/mstar-v7.dtsi @@ -60,6 +60,14 @@ clock-frequency = <32768>; status = "disabled"; }; + + xtal_div2: xtal_div2 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&xtal>; + clock-div = <2>; + clock-mult = <1>; + }; }; soc: soc { @@ -101,6 +109,12 @@ mask = <0x79>; }; + watchdog@6000 { + compatible = "mstar,msc313e-wdt"; + reg = <0x6000 0x1f>; + clocks = <&xtal_div2>; + }; + intc_fiq: interrupt-controller@201310 { compatible = "mstar,mst-intc"; reg = <0x201310 0x40>; diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index f9c2a9938898..5750ca1233cc 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -120,8 +120,6 @@ #address-cells = <1>; #size-cells = <0>; interrupts = <56>; - dmas = <&sdma 27 &sdma 28>; - dma-names = "tx", "rx"; }; i2c2: i2c@48072000 { @@ -131,8 +129,6 @@ #address-cells = <1>; #size-cells = <0>; interrupts = <57>; - dmas = <&sdma 29 &sdma 30>; - dma-names = "tx", "rx"; }; mcspi1: spi@48098000 { diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi index 494bf6972005..bb529a2a295d 100644 --- a/arch/arm/boot/dts/omap2420.dtsi +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -192,16 +192,15 @@ compatible = "ti,omap2-mailbox"; reg = <0x48094000 0x200>; interrupts = <26>, <34>; - interrupt-names = "dsp", "iva"; ti,hwmods = "mailbox"; #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <6>; - mbox_dsp: dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <0 0 0>; ti,mbox-rx = <1 0 0>; }; - mbox_iva: iva { + mbox_iva: mbox-iva { ti,mbox-tx = <2 1 3>; ti,mbox-rx = <3 1 3>; }; diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index d19d8ba3b607..23115ba61bc0 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -284,7 +284,7 @@ #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <6>; - mbox_dsp: dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <0 0 0>; ti,mbox-rx = <1 0 0>; }; diff --git a/arch/arm/boot/dts/omap3-evm-processor-common.dtsi b/arch/arm/boot/dts/omap3-evm-processor-common.dtsi index b4109f48ec18..e6ba30a21166 100644 --- a/arch/arm/boot/dts/omap3-evm-processor-common.dtsi +++ b/arch/arm/boot/dts/omap3-evm-processor-common.dtsi @@ -195,7 +195,7 @@ * for bus switch SN74CB3Q3384A, level-shifter SN74AVC16T245DGGR, and 1.8V. */ &gpio2 { - en_usb2_port { + en-usb2-port-hog { gpio-hog; gpios = <29 GPIO_ACTIVE_HIGH>; /* gpio_61 */ output-low; diff --git a/arch/arm/boot/dts/omap3-gta04a5.dts b/arch/arm/boot/dts/omap3-gta04a5.dts index fd84bbf3b9cc..9ce8d81250aa 100644 --- a/arch/arm/boot/dts/omap3-gta04a5.dts +++ b/arch/arm/boot/dts/omap3-gta04a5.dts @@ -37,7 +37,7 @@ }; &gpio5 { - irda_en { + irda-en-hog { gpio-hog; gpios = <(175-160) GPIO_ACTIVE_HIGH>; output-high; /* activate gpio_175 to disable IrDA receiver */ diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index c5b9da0d7e6c..64b7e6fddd1b 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -403,8 +403,6 @@ compatible = "ti,omap3-i2c"; reg = <0x48070000 0x80>; interrupts = <56>; - dmas = <&sdma 27 &sdma 28>; - dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; @@ -414,8 +412,6 @@ compatible = "ti,omap3-i2c"; reg = <0x48072000 0x80>; interrupts = <57>; - dmas = <&sdma 29 &sdma 30>; - dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; @@ -425,8 +421,6 @@ compatible = "ti,omap3-i2c"; reg = <0x48060000 0x80>; interrupts = <61>; - dmas = <&sdma 25 &sdma 26>; - dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; @@ -440,7 +434,7 @@ #mbox-cells = <1>; ti,mbox-num-users = <2>; ti,mbox-num-fifos = <2>; - mbox_dsp: dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <0 0 0>; ti,mbox-rx = <1 0 0>; }; diff --git a/arch/arm/boot/dts/omap4-l4.dtsi b/arch/arm/boot/dts/omap4-l4.dtsi index 99721673d7af..46b8f9efd413 100644 --- a/arch/arm/boot/dts/omap4-l4.dtsi +++ b/arch/arm/boot/dts/omap4-l4.dtsi @@ -600,11 +600,11 @@ #mbox-cells = <1>; ti,mbox-num-users = <3>; ti,mbox-num-fifos = <8>; - mbox_ipu: mbox_ipu { + mbox_ipu: mbox-ipu { ti,mbox-tx = <0 0 0>; ti,mbox-rx = <1 0 0>; }; - mbox_dsp: mbox_dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <3 0 0>; ti,mbox-rx = <2 0 0>; }; diff --git a/arch/arm/boot/dts/omap5-board-common.dtsi b/arch/arm/boot/dts/omap5-board-common.dtsi index d8f13626cfd1..45435bb88c89 100644 --- a/arch/arm/boot/dts/omap5-board-common.dtsi +++ b/arch/arm/boot/dts/omap5-board-common.dtsi @@ -149,7 +149,7 @@ &gpio8 { /* TI trees use GPIO instead of msecure, see also muxing */ - p234 { + msecure-hog { gpio-hog; gpios = <10 GPIO_ACTIVE_HIGH>; output-high; diff --git a/arch/arm/boot/dts/omap5-l4.dtsi b/arch/arm/boot/dts/omap5-l4.dtsi index b148b289e830..06cc3a19ddaa 100644 --- a/arch/arm/boot/dts/omap5-l4.dtsi +++ b/arch/arm/boot/dts/omap5-l4.dtsi @@ -616,11 +616,11 @@ #mbox-cells = <1>; ti,mbox-num-users = <3>; ti,mbox-num-fifos = <8>; - mbox_ipu: mbox_ipu { + mbox_ipu: mbox-ipu { ti,mbox-tx = <0 0 0>; ti,mbox-rx = <1 0 0>; }; - mbox_dsp: mbox_dsp { + mbox_dsp: mbox-dsp { ti,mbox-tx = <3 0 0>; ti,mbox-rx = <2 0 0>; }; diff --git a/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi index 91163867be34..31f59de5190b 100644 --- a/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi +++ b/arch/arm/boot/dts/openbmc-flash-layout-64.dtsi @@ -9,27 +9,27 @@ partitions { #size-cells = <1>; u-boot@0 { - reg = <0x0 0x60000>; // 384KB + reg = <0x0 0xe0000>; // 896KB label = "u-boot"; }; - u-boot-env@60000 { - reg = <0x60000 0x20000>; // 128KB + u-boot-env@e0000 { + reg = <0xe0000 0x20000>; // 128KB label = "u-boot-env"; }; - kernel@80000 { - reg = <0x80000 0x500000>; // 5MB + kernel@100000 { + reg = <0x100000 0x900000>; // 9MB label = "kernel"; }; - rofs@580000 { - reg = <0x580000 0x2a80000>; // 42.5MB + rofs@a00000 { + reg = <0xa00000 0x2000000>; // 32MB label = "rofs"; }; - rwfs@3000000 { - reg = <0x3000000 0x1000000>; // 16MB + rwfs@6000000 { + reg = <0x2a00000 0x1600000>; // 22MB label = "rwfs"; }; }; diff --git a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts index 282b89ce3d45..f7ea2e5dd191 100644 --- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts @@ -216,6 +216,10 @@ }; }; +&adm_dma { + status = "okay"; +}; + &gmac0 { status = "okay"; @@ -251,6 +255,39 @@ status = "okay"; }; +&hs_phy_1 { + status = "okay"; +}; + +&nand { + status = "okay"; + + nandcs@0 { + compatible = "qcom,nandcs"; + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot@0 { + label = "RouterBoard NAND 1 Boot"; + reg = <0x0000000 0x0800000>; + }; + + main@800000 { + label = "RouterBoard NAND 1 Main"; + reg = <0x0800000 0x7800000>; + }; + }; + }; +}; + &qcom_pinmux { buttons_pins: buttons_pins { mux { @@ -305,4 +342,25 @@ input-disable; }; }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio4"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-high; + }; + }; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; + + status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi index 98995ead4413..7bcf5ef92157 100644 --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi @@ -2,6 +2,8 @@ /dts-v1/; #include +#include +#include #include #include #include @@ -46,6 +48,228 @@ }; }; + thermal-zones { + tsens_tz_sensor0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 0>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 1>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 2>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor3 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 3>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor4 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 4>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor5 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 5>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor6 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 6>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor7 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 7>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor8 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 8>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor9 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 9>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + + tsens_tz_sensor10 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 10>; + + trips { + cpu-critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu-hot { + temperature = <95000>; + hysteresis = <2000>; + type = "hot"; + }; + }; + }; + }; + memory { device_type = "memory"; reg = <0x0 0x0>; @@ -185,6 +409,31 @@ bias-pull-up; }; }; + + nand_pins: nand_pins { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + function = "nand"; + drive-strength = <10>; + bias-disable; + }; + + pullups { + pins = "gpio39"; + bias-pull-up; + }; + + hold { + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; + bias-bus-hold; + }; + }; }; intc: interrupt-controller@2000000 { @@ -226,6 +475,26 @@ reg = <0x02098000 0x1000>, <0x02008000 0x1000>; }; + adm_dma: dma-controller@18300000 { + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = ; + #dma-cells = <1>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; + + resets = <&gcc ADM0_RESET>, + <&gcc ADM0_PBUS_RESET>, + <&gcc ADM0_C0_RESET>, + <&gcc ADM0_C1_RESET>, + <&gcc ADM0_C2_RESET>; + reset-names = "clk", "pbus", "c0", "c1", "c2"; + qcom,ee = <0>; + + status = "disabled"; + }; + saw0: regulator@2089000 { compatible = "qcom,saw2"; reg = <0x02089000 0x1000>, <0x02009000 0x1000>; @@ -403,6 +672,28 @@ status = "disabled"; }; + nand: nand-controller@1ac00000 { + compatible = "qcom,ipq806x-nand"; + reg = <0x1ac00000 0x800>; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + clocks = <&gcc EBI2_CLK>, + <&gcc EBI2_AON_CLK>; + clock-names = "core", "aon"; + + dmas = <&adm_dma 3>; + dma-names = "rxtx"; + qcom,cmd-crci = <15>; + qcom,data-crci = <3>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + sata: sata@29000000 { compatible = "qcom,ipq806x-ahci", "generic-ahci"; reg = <0x29000000 0x180>; @@ -436,6 +727,12 @@ reg = <0x00700000 0x1000>; #address-cells = <1>; #size-cells = <1>; + tsens_calib: calib@400 { + reg = <0x400 0xb>; + }; + tsens_calib_backup: calib_backup@410 { + reg = <0x410 0xb>; + }; }; gcc: clock-controller@900000 { @@ -443,6 +740,38 @@ reg = <0x00900000 0x4000>; #clock-cells = <1>; #reset-cells = <1>; + #power-domain-cells = <1>; + + tsens: thermal-sensor@900000 { + compatible = "qcom,ipq8064-tsens"; + + nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>; + nvmem-cell-names = "calib", "calib_backup"; + interrupts = ; + interrupt-names = "uplow"; + + #qcom,sensors = <11>; + #thermal-sensor-cells = <1>; + }; + }; + + rpm: rpm@108000 { + compatible = "qcom,rpm-ipq8064"; + reg = <0x108000 0x1000>; + qcom,ipc = <&l2cc 0x8 2>; + + interrupts = , + , + ; + interrupt-names = "ack", "err", "wakeup"; + + clocks = <&gcc RPM_MSG_RAM_H_CLK>; + clock-names = "ram"; + + rpmcc: clock-controller { + compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; + #clock-cells = <1>; + }; }; tcsr: syscon@1a400000 { @@ -450,6 +779,14 @@ reg = <0x1a400000 0x100>; }; + l2cc: clock-controller@2011000 { + compatible = "qcom,kpss-gcc", "syscon"; + reg = <0x2011000 0x1000>; + clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu_l2_aux"; + }; + lcc: clock-controller@28000000 { compatible = "qcom,lcc-ipq8064"; reg = <0x28000000 0x1000>; @@ -718,6 +1055,94 @@ status = "disabled"; }; + hs_phy_0: phy@100f8800 { + compatible = "qcom,ipq806x-usb-phy-hs"; + reg = <0x100f8800 0x30>; + clocks = <&gcc USB30_0_UTMI_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + + status = "disabled"; + }; + + ss_phy_0: phy@100f8830 { + compatible = "qcom,ipq806x-usb-phy-ss"; + reg = <0x100f8830 0x30>; + clocks = <&gcc USB30_0_MASTER_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + + status = "disabled"; + }; + + usb3_0: usb3@100f8800 { + compatible = "qcom,dwc3", "syscon"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x100f8800 0x8000>; + clocks = <&gcc USB30_0_MASTER_CLK>; + clock-names = "core"; + + ranges; + + resets = <&gcc USB30_0_MASTER_RESET>; + reset-names = "master"; + + status = "disabled"; + + dwc3_0: dwc3@10000000 { + compatible = "snps,dwc3"; + reg = <0x10000000 0xcd00>; + interrupts = ; + phys = <&hs_phy_0>, <&ss_phy_0>; + phy-names = "usb2-phy", "usb3-phy"; + dr_mode = "host"; + snps,dis_u3_susphy_quirk; + }; + }; + + hs_phy_1: phy@110f8800 { + compatible = "qcom,ipq806x-usb-phy-hs"; + reg = <0x110f8800 0x30>; + clocks = <&gcc USB30_1_UTMI_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + }; + + ss_phy_1: phy@110f8830 { + compatible = "qcom,ipq806x-usb-phy-ss"; + reg = <0x110f8830 0x30>; + clocks = <&gcc USB30_1_MASTER_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + }; + + usb3_1: usb3@110f8800 { + compatible = "qcom,dwc3", "syscon"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x110f8800 0x8000>; + clocks = <&gcc USB30_1_MASTER_CLK>; + clock-names = "core"; + + ranges; + + resets = <&gcc USB30_1_MASTER_RESET>; + reset-names = "master"; + + status = "disabled"; + + dwc3_1: dwc3@11000000 { + compatible = "snps,dwc3"; + reg = <0x11000000 0xcd00>; + interrupts = ; + phys = <&hs_phy_1>, <&ss_phy_1>; + phy-names = "usb2-phy", "usb3-phy"; + dr_mode = "host"; + snps,dis_u3_susphy_quirk; + }; + }; + vsdcc_fixed: vsdcc-regulator { compatible = "regulator-fixed"; regulator-name = "SDCC Power"; diff --git a/arch/arm/boot/dts/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom-sdx55-t55.dts index ddcd53aa533d..2ffcd085904d 100644 --- a/arch/arm/boot/dts/qcom-sdx55-t55.dts +++ b/arch/arm/boot/dts/qcom-sdx55-t55.dts @@ -250,7 +250,7 @@ nand-ecc-step-size = <512>; nand-bus-width = <8>; /* efs2 partition is secured */ - secure-regions = <0x500000 0xb00000>; + secure-regions = /bits/ 64 <0x500000 0xb00000>; }; }; diff --git a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts index 3065f84634b8..80c40da79604 100644 --- a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts +++ b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts @@ -250,8 +250,8 @@ nand-ecc-step-size = <512>; nand-bus-width = <8>; /* ico and efs2 partitions are secured */ - secure-regions = <0x500000 0x500000 - 0xa00000 0xb00000>; + secure-regions = /bits/ 64 <0x500000 0x500000 + 0xa00000 0xb00000>; }; }; diff --git a/arch/arm/boot/dts/r8a7742.dtsi b/arch/arm/boot/dts/r8a7742.dtsi index dd1b976d2a6c..a2279686ffcc 100644 --- a/arch/arm/boot/dts/r8a7742.dtsi +++ b/arch/arm/boot/dts/r8a7742.dtsi @@ -47,7 +47,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -56,6 +55,7 @@ clock-frequency = <1400000000>; clocks = <&cpg CPG_CORE R8A7742_CLK_Z>; power-domains = <&sysc R8A7742_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -77,6 +77,7 @@ clock-frequency = <1400000000>; clocks = <&cpg CPG_CORE R8A7742_CLK_Z>; power-domains = <&sysc R8A7742_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -98,6 +99,7 @@ clock-frequency = <1400000000>; clocks = <&cpg CPG_CORE R8A7742_CLK_Z>; power-domains = <&sysc R8A7742_PD_CA15_CPU2>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -119,6 +121,7 @@ clock-frequency = <1400000000>; clocks = <&cpg CPG_CORE R8A7742_CLK_Z>; power-domains = <&sysc R8A7742_PD_CA15_CPU3>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -750,6 +753,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7743.dtsi b/arch/arm/boot/dts/r8a7743.dtsi index 6e37b8da278b..7e5e09d210ec 100644 --- a/arch/arm/boot/dts/r8a7743.dtsi +++ b/arch/arm/boot/dts/r8a7743.dtsi @@ -49,7 +49,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -59,6 +58,7 @@ clocks = <&cpg CPG_CORE R8A7743_CLK_Z>; clock-latency = <300000>; /* 300 us */ power-domains = <&sysc R8A7743_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; /* kHz - uV - OPPs unknown yet */ @@ -78,6 +78,7 @@ clocks = <&cpg CPG_CORE R8A7743_CLK_Z>; clock-latency = <300000>; /* 300 us */ power-domains = <&sysc R8A7743_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; /* kHz - uV - OPPs unknown yet */ @@ -702,6 +703,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7744.dtsi b/arch/arm/boot/dts/r8a7744.dtsi index ace20861c0c4..8419683a9d83 100644 --- a/arch/arm/boot/dts/r8a7744.dtsi +++ b/arch/arm/boot/dts/r8a7744.dtsi @@ -49,7 +49,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -59,6 +58,7 @@ clocks = <&cpg CPG_CORE R8A7744_CLK_Z>; clock-latency = <300000>; /* 300 us */ power-domains = <&sysc R8A7744_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; /* kHz - uV - OPPs unknown yet */ @@ -78,6 +78,7 @@ clocks = <&cpg CPG_CORE R8A7744_CLK_Z>; clock-latency = <300000>; /* 300 us */ power-domains = <&sysc R8A7744_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; /* kHz - uV - OPPs unknown yet */ @@ -702,6 +703,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7744_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7745.dtsi b/arch/arm/boot/dts/r8a7745.dtsi index be33bdabe452..f877c51f769c 100644 --- a/arch/arm/boot/dts/r8a7745.dtsi +++ b/arch/arm/boot/dts/r8a7745.dtsi @@ -64,7 +64,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -73,6 +72,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7745_CLK_Z2>; power-domains = <&sysc R8A7745_PD_CA7_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -83,6 +83,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7745_CLK_Z2>; power-domains = <&sysc R8A7745_PD_CA7_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -645,6 +646,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a77470.dtsi b/arch/arm/boot/dts/r8a77470.dtsi index a1d7f6e7a2e3..13ef1e9bf4d5 100644 --- a/arch/arm/boot/dts/r8a77470.dtsi +++ b/arch/arm/boot/dts/r8a77470.dtsi @@ -25,7 +25,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -34,6 +33,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A77470_CLK_Z2>; power-domains = <&sysc R8A77470_PD_CA7_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -44,6 +44,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A77470_CLK_Z2>; power-domains = <&sysc R8A77470_PD_CA7_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -537,6 +538,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi index c9f8735860bf..95efbafb0b70 100644 --- a/arch/arm/boot/dts/r8a7778.dtsi +++ b/arch/arm/boot/dts/r8a7778.dtsi @@ -166,6 +166,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7778_CLK_I2C1>; power-domains = <&cpg_clocks>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; @@ -177,6 +178,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7778_CLK_I2C2>; power-domains = <&cpg_clocks>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; @@ -188,6 +190,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7778_CLK_I2C3>; power-domains = <&cpg_clocks>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts index d2240b89ee52..465845323495 100644 --- a/arch/arm/boot/dts/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/r8a7779-marzen.dts @@ -145,7 +145,7 @@ status = "okay"; clocks = <&mstp1_clks R8A7779_CLK_DU>, <&x3_clk>; - clock-names = "du", "dclkin.0"; + clock-names = "du.0", "dclkin.0"; ports { port@0 { diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index 74d7e9084eab..39fc58f32df6 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -198,6 +198,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7779_CLK_I2C1>; power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; @@ -209,6 +210,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7779_CLK_I2C2>; power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; @@ -220,6 +222,7 @@ interrupts = ; clocks = <&mstp0_clks R8A7779_CLK_I2C3>; power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; + i2c-scl-internal-delay-ns = <5>; status = "disabled"; }; @@ -463,6 +466,7 @@ reg = <0xfff80000 0x40000>; interrupts = ; clocks = <&mstp1_clks R8A7779_CLK_DU>; + clock-names = "du.0"; power-domains = <&sysc R8A7779_PD_ALWAYS_ON>; status = "disabled"; diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index 2dad0742d2ba..fa6d986b5d46 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -81,6 +81,9 @@ keyboard { compatible = "gpio-keys"; + pinctrl-0 = <&keyboard_pins>; + pinctrl-names = "default"; + one { linux,code = ; label = "SW2-1"; @@ -659,6 +662,11 @@ groups = "audio_clk_a"; function = "audio_clk"; }; + + keyboard_pins: keyboard { + pins = "GP_1_14", "GP_1_24", "GP_1_26", "GP_1_28"; + bias-pull-up; + }; }; ðer { diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index de29394eed63..ed6dd4fcc503 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -69,7 +69,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -78,6 +77,7 @@ clock-frequency = <1300000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z>; power-domains = <&sysc R8A7790_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -99,6 +99,7 @@ clock-frequency = <1300000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z>; power-domains = <&sysc R8A7790_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -120,6 +121,7 @@ clock-frequency = <1300000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z>; power-domains = <&sysc R8A7790_PD_CA15_CPU2>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -141,6 +143,7 @@ clock-frequency = <1300000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z>; power-domains = <&sysc R8A7790_PD_CA15_CPU3>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; capacity-dmips-mhz = <1024>; voltage-tolerance = <1>; /* 1% */ @@ -162,6 +165,7 @@ clock-frequency = <780000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z2>; power-domains = <&sysc R8A7790_PD_CA7_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; capacity-dmips-mhz = <539>; }; @@ -173,6 +177,7 @@ clock-frequency = <780000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z2>; power-domains = <&sysc R8A7790_PD_CA7_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; capacity-dmips-mhz = <539>; }; @@ -184,6 +189,7 @@ clock-frequency = <780000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z2>; power-domains = <&sysc R8A7790_PD_CA7_CPU2>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; capacity-dmips-mhz = <539>; }; @@ -195,6 +201,7 @@ clock-frequency = <780000000>; clocks = <&cpg CPG_CORE R8A7790_CLK_Z2>; power-domains = <&sysc R8A7790_PD_CA7_CPU3>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; capacity-dmips-mhz = <539>; }; @@ -768,6 +775,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 61e881bbbf6e..2a8b6fd9095c 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -81,7 +81,7 @@ keyboard { compatible = "gpio-keys"; - pinctrl-0 = <&sw2_pins>; + pinctrl-0 = <&keyboard_pins>; pinctrl-names = "default"; key-1 { @@ -622,7 +622,7 @@ function = "audio_clk"; }; - sw2_pins: sw2 { + keyboard_pins: keyboard { pins = "GP_5_0", "GP_5_1", "GP_5_2", "GP_5_3"; bias-pull-up; }; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 9d8320f71a6a..0ccc162d3c2c 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -68,7 +68,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -77,6 +76,7 @@ clock-frequency = <1500000000>; clocks = <&cpg CPG_CORE R8A7791_CLK_Z>; power-domains = <&sysc R8A7791_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; voltage-tolerance = <1>; /* 1% */ clock-latency = <300000>; /* 300 us */ @@ -97,6 +97,7 @@ clock-frequency = <1500000000>; clocks = <&cpg CPG_CORE R8A7791_CLK_Z>; power-domains = <&sysc R8A7791_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; voltage-tolerance = <1>; /* 1% */ clock-latency = <300000>; /* 300 us */ @@ -728,6 +729,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7792-blanche.dts b/arch/arm/boot/dts/r8a7792-blanche.dts index c100ae903a46..62aa9f61321b 100644 --- a/arch/arm/boot/dts/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/r8a7792-blanche.dts @@ -112,6 +112,9 @@ keyboard { compatible = "gpio-keys"; + pinctrl-0 = <&keyboard_pins>; + pinctrl-names = "default"; + key-1 { linux,code = ; label = "SW2-1"; @@ -235,6 +238,11 @@ function = "du1"; }; + keyboard_pins: keyboard { + pins = "GP_3_10", "GP_3_11", "GP_3_12", "GP_3_15", "GP_11_02"; + bias-pull-up; + }; + pmic_irq_pins: pmicirq { groups = "intc_irq2"; function = "intc"; diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi index 253e8bf643d1..9cdb73894ac2 100644 --- a/arch/arm/boot/dts/r8a7792.dtsi +++ b/arch/arm/boot/dts/r8a7792.dtsi @@ -45,7 +45,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -54,6 +53,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7792_CLK_Z>; power-domains = <&sysc R8A7792_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; }; @@ -64,6 +64,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7792_CLK_Z>; power-domains = <&sysc R8A7792_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA15>; }; @@ -537,6 +538,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7792_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts index 87fa57a99399..479e0fdf0c37 100644 --- a/arch/arm/boot/dts/r8a7793-gose.dts +++ b/arch/arm/boot/dts/r8a7793-gose.dts @@ -64,9 +64,12 @@ reg = <0 0x40000000 0 0x40000000>; }; - gpio-keys { + keyboard { compatible = "gpio-keys"; + pinctrl-0 = <&keyboard_pins>; + pinctrl-names = "default"; + key-1 { gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; linux,code = ; @@ -567,6 +570,11 @@ function = "audio_clk"; }; + keyboard_pins: keyboard { + pins = "GP_5_0", "GP_5_1", "GP_5_2", "GP_5_3"; + bias-pull-up; + }; + vin0_pins: vin0 { groups = "vin0_data24", "vin0_sync", "vin0_clkenb", "vin0_clk"; function = "vin0"; diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index 6d74475030ed..dea4b1e108af 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -60,7 +60,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -69,6 +68,7 @@ clock-frequency = <1500000000>; clocks = <&cpg CPG_CORE R8A7793_CLK_Z>; power-domains = <&sysc R8A7793_PD_CA15_CPU0>; + enable-method = "renesas,apmu"; voltage-tolerance = <1>; /* 1% */ clock-latency = <300000>; /* 300 us */ @@ -89,6 +89,7 @@ clock-frequency = <1500000000>; clocks = <&cpg CPG_CORE R8A7793_CLK_Z>; power-domains = <&sysc R8A7793_PD_CA15_CPU1>; + enable-method = "renesas,apmu"; voltage-tolerance = <1>; /* 1% */ clock-latency = <300000>; /* 300 us */ diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts index f9dba5688d3f..f330d796a772 100644 --- a/arch/arm/boot/dts/r8a7794-alt.dts +++ b/arch/arm/boot/dts/r8a7794-alt.dts @@ -8,6 +8,7 @@ /dts-v1/; #include "r8a7794.dtsi" #include +#include / { model = "Alt"; @@ -94,6 +95,42 @@ #size-cells = <1>; }; + keyboard { + compatible = "gpio-keys"; + + pinctrl-0 = <&keyboard_pins>; + pinctrl-names = "default"; + + one { + linux,code = ; + label = "SW2-1"; + wakeup-source; + debounce-interval = <20>; + gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; + }; + two { + linux,code = ; + label = "SW2-2"; + wakeup-source; + debounce-interval = <20>; + gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; + }; + three { + linux,code = ; + label = "SW2-3"; + wakeup-source; + debounce-interval = <20>; + gpios = <&gpio3 11 GPIO_ACTIVE_LOW>; + }; + four { + linux,code = ; + label = "SW2-4"; + wakeup-source; + debounce-interval = <20>; + gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; + }; + }; + vga-encoder { compatible = "adi,adv7123"; @@ -319,6 +356,11 @@ groups = "usb1"; function = "usb1"; }; + + keyboard_pins: keyboard { + pins = "GP_3_9", "GP_3_10", "GP_3_11", "GP_3_12"; + bias-pull-up; + }; }; &cmt0 { diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts index eb89a27a6ed0..cafa3046daa4 100644 --- a/arch/arm/boot/dts/r8a7794-silk.dts +++ b/arch/arm/boot/dts/r8a7794-silk.dts @@ -45,9 +45,12 @@ reg = <0 0x40000000 0 0x40000000>; }; - gpio-keys { + keyboard { compatible = "gpio-keys"; + pinctrl-0 = <&keyboard_pins>; + pinctrl-names = "default"; + key-3 { gpios = <&gpio5 10 GPIO_ACTIVE_LOW>; linux,code = ; @@ -358,6 +361,11 @@ function = "du1"; }; + keyboard_pins: keyboard { + pins = "GP_3_9", "GP_3_10", "GP_3_11", "GP_3_12"; + bias-pull-up; + }; + ssi_pins: sound { groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data"; function = "ssi"; diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 330dc516ecd1..eac9ed8df0be 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -62,7 +62,6 @@ cpus { #address-cells = <1>; #size-cells = <0>; - enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -71,6 +70,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7794_CLK_Z2>; power-domains = <&sysc R8A7794_PD_CA7_CPU0>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -81,6 +81,7 @@ clock-frequency = <1000000000>; clocks = <&cpg CPG_CORE R8A7794_CLK_Z2>; power-domains = <&sysc R8A7794_PD_CA7_CPU1>; + enable-method = "renesas,apmu"; next-level-cache = <&L2_CA7>; }; @@ -598,6 +599,7 @@ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>; interrupts = ; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7794_PD_ALWAYS_ON>; resets = <&cpg 812>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/rk3036-kylin.dts b/arch/arm/boot/dts/rk3036-kylin.dts index 7154b827ea2f..e817eba8c622 100644 --- a/arch/arm/boot/dts/rk3036-kylin.dts +++ b/arch/arm/boot/dts/rk3036-kylin.dts @@ -390,7 +390,7 @@ }; }; - sleep { + suspend { global_pwroff: global-pwroff { rockchip,pins = <2 RK_PA7 1 &pcfg_pull_none>; }; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index e24230d50a78..ffa9bc7ed3d0 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include / { #address-cells = <1>; @@ -111,10 +112,32 @@ assigned-clock-rates = <100000000>; clocks = <&cru SCLK_GPU>, <&cru SCLK_GPU>; clock-names = "bus", "core"; + power-domains = <&power RK3036_PD_GPU>; resets = <&cru SRST_GPU>; status = "disabled"; }; + vpu: video-codec@10108000 { + compatible = "rockchip,rk3036-vpu"; + reg = <0x10108000 0x800>; + interrupts = ; + interrupt-names = "vdpu"; + clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; + clock-names = "aclk", "hclk"; + iommus = <&vpu_mmu>; + power-domains = <&power RK3036_PD_VPU>; + }; + + vpu_mmu: iommu@10108800 { + compatible = "rockchip,iommu"; + reg = <0x10108800 0x100>; + interrupts = ; + clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; + clock-names = "aclk", "iface"; + power-domains = <&power RK3036_PD_VPU>; + #iommu-cells = <0>; + }; + vop: vop@10118000 { compatible = "rockchip,rk3036-vop"; reg = <0x10118000 0x19c>; @@ -124,6 +147,7 @@ resets = <&cru SRST_LCDC1_A>, <&cru SRST_LCDC1_H>, <&cru SRST_LCDC1_D>; reset-names = "axi", "ahb", "dclk"; iommus = <&vop_mmu>; + power-domains = <&power RK3036_PD_VIO>; status = "disabled"; vop_out: port { @@ -140,13 +164,28 @@ compatible = "rockchip,iommu"; reg = <0x10118300 0x100>; interrupts = ; - interrupt-names = "vop_mmu"; clocks = <&cru ACLK_LCDC>, <&cru HCLK_LCDC>; clock-names = "aclk", "iface"; + power-domains = <&power RK3036_PD_VIO>; #iommu-cells = <0>; status = "disabled"; }; + qos_gpu: qos@1012d000 { + compatible = "rockchip,rk3036-qos", "syscon"; + reg = <0x1012d000 0x20>; + }; + + qos_vpu: qos@1012e000 { + compatible = "rockchip,rk3036-qos", "syscon"; + reg = <0x1012e000 0x20>; + }; + + qos_vio: qos@1012f000 { + compatible = "rockchip,rk3036-qos", "syscon"; + reg = <0x1012f000 0x20>; + }; + gic: interrupt-controller@10139000 { compatible = "arm,gic-400"; interrupt-controller; @@ -302,6 +341,37 @@ compatible = "rockchip,rk3036-grf", "syscon", "simple-mfd"; reg = <0x20008000 0x1000>; + power: power-controller { + compatible = "rockchip,rk3036-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3036_PD_VIO { + reg = ; + clocks = <&cru ACLK_LCDC>, + <&cru HCLK_LCDC>, + <&cru SCLK_LCDC>; + pm_qos = <&qos_vio>; + #power-domain-cells = <0>; + }; + + power-domain@RK3036_PD_VPU { + reg = ; + clocks = <&cru ACLK_VCODEC>, + <&cru HCLK_VCODEC>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3036_PD_GPU { + reg = ; + clocks = <&cru SCLK_GPU>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + }; + reboot-mode { compatible = "syscon-reboot-mode"; offset = <0x1d8>; diff --git a/arch/arm/boot/dts/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rk3066a-bqcurie2.dts index eba7a1344976..390aa33cd55a 100644 --- a/arch/arm/boot/dts/rk3066a-bqcurie2.dts +++ b/arch/arm/boot/dts/rk3066a-bqcurie2.dts @@ -12,6 +12,11 @@ model = "bq Curie 2"; compatible = "mundoreader,bq-curie2", "rockchip,rk3066a"; + aliases { + mmc0 = &mmc0; + mmc1 = &mmc1; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; diff --git a/arch/arm/boot/dts/rk3066a-marsboard.dts b/arch/arm/boot/dts/rk3066a-marsboard.dts index 6b121658d93c..a66d915aa0f6 100644 --- a/arch/arm/boot/dts/rk3066a-marsboard.dts +++ b/arch/arm/boot/dts/rk3066a-marsboard.dts @@ -10,6 +10,10 @@ model = "MarsBoard RK3066"; compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a"; + aliases { + mmc0 = &mmc0; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; diff --git a/arch/arm/boot/dts/rk3066a-mk808.dts b/arch/arm/boot/dts/rk3066a-mk808.dts index eed9e60cffa2..9790bc63b50a 100644 --- a/arch/arm/boot/dts/rk3066a-mk808.dts +++ b/arch/arm/boot/dts/rk3066a-mk808.dts @@ -10,6 +10,11 @@ model = "Rikomagic MK808"; compatible = "rikomagic,mk808", "rockchip,rk3066a"; + aliases { + mmc0 = &mmc0; + mmc1 = &mmc1; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm/boot/dts/rk3066a-rayeager.dts b/arch/arm/boot/dts/rk3066a-rayeager.dts index 309518403d86..12b2e59aebc4 100644 --- a/arch/arm/boot/dts/rk3066a-rayeager.dts +++ b/arch/arm/boot/dts/rk3066a-rayeager.dts @@ -11,6 +11,12 @@ model = "Rayeager PX2"; compatible = "chipspark,rayeager-px2", "rockchip,rk3066a"; + aliases { + mmc0 = &mmc0; + mmc1 = &mmc1; + mmc2 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x40000000>; @@ -58,7 +64,7 @@ }; /* input for 5V_STDBY is VSYS or DC5V, selectable by jumper J4 */ - vcc_stdby: 5v-stdby-regulator { + vcc_stdby: stdby-regulator { compatible = "regulator-fixed"; regulator-name = "5v_stdby"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi index 252750c97f97..f5a665b5d209 100644 --- a/arch/arm/boot/dts/rk3066a.dtsi +++ b/arch/arm/boot/dts/rk3066a.dtsi @@ -217,7 +217,7 @@ <150000000>, <75000000>; }; - timer@2000e000 { + timer2: timer@2000e000 { compatible = "snps,dw-apb-timer-osc"; reg = <0x2000e000 0x100>; interrupts = ; @@ -238,7 +238,7 @@ }; }; - timer@20038000 { + timer0: timer@20038000 { compatible = "snps,dw-apb-timer-osc"; reg = <0x20038000 0x100>; interrupts = ; @@ -246,7 +246,7 @@ clock-names = "timer", "pclk"; }; - timer@2003a000 { + timer1: timer@2003a000 { compatible = "snps,dw-apb-timer-osc"; reg = <0x2003a000 0x100>; interrupts = ; @@ -266,30 +266,6 @@ status = "disabled"; }; - usbphy: phy { - compatible = "rockchip,rk3066a-usb-phy", "rockchip,rk3288-usb-phy"; - rockchip,grf = <&grf>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - usbphy0: usb-phy@17c { - #phy-cells = <0>; - reg = <0x17c>; - clocks = <&cru SCLK_OTGPHY0>; - clock-names = "phyclk"; - #clock-cells = <0>; - }; - - usbphy1: usb-phy@188 { - #phy-cells = <0>; - reg = <0x188>; - clocks = <&cru SCLK_OTGPHY1>; - clock-names = "phyclk"; - #clock-cells = <0>; - }; - }; - pinctrl: pinctrl { compatible = "rockchip,rk3066a-pinctrl"; rockchip,grf = <&grf>; @@ -702,6 +678,34 @@ power-domains = <&power RK3066_PD_GPU>; }; +&grf { + compatible = "rockchip,rk3066-grf", "syscon", "simple-mfd"; + + usbphy: usbphy { + compatible = "rockchip,rk3066a-usb-phy", + "rockchip,rk3288-usb-phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + usbphy0: usb-phy@17c { + reg = <0x17c>; + clocks = <&cru SCLK_OTGPHY0>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + + usbphy1: usb-phy@188 { + reg = <0x188>; + clocks = <&cru SCLK_OTGPHY1>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + }; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_xfer>; @@ -755,7 +759,7 @@ #address-cells = <1>; #size-cells = <0>; - pd_vio@RK3066_PD_VIO { + power-domain@RK3066_PD_VIO { reg = ; clocks = <&cru ACLK_LCDC0>, <&cru ACLK_LCDC1>, @@ -780,21 +784,24 @@ <&qos_cif1>, <&qos_ipp>, <&qos_rga>; + #power-domain-cells = <0>; }; - pd_video@RK3066_PD_VIDEO { + power-domain@RK3066_PD_VIDEO { reg = ; clocks = <&cru ACLK_VDPU>, <&cru ACLK_VEPU>, <&cru HCLK_VDPU>, <&cru HCLK_VEPU>; pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; }; - pd_gpu@RK3066_PD_GPU { + power-domain@RK3066_PD_GPU { reg = ; clocks = <&cru ACLK_GPU>; pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; }; }; }; @@ -861,6 +868,10 @@ pinctrl-0 = <&uart3_xfer>; }; +&vpu { + power-domains = <&power RK3066_PD_VIDEO>; +}; + &wdt { compatible = "rockchip,rk3066-wdt", "snps,dw-wdt"; }; diff --git a/arch/arm/boot/dts/rk3188-bqedison2qc.dts b/arch/arm/boot/dts/rk3188-bqedison2qc.dts index 66a0ff196eb1..85d3fce0142f 100644 --- a/arch/arm/boot/dts/rk3188-bqedison2qc.dts +++ b/arch/arm/boot/dts/rk3188-bqedison2qc.dts @@ -13,6 +13,12 @@ model = "BQ Edison2 Quad-Core"; compatible = "mundoreader,bq-edison2qc", "rockchip,rk3188"; + aliases { + mmc0 = &mmc0; + mmc1 = &mmc1; + mmc2 = &emmc; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x80000000>; diff --git a/arch/arm/boot/dts/rk3188-px3-evb.dts b/arch/arm/boot/dts/rk3188-px3-evb.dts index c32e1d441cf7..39c60426c9c9 100644 --- a/arch/arm/boot/dts/rk3188-px3-evb.dts +++ b/arch/arm/boot/dts/rk3188-px3-evb.dts @@ -11,6 +11,11 @@ model = "Rockchip PX3-EVB"; compatible = "rockchip,px3-evb", "rockchip,px3", "rockchip,rk3188"; + aliases { + mmc0 = &mmc0; + mmc1 = &emmc; + }; + chosen { stdout-path = "serial2:115200n8"; }; diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts index b0fef82c0a71..36c0945f43b2 100644 --- a/arch/arm/boot/dts/rk3188-radxarock.dts +++ b/arch/arm/boot/dts/rk3188-radxarock.dts @@ -11,6 +11,10 @@ model = "Radxa Rock"; compatible = "radxa,rock", "rockchip,rk3188"; + aliases { + mmc0 = &mmc0; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x80000000>; diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 2298a8d840ba..793a1b9117fe 100644 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -150,16 +150,16 @@ compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer"; reg = <0x2000e000 0x20>; interrupts = ; - clocks = <&cru SCLK_TIMER3>, <&cru PCLK_TIMER3>; - clock-names = "timer", "pclk"; + clocks = <&cru PCLK_TIMER3>, <&cru SCLK_TIMER3>; + clock-names = "pclk", "timer"; }; timer6: timer@200380a0 { compatible = "rockchip,rk3188-timer", "rockchip,rk3288-timer"; reg = <0x200380a0 0x20>; interrupts = ; - clocks = <&cru SCLK_TIMER6>, <&cru PCLK_TIMER0>; - clock-names = "timer", "pclk"; + clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER6>; + clock-names = "pclk", "timer"; }; i2s0: i2s@1011a000 { @@ -214,30 +214,6 @@ }; }; - usbphy: phy { - compatible = "rockchip,rk3188-usb-phy", "rockchip,rk3288-usb-phy"; - rockchip,grf = <&grf>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - usbphy0: usb-phy@10c { - #phy-cells = <0>; - reg = <0x10c>; - clocks = <&cru SCLK_OTGPHY0>; - clock-names = "phyclk"; - #clock-cells = <0>; - }; - - usbphy1: usb-phy@11c { - #phy-cells = <0>; - reg = <0x11c>; - clocks = <&cru SCLK_OTGPHY1>; - clock-names = "phyclk"; - #clock-cells = <0>; - }; - }; - pinctrl: pinctrl { compatible = "rockchip,rk3188-pinctrl"; rockchip,grf = <&grf>; @@ -662,6 +638,34 @@ power-domains = <&power RK3188_PD_GPU>; }; +&grf{ + compatible = "rockchip,rk3188-grf", "syscon", "simple-mfd"; + + usbphy: usbphy { + compatible = "rockchip,rk3188-usb-phy", + "rockchip,rk3288-usb-phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + usbphy0: usb-phy@10c { + reg = <0x10c>; + clocks = <&cru SCLK_OTGPHY0>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + + usbphy1: usb-phy@11c { + reg = <0x11c>; + clocks = <&cru SCLK_OTGPHY1>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + }; +}; + &i2c0 { compatible = "rockchip,rk3188-i2c"; pinctrl-names = "default"; @@ -699,7 +703,7 @@ #address-cells = <1>; #size-cells = <0>; - pd_vio@RK3188_PD_VIO { + power-domain@RK3188_PD_VIO { reg = ; clocks = <&cru ACLK_LCDC0>, <&cru ACLK_LCDC1>, @@ -719,21 +723,24 @@ <&qos_cif0>, <&qos_ipp>, <&qos_rga>; + #power-domain-cells = <0>; }; - pd_video@RK3188_PD_VIDEO { + power-domain@RK3188_PD_VIDEO { reg = ; clocks = <&cru ACLK_VDPU>, <&cru ACLK_VEPU>, <&cru HCLK_VDPU>, <&cru HCLK_VEPU>; pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; }; - pd_gpu@RK3188_PD_GPU { + power-domain@RK3188_PD_GPU { reg = ; clocks = <&cru ACLK_GPU>; pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; }; }; }; @@ -794,6 +801,11 @@ pinctrl-0 = <&uart3_xfer>; }; +&vpu { + compatible = "rockchip,rk3188-vpu", "rockchip,rk3066-vpu"; + power-domains = <&power RK3188_PD_VIDEO>; +}; + &wdt { compatible = "rockchip,rk3188-wdt", "snps,dw-wdt"; }; diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index 208f21245095..75af99c76d7e 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include / { #address-cells = <1>; @@ -190,7 +191,65 @@ status = "disabled"; }; - u2phy0: usb2-phy@760 { + power: power-controller { + compatible = "rockchip,rk3228-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3228_PD_VIO { + reg = ; + clocks = <&cru ACLK_HDCP>, + <&cru SCLK_HDCP>, + <&cru ACLK_IEP>, + <&cru HCLK_IEP>, + <&cru ACLK_RGA>, + <&cru HCLK_RGA>, + <&cru SCLK_RGA>; + pm_qos = <&qos_hdcp>, + <&qos_iep>, + <&qos_rga_r>, + <&qos_rga_w>; + #power-domain-cells = <0>; + }; + + power-domain@RK3228_PD_VOP { + reg = ; + clocks =<&cru ACLK_VOP>, + <&cru DCLK_VOP>, + <&cru HCLK_VOP>; + pm_qos = <&qos_vop>; + #power-domain-cells = <0>; + }; + + power-domain@RK3228_PD_VPU { + reg = ; + clocks = <&cru ACLK_VPU>, + <&cru HCLK_VPU>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3228_PD_RKVDEC { + reg = ; + clocks = <&cru ACLK_RKVDEC>, + <&cru HCLK_RKVDEC>, + <&cru SCLK_VDEC_CABAC>, + <&cru SCLK_VDEC_CORE>; + pm_qos = <&qos_rkvdec_r>, + <&qos_rkvdec_w>; + #power-domain-cells = <0>; + }; + + power-domain@RK3228_PD_GPU { + reg = ; + clocks = <&cru ACLK_GPU>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + }; + + u2phy0: usb2phy@760 { compatible = "rockchip,rk3228-usb2phy"; reg = <0x0760 0x0c>; clocks = <&cru SCLK_OTGPHY0>; @@ -217,7 +276,7 @@ }; }; - u2phy1: usb2-phy@800 { + u2phy1: usb2phy@800 { compatible = "rockchip,rk3228-usb2phy"; reg = <0x0800 0x0c>; clocks = <&cru SCLK_OTGPHY1>; @@ -379,7 +438,6 @@ reg = <0x110b0000 0x10>; #pwm-cells = <3>; clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; pinctrl-names = "default"; pinctrl-0 = <&pwm0_pin>; status = "disabled"; @@ -390,7 +448,6 @@ reg = <0x110b0010 0x10>; #pwm-cells = <3>; clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; pinctrl-names = "default"; pinctrl-0 = <&pwm1_pin>; status = "disabled"; @@ -401,7 +458,6 @@ reg = <0x110b0020 0x10>; #pwm-cells = <3>; clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; pinctrl-names = "default"; pinctrl-0 = <&pwm2_pin>; status = "disabled"; @@ -412,7 +468,6 @@ reg = <0x110b0030 0x10>; #pwm-cells = <2>; clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; pinctrl-names = "default"; pinctrl-0 = <&pwm3_pin>; status = "disabled"; @@ -517,7 +572,7 @@ pinctrl-0 = <&otp_pin>; pinctrl-1 = <&otp_out>; pinctrl-2 = <&otp_pin>; - #thermal-sensor-cells = <0>; + #thermal-sensor-cells = <1>; rockchip,hw-tshut-temp = <95000>; status = "disabled"; }; @@ -550,30 +605,54 @@ "ppmmu1"; clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; clock-names = "bus", "core"; + power-domains = <&power RK3228_PD_GPU>; resets = <&cru SRST_GPU_A>; status = "disabled"; }; + vpu: video-codec@20020000 { + compatible = "rockchip,rk3228-vpu", "rockchip,rk3399-vpu"; + reg = <0x20020000 0x800>; + interrupts = , + ; + interrupt-names = "vepu", "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + iommus = <&vpu_mmu>; + power-domains = <&power RK3228_PD_VPU>; + }; + vpu_mmu: iommu@20020800 { compatible = "rockchip,iommu"; reg = <0x20020800 0x100>; interrupts = ; - interrupt-names = "vpu_mmu"; clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; clock-names = "aclk", "iface"; - iommu-cells = <0>; - status = "disabled"; + power-domains = <&power RK3228_PD_VPU>; + #iommu-cells = <0>; + }; + + vdec: video-codec@20030000 { + compatible = "rockchip,rk3228-vdec", "rockchip,rk3399-vdec"; + reg = <0x20030000 0x480>; + interrupts = ; + clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>, + <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; + clock-names = "axi", "ahb", "cabac", "core"; + assigned-clocks = <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; + assigned-clock-rates = <300000000>, <300000000>; + iommus = <&vdec_mmu>; + power-domains = <&power RK3228_PD_RKVDEC>; }; vdec_mmu: iommu@20030480 { compatible = "rockchip,iommu"; reg = <0x20030480 0x40>, <0x200304c0 0x40>; interrupts = ; - interrupt-names = "vdec_mmu"; clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; clock-names = "aclk", "iface"; - iommu-cells = <0>; - status = "disabled"; + power-domains = <&power RK3228_PD_RKVDEC>; + #iommu-cells = <0>; }; vop: vop@20050000 { @@ -585,6 +664,7 @@ resets = <&cru SRST_VOP_A>, <&cru SRST_VOP_H>, <&cru SRST_VOP_D>; reset-names = "axi", "ahb", "dclk"; iommus = <&vop_mmu>; + power-domains = <&power RK3228_PD_VOP>; status = "disabled"; vop_out: port { @@ -602,9 +682,9 @@ compatible = "rockchip,iommu"; reg = <0x20053f00 0x100>; interrupts = ; - interrupt-names = "vop_mmu"; clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; clock-names = "aclk", "iface"; + power-domains = <&power RK3228_PD_VOP>; #iommu-cells = <0>; status = "disabled"; }; @@ -615,6 +695,7 @@ interrupts = ; clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>; clock-names = "aclk", "hclk", "sclk"; + power-domains = <&power RK3228_PD_VIO>; resets = <&cru SRST_RGA>, <&cru SRST_RGA_A>, <&cru SRST_RGA_H>; reset-names = "core", "axi", "ahb"; }; @@ -623,10 +704,10 @@ compatible = "rockchip,iommu"; reg = <0x20070800 0x100>; interrupts = ; - interrupt-names = "iep_mmu"; clocks = <&cru ACLK_IEP>, <&cru HCLK_IEP>; clock-names = "aclk", "iface"; - iommu-cells = <0>; + power-domains = <&power RK3228_PD_VIO>; + #iommu-cells = <0>; status = "disabled"; }; @@ -800,6 +881,51 @@ status = "disabled"; }; + qos_iep: qos@31030080 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31030080 0x20>; + }; + + qos_rga_w: qos@31030100 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31030100 0x20>; + }; + + qos_hdcp: qos@31030180 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31030180 0x20>; + }; + + qos_rga_r: qos@31030200 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31030200 0x20>; + }; + + qos_vpu: qos@31040000 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31040000 0x20>; + }; + + qos_gpu: qos@31050000 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31050000 0x20>; + }; + + qos_vop: qos@31060000 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31060000 0x20>; + }; + + qos_rkvdec_r: qos@31070000 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31070000 0x20>; + }; + + qos_rkvdec_w: qos@31070080 { + compatible = "rockchip,rk3228-qos", "syscon"; + reg = <0x31070080 0x20>; + }; + gic: interrupt-controller@32010000 { compatible = "arm,gic-400"; interrupt-controller; diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi index 44bb5e6f83b1..76363b8afcb9 100644 --- a/arch/arm/boot/dts/rk3288-rock2-som.dtsi +++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi @@ -218,7 +218,7 @@ flash0-supply = <&vcc_flash>; flash1-supply = <&vccio_pmu>; gpio30-supply = <&vccio_pmu>; - gpio1830 = <&vcc_io>; + gpio1830-supply = <&vcc_io>; lcdc-supply = <&vcc_io>; sdcard-supply = <&vccio_sd>; wifi-supply = <&vcc_18>; diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts index aa50f8ed4ca0..b156a83eb7d7 100644 --- a/arch/arm/boot/dts/rk3288-vyasa.dts +++ b/arch/arm/boot/dts/rk3288-vyasa.dts @@ -379,10 +379,10 @@ audio-supply = <&vcc_18>; bb-supply = <&vcc_io>; dvp-supply = <&vcc_io>; - flash0-suuply = <&vcc_18>; + flash0-supply = <&vcc_18>; flash1-supply = <&vcc_lan>; gpio30-supply = <&vcc_io>; - gpio1830 = <&vcc_io>; + gpio1830-supply = <&vcc_io>; lcdc-supply = <&vcc_io>; sdcard-supply = <&vccio_sd>; wifi-supply = <&vcc_18>; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 05557ad02b33..9c5a7791a1ab 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -196,8 +196,8 @@ compatible = "rockchip,rk3288-timer"; reg = <0x0 0xff810000 0x0 0x20>; interrupts = ; - clocks = <&xin24m>, <&cru PCLK_TIMER>; - clock-names = "timer", "pclk"; + clocks = <&cru PCLK_TIMER>, <&xin24m>; + clock-names = "pclk", "timer"; }; display-subsystem { @@ -765,7 +765,7 @@ * *_HDMI HDMI * *_MIPI_* MIPI */ - pd_vio@RK3288_PD_VIO { + power-domain@RK3288_PD_VIO { reg = ; clocks = <&cru ACLK_IEP>, <&cru ACLK_ISP>, @@ -801,19 +801,21 @@ <&qos_vio2_rga_r>, <&qos_vio2_rga_w>, <&qos_vio1_isp_r>; + #power-domain-cells = <0>; }; /* * Note: The following 3 are HEVC(H.265) clocks, * and on the ACLK_HEVC_NIU (NOC). */ - pd_hevc@RK3288_PD_HEVC { + power-domain@RK3288_PD_HEVC { reg = ; clocks = <&cru ACLK_HEVC>, <&cru SCLK_HEVC_CABAC>, <&cru SCLK_HEVC_CORE>; pm_qos = <&qos_hevc_r>, <&qos_hevc_w>; + #power-domain-cells = <0>; }; /* @@ -821,22 +823,24 @@ * (video endecoder & decoder) clocks that on the * ACLK_VCODEC_NIU and HCLK_VCODEC_NIU (NOC). */ - pd_video@RK3288_PD_VIDEO { + power-domain@RK3288_PD_VIDEO { reg = ; clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; pm_qos = <&qos_video>; + #power-domain-cells = <0>; }; /* * Note: ACLK_GPU is the GPU clock, * and on the ACLK_GPU_NIU (NOC). */ - pd_gpu@RK3288_PD_GPU { + power-domain@RK3288_PD_GPU { reg = ; clocks = <&cru ACLK_GPU>; pm_qos = <&qos_gpu_r>, <&qos_gpu_w>; + #power-domain-cells = <0>; }; }; @@ -1582,7 +1586,7 @@ drive-strength = <12>; }; - sleep { + suspend { global_pwroff: global-pwroff { rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>; }; diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi index 755c946f11de..616a828e0c6e 100644 --- a/arch/arm/boot/dts/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rk3xxx.dtsi @@ -21,9 +21,6 @@ i2c2 = &i2c2; i2c3 = &i2c3; i2c4 = &i2c4; - mshc0 = &emmc; - mshc1 = &mmc0; - mshc2 = &mmc1; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -50,6 +47,18 @@ status = "disabled"; }; + vpu: video-codec@10104000 { + compatible = "rockchip,rk3066-vpu"; + reg = <0x10104000 0x800>; + interrupts = , + ; + interrupt-names = "vepu", "vdpu"; + clocks = <&cru ACLK_VDPU>, <&cru HCLK_VDPU>, + <&cru ACLK_VEPU>, <&cru HCLK_VEPU>; + clock-names = "aclk_vdpu", "hclk_vdpu", + "aclk_vepu", "hclk_vepu"; + }; + L2: cache-controller@10138000 { compatible = "arm,pl310-cache"; reg = <0x10138000 0x1000>; @@ -256,7 +265,7 @@ }; grf: grf@20008000 { - compatible = "syscon"; + compatible = "syscon", "simple-mfd"; reg = <0x20008000 0x200>; }; diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi index 884872ca5207..9bd0acf3b708 100644 --- a/arch/arm/boot/dts/rv1108.dtsi +++ b/arch/arm/boot/dts/rv1108.dtsi @@ -265,7 +265,7 @@ #address-cells = <1>; #size-cells = <1>; - u2phy: usb2-phy@100 { + u2phy: usb2phy@100 { compatible = "rockchip,rv1108-usb2phy"; reg = <0x100 0x0c>; clocks = <&cru SCLK_USBPHY>; diff --git a/arch/arm/boot/dts/s5pv210-goni.dts b/arch/arm/boot/dts/s5pv210-goni.dts index 5c1e12d39747..c6f39147cb96 100644 --- a/arch/arm/boot/dts/s5pv210-goni.dts +++ b/arch/arm/boot/dts/s5pv210-goni.dts @@ -358,15 +358,6 @@ reg = <0x4a>; interrupt-parent = <&gpj0>; interrupts = <5 IRQ_TYPE_EDGE_FALLING>; - - atmel,x-line = <17>; - atmel,y-line = <11>; - atmel,x-size = <800>; - atmel,y-size = <480>; - atmel,burst-length = <0x21>; - atmel,threshold = <0x28>; - atmel,orientation = <1>; - vdd-supply = <&tsp_reg>; }; }; diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index e47e1ca63043..f6e3e6f57252 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -794,7 +794,7 @@ 0xffffffff 0x3ffcfe7c 0x1c010101 /* pioA */ 0x7fffffff 0xfffccc3a 0x3f00cc3a /* pioB */ 0xffffffff 0x3ff83fff 0xff00ffff /* pioC */ - 0x0003ff00 0x8002a800 0x00000000 /* pioD */ + 0xb003ff00 0x8002a800 0x00000000 /* pioD */ 0xffffffff 0x7fffffff 0x76fff1bf /* pioE */ >; diff --git a/arch/arm/boot/dts/sd5203.dts b/arch/arm/boot/dts/sd5203.dts index 3cc9a23910be..a61a078ea042 100644 --- a/arch/arm/boot/dts/sd5203.dts +++ b/arch/arm/boot/dts/sd5203.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020 Hisilicon Limited. + * Copyright (c) 2020 HiSilicon Limited. * * DTS file for Hisilicon SD5203 Board */ diff --git a/arch/arm/boot/dts/ste-ab8500.dtsi b/arch/arm/boot/dts/ste-ab8500.dtsi index a16a00fb5fa5..d0fe3f9aa183 100644 --- a/arch/arm/boot/dts/ste-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-ab8500.dtsi @@ -34,7 +34,7 @@ #clock-cells = <1>; }; - ab8500_gpio: ab8500-gpio { + ab8500_gpio: ab8500-gpiocontroller { compatible = "stericsson,ab8500-gpio"; gpio-controller; #gpio-cells = <2>; @@ -42,15 +42,15 @@ ab8500-rtc { compatible = "stericsson,ab8500-rtc"; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH - 18 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>, + <18 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "60S", "ALARM"; }; gpadc: ab8500-gpadc { compatible = "stericsson,ab8500-gpadc"; - interrupts = <32 IRQ_TYPE_LEVEL_HIGH - 39 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH>, + <39 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "HW_CONV_END", "SW_CONV_END"; vddadc-supply = <&ab8500_ldo_tvout_reg>; #address-cells = <1>; @@ -219,13 +219,13 @@ ab8500_usb { compatible = "stericsson,ab8500-usb"; - interrupts = < 90 IRQ_TYPE_LEVEL_HIGH - 96 IRQ_TYPE_LEVEL_HIGH - 14 IRQ_TYPE_LEVEL_HIGH - 15 IRQ_TYPE_LEVEL_HIGH - 79 IRQ_TYPE_LEVEL_HIGH - 74 IRQ_TYPE_LEVEL_HIGH - 75 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <90 IRQ_TYPE_LEVEL_HIGH>, + <96 IRQ_TYPE_LEVEL_HIGH>, + <14 IRQ_TYPE_LEVEL_HIGH>, + <15 IRQ_TYPE_LEVEL_HIGH>, + <79 IRQ_TYPE_LEVEL_HIGH>, + <74 IRQ_TYPE_LEVEL_HIGH>, + <75 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "ID_WAKEUP_R", "ID_WAKEUP_F", "VBUS_DET_F", @@ -242,8 +242,8 @@ ab8500-ponkey { compatible = "stericsson,ab8500-poweron-key"; - interrupts = <6 IRQ_TYPE_LEVEL_HIGH - 7 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH>, + <7 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; }; diff --git a/arch/arm/boot/dts/ste-ab8505.dtsi b/arch/arm/boot/dts/ste-ab8505.dtsi index cc045b2fc217..0defc15b9bbc 100644 --- a/arch/arm/boot/dts/ste-ab8505.dtsi +++ b/arch/arm/boot/dts/ste-ab8505.dtsi @@ -31,7 +31,7 @@ #clock-cells = <1>; }; - ab8505_gpio: ab8505-gpio { + ab8505_gpio: ab8505-gpiocontroller { compatible = "stericsson,ab8505-gpio"; gpio-controller; #gpio-cells = <2>; @@ -39,8 +39,8 @@ ab8500-rtc { compatible = "stericsson,ab8500-rtc"; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH - 18 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>, + <18 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "60S", "ALARM"; }; @@ -182,13 +182,13 @@ ab8500_usb: ab8500_usb { compatible = "stericsson,ab8500-usb"; - interrupts = < 90 IRQ_TYPE_LEVEL_HIGH - 96 IRQ_TYPE_LEVEL_HIGH - 14 IRQ_TYPE_LEVEL_HIGH - 15 IRQ_TYPE_LEVEL_HIGH - 79 IRQ_TYPE_LEVEL_HIGH - 74 IRQ_TYPE_LEVEL_HIGH - 75 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <90 IRQ_TYPE_LEVEL_HIGH>, + <96 IRQ_TYPE_LEVEL_HIGH>, + <14 IRQ_TYPE_LEVEL_HIGH>, + <15 IRQ_TYPE_LEVEL_HIGH>, + <79 IRQ_TYPE_LEVEL_HIGH>, + <74 IRQ_TYPE_LEVEL_HIGH>, + <75 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "ID_WAKEUP_R", "ID_WAKEUP_F", "VBUS_DET_F", @@ -205,8 +205,8 @@ ab8500-ponkey { compatible = "stericsson,ab8500-poweron-key"; - interrupts = <6 IRQ_TYPE_LEVEL_HIGH - 7 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH>, + <7 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; }; diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi index 4946743de7b9..3ccb7b5c7162 100644 --- a/arch/arm/boot/dts/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi @@ -9,7 +9,7 @@ soc { prcmu@80157000 { ab8500 { - ab8500-gpio { + ab8500-gpiocontroller { /* Hog a few default settings */ pinctrl-names = "default"; pinctrl-0 = <&gpio2_default_mode>, diff --git a/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi index 8d59202cebd6..37e59403c01f 100644 --- a/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi +++ b/arch/arm/boot/dts/ste-href-tvk1281618-r2.dtsi @@ -104,6 +104,9 @@ * <&gpio1 0 IRQ_TYPE_EDGE_FALLING>, * <&gpio2 19 IRQ_TYPE_EDGE_FALLING>; */ + mount-matrix = "0", "1", "0", + "1", "0", "0", + "0", "0", "-1"; }; magnetometer@1e { /* Magnetometer */ @@ -136,6 +139,9 @@ /* INT2 would need to be open drain */ interrupts = <18 IRQ_TYPE_EDGE_RISING>, <19 IRQ_TYPE_EDGE_RISING>; + mount-matrix = "0", "-1", "0", + "-1", "0", "0", + "0", "0", "-1"; }; magnetometer@f { /* Magnetometer */ diff --git a/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi index 70f058352efc..00ce9d79f540 100644 --- a/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi +++ b/arch/arm/boot/dts/ste-href-tvk1281618-r3.dtsi @@ -89,10 +89,12 @@ <19 IRQ_TYPE_EDGE_RISING>; pinctrl-names = "default"; pinctrl-0 = <&accel_tvk_mode>; + mount-matrix = "0", "-1", "0", + "-1", "0", "0", + "0", "0", "-1"; }; magnetometer@1e { compatible = "st,lsm303dlm-magn"; - st,drdy-int-pin = <1>; reg = <0x1e>; vdd-supply = <&ab8500_ldo_aux1_reg>; vddio-supply = <&db8500_vsmps2_reg>; diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 83b179692dff..c97e8d29004f 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -4,6 +4,7 @@ */ #include +#include #include "ste-href-family-pinctrl.dtsi" / { @@ -64,17 +65,20 @@ reg = <0>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; linux,default-trigger = "heartbeat"; }; chan@1 { reg = <1>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; }; chan@2 { reg = <2>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; }; }; lp5521@34 { @@ -88,16 +92,19 @@ reg = <0>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; }; chan@1 { reg = <1>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; }; chan@2 { reg = <2>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = ; }; }; bh1780@29 { @@ -202,7 +209,7 @@ prcmu@80157000 { ab8500 { - ab8500-gpio { + ab8500-gpiocontroller { }; ab8500_usb { diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index b344b3748143..40f1d7c9c1d4 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -376,7 +376,7 @@ prcmu@80157000 { ab8500 { - ab8500-gpio { + ab8500-gpiocontroller { /* * AB8500 GPIOs are numbered starting from 1, so the first * index 0 is what in the datasheet is called "GPIO1", and diff --git a/arch/arm/boot/dts/ste-ux500-samsung-golden.dts b/arch/arm/boot/dts/ste-ux500-samsung-golden.dts index 0d43ee6583cf..40df7c61bf69 100644 --- a/arch/arm/boot/dts/ste-ux500-samsung-golden.dts +++ b/arch/arm/boot/dts/ste-ux500-samsung-golden.dts @@ -121,7 +121,7 @@ #size-cells = <0>; wifi@1 { - compatible = "brcm,bcm4329-fmac"; + compatible = "brcm,bcm4334-fmac", "brcm,bcm4329-fmac"; reg = <1>; /* GPIO216 (WLAN_HOST_WAKE) */ @@ -162,6 +162,7 @@ pinctrl-1 = <&u0_a_1_sleep>; bluetooth { + /* BCM4334B0 actually */ compatible = "brcm,bcm4330-bt"; /* GPIO222 (BT_VREG_ON) */ shutdown-gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts index f24369873ce2..25af066f6f3a 100644 --- a/arch/arm/boot/dts/ste-ux500-samsung-janice.dts +++ b/arch/arm/boot/dts/ste-ux500-samsung-janice.dts @@ -401,8 +401,7 @@ status = "okay"; wifi@1 { - /* Actually BRCM4330 */ - compatible = "brcm,bcm4329-fmac"; + compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac"; reg = <1>; /* GPIO216 WL_HOST_WAKE */ interrupt-parent = <&gpio6>; @@ -436,6 +435,7 @@ status = "okay"; bluetooth { + /* BCM4330B1 actually */ compatible = "brcm,bcm4330-bt"; /* GPIO222 rail BT_VREG_EN to BT_REG_ON */ shutdown-gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>; @@ -583,10 +583,9 @@ accelerometer@08 { compatible = "bosch,bma222"; reg = <0x08>; - /* FIXME: no idea about this */ - mount-matrix = "1", "0", "0", - "0", "1", "0", - "0", "0", "1"; + mount-matrix = "0", "1", "0", + "-1", "0", "0", + "0", "0", "-1"; vddio-supply = <&ab8500_ldo_aux2_reg>; // 1.8V vdd-supply = <&ab8500_ldo_aux1_reg>; // 3V }; diff --git a/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts b/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts index d28a00757d0b..94afd7a0fe1f 100644 --- a/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts +++ b/arch/arm/boot/dts/ste-ux500-samsung-skomer.dts @@ -211,7 +211,7 @@ #size-cells = <0>; wifi@1 { - compatible = "brcm,bcm4329-fmac"; + compatible = "brcm,bcm4334-fmac", "brcm,bcm4329-fmac"; reg = <1>; /* GPIO216 WL_HOST_WAKE */ interrupt-parent = <&gpio6>; @@ -247,6 +247,7 @@ /* FIXME: not quite working yet, probably needs regulators */ bluetooth { + /* BCM4334B0 actually */ compatible = "brcm,bcm4330-bt"; shutdown-gpios = <&gpio6 30 GPIO_ACTIVE_HIGH>; device-wakeup-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts index 7e10ae744c9d..9ac1ffe53413 100644 --- a/arch/arm/boot/dts/stm32429i-eval.dts +++ b/arch/arm/boot/dts/stm32429i-eval.dts @@ -119,17 +119,15 @@ }; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@0 { + button-0 { label = "Wake up"; linux,code = ; gpios = <&gpioa 0 0>; }; - button@1 { + button-1 { label = "Tamper"; linux,code = ; gpios = <&gpioc 13 0>; diff --git a/arch/arm/boot/dts/stm32746g-eval.dts b/arch/arm/boot/dts/stm32746g-eval.dts index ca8c192449ee..327613fd9666 100644 --- a/arch/arm/boot/dts/stm32746g-eval.dts +++ b/arch/arm/boot/dts/stm32746g-eval.dts @@ -81,12 +81,10 @@ }; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@0 { + button-0 { label = "Wake up"; linux,code = ; gpios = <&gpioc 13 0>; diff --git a/arch/arm/boot/dts/stm32f4-pinctrl.dtsi b/arch/arm/boot/dts/stm32f4-pinctrl.dtsi index 4774163af54b..155d9ffacc83 100644 --- a/arch/arm/boot/dts/stm32f4-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32f4-pinctrl.dtsi @@ -45,7 +45,7 @@ / { soc { - pinctrl: pin-controller { + pinctrl: pin-controller@40020000 { #address-cells = <1>; #size-cells = <1>; ranges = <0 0x40020000 0x3000>; diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts index 3dc068b91ca1..075ac57d0bf4 100644 --- a/arch/arm/boot/dts/stm32f429-disco.dts +++ b/arch/arm/boot/dts/stm32f429-disco.dts @@ -81,12 +81,10 @@ }; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@0 { + button-0 { label = "User"; linux,code = ; gpios = <&gpioa 0 0>; diff --git a/arch/arm/boot/dts/stm32f429-pinctrl.dtsi b/arch/arm/boot/dts/stm32f429-pinctrl.dtsi index 3e7a17d9112e..e10d7a1f3207 100644 --- a/arch/arm/boot/dts/stm32f429-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32f429-pinctrl.dtsi @@ -42,54 +42,50 @@ #include "stm32f4-pinctrl.dtsi" -/ { - soc { - pinctrl: pin-controller { - compatible = "st,stm32f429-pinctrl"; +&pinctrl { + compatible = "st,stm32f429-pinctrl"; - gpioa: gpio@40020000 { - gpio-ranges = <&pinctrl 0 0 16>; - }; + gpioa: gpio@40020000 { + gpio-ranges = <&pinctrl 0 0 16>; + }; - gpiob: gpio@40020400 { - gpio-ranges = <&pinctrl 0 16 16>; - }; + gpiob: gpio@40020400 { + gpio-ranges = <&pinctrl 0 16 16>; + }; - gpioc: gpio@40020800 { - gpio-ranges = <&pinctrl 0 32 16>; - }; + gpioc: gpio@40020800 { + gpio-ranges = <&pinctrl 0 32 16>; + }; - gpiod: gpio@40020c00 { - gpio-ranges = <&pinctrl 0 48 16>; - }; + gpiod: gpio@40020c00 { + gpio-ranges = <&pinctrl 0 48 16>; + }; - gpioe: gpio@40021000 { - gpio-ranges = <&pinctrl 0 64 16>; - }; + gpioe: gpio@40021000 { + gpio-ranges = <&pinctrl 0 64 16>; + }; - gpiof: gpio@40021400 { - gpio-ranges = <&pinctrl 0 80 16>; - }; + gpiof: gpio@40021400 { + gpio-ranges = <&pinctrl 0 80 16>; + }; - gpiog: gpio@40021800 { - gpio-ranges = <&pinctrl 0 96 16>; - }; + gpiog: gpio@40021800 { + gpio-ranges = <&pinctrl 0 96 16>; + }; - gpioh: gpio@40021c00 { - gpio-ranges = <&pinctrl 0 112 16>; - }; + gpioh: gpio@40021c00 { + gpio-ranges = <&pinctrl 0 112 16>; + }; - gpioi: gpio@40022000 { - gpio-ranges = <&pinctrl 0 128 16>; - }; + gpioi: gpio@40022000 { + gpio-ranges = <&pinctrl 0 128 16>; + }; - gpioj: gpio@40022400 { - gpio-ranges = <&pinctrl 0 144 16>; - }; + gpioj: gpio@40022400 { + gpio-ranges = <&pinctrl 0 144 16>; + }; - gpiok: gpio@40022800 { - gpio-ranges = <&pinctrl 0 160 8>; - }; - }; + gpiok: gpio@40022800 { + gpio-ranges = <&pinctrl 0 160 8>; }; }; diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi index f6530d724d00..8748d5850298 100644 --- a/arch/arm/boot/dts/stm32f429.dtsi +++ b/arch/arm/boot/dts/stm32f429.dtsi @@ -283,8 +283,6 @@ }; timers13: timers@40001c00 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40001C00 0x400>; clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM13)>; @@ -299,8 +297,6 @@ }; timers14: timers@40002000 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40002000 0x400>; clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM14)>; @@ -633,8 +629,6 @@ }; timers10: timers@40014400 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40014400 0x400>; clocks = <&rcc 0 STM32F4_APB2_CLOCK(TIM10)>; @@ -649,8 +643,6 @@ }; timers11: timers@40014800 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40014800 0x400>; clocks = <&rcc 0 STM32F4_APB2_CLOCK(TIM11)>; @@ -709,7 +701,7 @@ status = "disabled"; }; - rcc: rcc@40023810 { + rcc: rcc@40023800 { #reset-cells = <1>; #clock-cells = <2>; compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts index 2e1b3bbbe4b5..8c982ae79f43 100644 --- a/arch/arm/boot/dts/stm32f469-disco.dts +++ b/arch/arm/boot/dts/stm32f469-disco.dts @@ -104,12 +104,10 @@ }; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@0 { + button-0 { label = "User"; linux,code = ; gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/stm32f469-pinctrl.dtsi b/arch/arm/boot/dts/stm32f469-pinctrl.dtsi index fff542662eea..6bf60263dff8 100644 --- a/arch/arm/boot/dts/stm32f469-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32f469-pinctrl.dtsi @@ -42,55 +42,51 @@ #include "stm32f4-pinctrl.dtsi" -/ { - soc { - pinctrl: pin-controller { - compatible = "st,stm32f469-pinctrl"; +&pinctrl { + compatible = "st,stm32f469-pinctrl"; - gpioa: gpio@40020000 { - gpio-ranges = <&pinctrl 0 0 16>; - }; + gpioa: gpio@40020000 { + gpio-ranges = <&pinctrl 0 0 16>; + }; - gpiob: gpio@40020400 { - gpio-ranges = <&pinctrl 0 16 16>; - }; + gpiob: gpio@40020400 { + gpio-ranges = <&pinctrl 0 16 16>; + }; - gpioc: gpio@40020800 { - gpio-ranges = <&pinctrl 0 32 16>; - }; + gpioc: gpio@40020800 { + gpio-ranges = <&pinctrl 0 32 16>; + }; - gpiod: gpio@40020c00 { - gpio-ranges = <&pinctrl 0 48 16>; - }; + gpiod: gpio@40020c00 { + gpio-ranges = <&pinctrl 0 48 16>; + }; - gpioe: gpio@40021000 { - gpio-ranges = <&pinctrl 0 64 16>; - }; + gpioe: gpio@40021000 { + gpio-ranges = <&pinctrl 0 64 16>; + }; - gpiof: gpio@40021400 { - gpio-ranges = <&pinctrl 0 80 16>; - }; + gpiof: gpio@40021400 { + gpio-ranges = <&pinctrl 0 80 16>; + }; - gpiog: gpio@40021800 { - gpio-ranges = <&pinctrl 0 96 16>; - }; + gpiog: gpio@40021800 { + gpio-ranges = <&pinctrl 0 96 16>; + }; - gpioh: gpio@40021c00 { - gpio-ranges = <&pinctrl 0 112 16>; - }; + gpioh: gpio@40021c00 { + gpio-ranges = <&pinctrl 0 112 16>; + }; - gpioi: gpio@40022000 { - gpio-ranges = <&pinctrl 0 128 16>; - }; + gpioi: gpio@40022000 { + gpio-ranges = <&pinctrl 0 128 16>; + }; - gpioj: gpio@40022400 { - gpio-ranges = <&pinctrl 0 144 6>, - <&pinctrl 12 156 4>; - }; + gpioj: gpio@40022400 { + gpio-ranges = <&pinctrl 0 144 6>, + <&pinctrl 12 156 4>; + }; - gpiok: gpio@40022800 { - gpio-ranges = <&pinctrl 3 163 5>; - }; - }; + gpiok: gpio@40022800 { + gpio-ranges = <&pinctrl 3 163 5>; }; }; diff --git a/arch/arm/boot/dts/stm32f7-pinctrl.dtsi b/arch/arm/boot/dts/stm32f7-pinctrl.dtsi index fe4cfda72a47..1cf8a23c2644 100644 --- a/arch/arm/boot/dts/stm32f7-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32f7-pinctrl.dtsi @@ -9,7 +9,7 @@ / { soc { - pinctrl: pin-controller { + pinctrl: pin-controller@40020000 { #address-cells = <1>; #size-cells = <1>; ranges = <0 0x40020000 0x3000>; diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi index e1df603fc981..014b416f57e6 100644 --- a/arch/arm/boot/dts/stm32f746.dtsi +++ b/arch/arm/boot/dts/stm32f746.dtsi @@ -265,8 +265,6 @@ }; timers13: timers@40001c00 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40001C00 0x400>; clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM13)>; @@ -281,8 +279,6 @@ }; timers14: timers@40002000 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40002000 0x400>; clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM14)>; @@ -364,9 +360,9 @@ status = "disabled"; }; - i2c3: i2c@40005C00 { + i2c3: i2c@40005c00 { compatible = "st,stm32f7-i2c"; - reg = <0x40005C00 0x400>; + reg = <0x40005c00 0x400>; interrupts = <72>, <73>; resets = <&rcc STM32F7_APB1_RESET(I2C3)>; @@ -531,8 +527,6 @@ }; timers10: timers@40014400 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40014400 0x400>; clocks = <&rcc 0 STM32F7_APB2_CLOCK(TIM10)>; @@ -547,8 +541,6 @@ }; timers11: timers@40014800 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40014800 0x400>; clocks = <&rcc 0 STM32F7_APB2_CLOCK(TIM11)>; diff --git a/arch/arm/boot/dts/stm32f769-disco.dts b/arch/arm/boot/dts/stm32f769-disco.dts index 0ce7fbc20fa4..be943b701980 100644 --- a/arch/arm/boot/dts/stm32f769-disco.dts +++ b/arch/arm/boot/dts/stm32f769-disco.dts @@ -75,12 +75,10 @@ }; }; - gpio_keys { + gpio-keys { compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; autorepeat; - button@0 { + button-0 { label = "User"; linux,code = ; gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 05ecdf9ff03a..6e42ca2dada2 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -485,8 +485,6 @@ }; lptimer4: timer@58002c00 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-lptimer"; reg = <0x58002c00 0x400>; clocks = <&rcc LPTIM4_CK>; @@ -501,8 +499,6 @@ }; lptimer5: timer@58003000 { - #address-cells = <1>; - #size-cells = <0>; compatible = "st,stm32-lptimer"; reg = <0x58003000 0x400>; clocks = <&rcc LPTIM5_CK>; diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi index 060baa8b7e9d..5b60ecbd718f 100644 --- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi @@ -118,6 +118,39 @@ }; }; + dcmi_pins_b: dcmi-1 { + pins { + pinmux = ,/* DCMI_HSYNC */ + ,/* DCMI_VSYNC */ + ,/* DCMI_PIXCLK */ + ,/* DCMI_D0 */ + ,/* DCMI_D1 */ + ,/* DCMI_D2 */ + ,/* DCMI_D3 */ + ,/* DCMI_D4 */ + ,/* DCMI_D5 */ + ,/* DCMI_D6 */ + ;/* DCMI_D7 */ + bias-disable; + }; + }; + + dcmi_sleep_pins_b: dcmi-sleep-1 { + pins { + pinmux = ,/* DCMI_HSYNC */ + ,/* DCMI_VSYNC */ + ,/* DCMI_PIXCLK */ + ,/* DCMI_D0 */ + ,/* DCMI_D1 */ + ,/* DCMI_D2 */ + ,/* DCMI_D3 */ + ,/* DCMI_D4 */ + ,/* DCMI_D5 */ + ,/* DCMI_D6 */ + ;/* DCMI_D7 */ + }; + }; + ethernet0_rgmii_pins_a: rgmii-0 { pins1 { pinmux = , /* ETH_RGMII_CLK125 */ diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi index fcd3230c469b..bd289bf5d269 100644 --- a/arch/arm/boot/dts/stm32mp151.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -1369,8 +1369,8 @@ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; - dmas = <&mdma1 22 0x2 0x100002 0x0 0x0>, - <&mdma1 22 0x2 0x100008 0x0 0x0>; + dmas = <&mdma1 22 0x2 0x10100002 0x0 0x0>, + <&mdma1 22 0x2 0x10100008 0x0 0x0>; dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; @@ -1416,12 +1416,6 @@ status = "disabled"; }; - stmmac_axi_config_0: stmmac-axi-config { - snps,wr_osr_lmt = <0x7>; - snps,rd_osr_lmt = <0x7>; - snps,blen = <0 0 0 0 16 8 4>; - }; - ethernet0: ethernet@5800a000 { compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; @@ -1447,6 +1441,12 @@ snps,axi-config = <&stmmac_axi_config_0>; snps,tso; status = "disabled"; + + stmmac_axi_config_0: stmmac-axi-config { + snps,wr_osr_lmt = <0x7>; + snps,rd_osr_lmt = <0x7>; + snps,blen = <0 0 0 0 16 8 4>; + }; }; usbh_ohci: usb@5800c000 { diff --git a/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts index 674b2d330dc4..5670b23812a2 100644 --- a/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts +++ b/arch/arm/boot/dts/stm32mp157a-microgea-stm32mp1-microdev2.0-of7.dts @@ -89,7 +89,7 @@ }; &pinctrl { - ltdc_pins: ltdc { + ltdc_pins: ltdc-0 { pins { pinmux = , /* LTDC_B2 */ , /* LTDC_R6 */ diff --git a/arch/arm/boot/dts/stm32mp157a-stinger96.dtsi b/arch/arm/boot/dts/stm32mp157a-stinger96.dtsi index 113c48b2ef93..a4b14ef3caee 100644 --- a/arch/arm/boot/dts/stm32mp157a-stinger96.dtsi +++ b/arch/arm/boot/dts/stm32mp157a-stinger96.dtsi @@ -184,8 +184,6 @@ vdd_usb: ldo4 { regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; interrupts = ; }; @@ -208,7 +206,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -219,13 +216,13 @@ vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; diff --git a/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi b/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi index 6cf49a0a9e69..2d9461006810 100644 --- a/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi +++ b/arch/arm/boot/dts/stm32mp157c-odyssey-som.dtsi @@ -173,8 +173,6 @@ vdd_usb: ldo4 { regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; interrupts = ; }; @@ -197,7 +195,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -213,7 +210,7 @@ vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; @@ -269,7 +266,7 @@ st,neg-edge; bus-width = <8>; vmmc-supply = <&v3v3>; - vqmmc-supply = <&v3v3>; + vqmmc-supply = <&vdd>; mmc-ddr-3_3v; status = "okay"; }; diff --git a/arch/arm/boot/dts/stm32mp157c-odyssey.dts b/arch/arm/boot/dts/stm32mp157c-odyssey.dts index a7ffec8f1516..be1dd5e9e744 100644 --- a/arch/arm/boot/dts/stm32mp157c-odyssey.dts +++ b/arch/arm/boot/dts/stm32mp157c-odyssey.dts @@ -64,7 +64,7 @@ pinctrl-0 = <&sdmmc1_b4_pins_a>; pinctrl-1 = <&sdmmc1_b4_od_pins_a>; pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; - cd-gpios = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + cd-gpios = <&gpioi 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; disable-wp; st,neg-edge; bus-width = <4>; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi index 5523f4138fd6..c5ea08fec535 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-pdk2.dtsi @@ -34,7 +34,6 @@ gpio-keys-polled { compatible = "gpio-keys-polled"; - #size-cells = <0>; poll-interval = <20>; /* @@ -60,7 +59,6 @@ gpio-keys { compatible = "gpio-keys"; - #size-cells = <0>; button-1 { label = "TA2-GPIO-B"; @@ -184,12 +182,11 @@ }; - polytouch@38 { - compatible = "edt,edt-ft5x06"; + touchscreen@38 { + compatible = "edt,edt-ft5406"; reg = <0x38>; interrupt-parent = <&gpiog>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO E */ - linux,wakeup; }; }; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi index 272a1a67a9ad..2af0a6752674 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi @@ -123,7 +123,6 @@ max-speed = <100>; phy-handle = <&phy0>; st,eth-ref-clk-sel; - phy-reset-gpios = <&gpioh 3 GPIO_ACTIVE_LOW>; mdio0 { #address-cells = <1>; @@ -132,6 +131,13 @@ phy0: ethernet-phy@1 { reg = <1>; + /* LAN8710Ai */ + compatible = "ethernet-phy-id0007.c0f0", + "ethernet-phy-ieee802.3-c22"; + clocks = <&rcc ETHCK_K>; + reset-gpios = <&gpioh 3 GPIO_ACTIVE_LOW>; + reset-assert-us = <500>; + reset-deassert-us = <500>; interrupt-parent = <&gpioi>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; }; @@ -144,7 +150,7 @@ pinctrl-1 = <&fmc_sleep_pins_b>; status = "okay"; - ksz8851: ks8851mll@1,0 { + ksz8851: ethernet@1,0 { compatible = "micrel,ks8851-mll"; reg = <1 0x0 0x2>, <1 0x2 0x20000>; interrupt-parent = <&gpioc>; @@ -327,8 +333,6 @@ vdd_usb: ldo4 { regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; interrupts = ; }; @@ -350,7 +354,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -366,7 +369,7 @@ vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; @@ -431,7 +434,7 @@ #size-cells = <0>; status = "okay"; - flash0: mx66l51235l@0 { + flash0: flash@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-rx-bus-width = <4>; diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi index 013ae369791d..2b0ac605549d 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi @@ -198,7 +198,7 @@ #size-cells = <0>; status = "okay"; - flash0: spi-flash@0 { + flash0: flash@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-rx-bus-width = <4>; diff --git a/arch/arm/boot/dts/stm32mp15xx-osd32.dtsi b/arch/arm/boot/dts/stm32mp15xx-osd32.dtsi index 713485a95795..6706d8311a66 100644 --- a/arch/arm/boot/dts/stm32mp15xx-osd32.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-osd32.dtsi @@ -146,8 +146,6 @@ vdd_usb: ldo4 { regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; interrupts = ; }; @@ -171,7 +169,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -182,13 +179,13 @@ vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; interrupts = ; - regulator-active-discharge; + regulator-active-discharge = <1>; }; }; diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi index 7344c37107c6..2beddbb3c518 100644 --- a/arch/arm/boot/dts/sun8i-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a33.dtsi @@ -198,7 +198,7 @@ }; link_codec: simple-audio-card,codec { - sound-dai = <&codec>; + sound-dai = <&codec 0>; }; }; @@ -238,7 +238,7 @@ }; codec: codec@1c22e00 { - #sound-dai-cells = <0>; + #sound-dai-cells = <1>; compatible = "allwinner,sun8i-a33-codec"; reg = <0x01c22e00 0x400>; interrupts = ; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts index 97f497854e05..d05fa679dcd3 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts @@ -85,7 +85,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-r40-feta40i.dtsi b/arch/arm/boot/dts/sun8i-r40-feta40i.dtsi new file mode 100644 index 000000000000..265e0fa57a32 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-r40-feta40i.dtsi @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +// Copyright (C) 2021 Ivan Uvarov +// Based on the sun8i-r40-bananapi-m2-ultra.dts, which is: +// Copyright (C) 2017 Chen-Yu Tsai +// Copyright (C) 2017 Icenowy Zheng + +#include "sun8i-r40.dtsi" + +&i2c0 { + status = "okay"; + + axp22x: pmic@34 { + compatible = "x-powers,axp221"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +#include "axp22x.dtsi" + +&mmc2 { + vmmc-supply = <®_dcdc1>; + vqmmc-supply = <®_aldo2>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&pio { + pinctrl-names = "default"; + pinctrl-0 = <&clk_out_a_pin>; + vcc-pa-supply = <®_dcdc1>; + vcc-pc-supply = <®_aldo2>; + vcc-pd-supply = <®_dcdc1>; + vcc-pf-supply = <®_dldo4>; + vcc-pg-supply = <®_dldo1>; +}; + +®_aldo2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pa"; +}; + +®_aldo3 { + regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "avcc"; +}; + +®_dcdc1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-3v3"; +}; + +®_dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-cpu"; +}; + +®_dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-sys"; +}; + +®_dcdc5 { + regulator-always-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-name = "vcc-dram"; +}; + +®_dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-wifi-io"; +}; + +®_dldo4 { + regulator-always-on; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-name = "vdd2v5-sata"; +}; + +®_eldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdd1v2-sata"; +}; + +®_eldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc-pe"; +}; diff --git a/arch/arm/boot/dts/sun8i-r40-oka40i-c.dts b/arch/arm/boot/dts/sun8i-r40-oka40i-c.dts new file mode 100644 index 000000000000..0bd1336206b8 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-r40-oka40i-c.dts @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +// Copyright (C) 2021 Ivan Uvarov +// Based on the sun8i-r40-bananapi-m2-ultra.dts, which is: +// Copyright (C) 2017 Chen-Yu Tsai +// Copyright (C) 2017 Icenowy Zheng + +/dts-v1/; +#include "sun8i-r40-feta40i.dtsi" + +#include +#include + +/ { + model = "Forlinx OKA40i-C"; + compatible = "forlinx,oka40i-c", "forlinx,feta40i-c", "allwinner,sun8i-r40"; + + aliases { + ethernet0 = &gmac; + serial0 = &uart0; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; /* RS485 */ + serial7 = &uart7; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-5 { /* this is how the leds are labeled on the board */ + gpios = <&pio 7 26 GPIO_ACTIVE_LOW>; /* PH26 */ + color = ; + function = LED_FUNCTION_STATUS; + }; + + led-6 { + gpios = <&pio 8 15 GPIO_ACTIVE_LOW>; /* PI15 */ + color = ; + function = LED_FUNCTION_STATUS; + }; + }; + + reg_vcc5v0: vcc5v0 { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&pio 1 10 GPIO_ACTIVE_LOW>; // PB10 WIFI_EN + clocks = <&ccu CLK_OUTA>; + clock-names = "ext_clock"; + }; +}; + +&ahci { + ahci-supply = <®_dldo4>; + phy-supply = <®_eldo2>; + status = "okay"; +}; + +&de { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&ehci2 { + status = "okay"; +}; + +&gmac { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_rgmii_pins>; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + phy-supply = <®_dcdc1>; + status = "okay"; +}; + +&gmac_mdio { + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_dcdc1>; + vqmmc-supply = <®_dcdc1>; + bus-width = <4>; + cd-gpios = <&pio 8 11 GPIO_ACTIVE_LOW>; // PI11 + status = "okay"; +}; + +&mmc3 { + vmmc-supply = <®_dcdc1>; + vqmmc-supply = <®_dcdc1>; + bus-width = <4>; + cd-gpios = <&pio 8 10 GPIO_ACTIVE_LOW>; // PI10 + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&ohci2 { + status = "okay"; +}; + +®_dc1sw { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-lcd"; +}; + +®_dldo2 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-wifi"; +}; + +&tcon_tv0 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pi_pins>, <&uart2_rts_cts_pi_pins>; + uart-has-rtscts; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pg_pins>, <&uart3_rts_cts_pg_pins>; + uart-has-rtscts; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pg_pins>; + status = "okay"; +}; + +&uart5 { /* RS485 */ + pinctrl-names = "default"; + pinctrl-0 = <&uart5_ph_pins>; + status = "okay"; +}; + +&uart7 { + pinctrl-names = "default"; + pinctrl-0 = <&uart7_pi_pins>; + status = "okay"; +}; + +&usbphy { + usb1_vbus-supply = <®_vcc5v0>; + usb2_vbus-supply = <®_vcc5v0>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi index d5ad3b9efd12..291f4784e86c 100644 --- a/arch/arm/boot/dts/sun8i-r40.dtsi +++ b/arch/arm/boot/dts/sun8i-r40.dtsi @@ -357,6 +357,8 @@ clock-names = "ahb", "mmc"; resets = <&ccu RST_BUS_MMC3>; reset-names = "ahb"; + pinctrl-0 = <&mmc3_pins>; + pinctrl-names = "default"; interrupts = ; status = "disabled"; #address-cells = <1>; @@ -601,6 +603,15 @@ bias-pull-up; }; + /omit-if-no-ref/ + mmc3_pins: mmc3-pins { + pins = "PI4", "PI5", "PI6", + "PI7", "PI8", "PI9"; + function = "mmc3"; + drive-strength = <30>; + bias-pull-up; + }; + /omit-if-no-ref/ spi0_pc_pins: spi0-pc-pins { pins = "PC0", "PC1", "PC2"; @@ -631,20 +642,65 @@ function = "spi1"; }; + /omit-if-no-ref/ uart0_pb_pins: uart0-pb-pins { pins = "PB22", "PB23"; function = "uart0"; }; + /omit-if-no-ref/ + uart2_pi_pins: uart2-pi-pins { + pins = "PI18", "PI19"; + function = "uart2"; + }; + + /omit-if-no-ref/ + uart2_rts_cts_pi_pins: uart2-rts-cts-pi-pins{ + pins = "PI16", "PI17"; + function = "uart2"; + }; + + /omit-if-no-ref/ uart3_pg_pins: uart3-pg-pins { pins = "PG6", "PG7"; function = "uart3"; }; + /omit-if-no-ref/ uart3_rts_cts_pg_pins: uart3-rts-cts-pg-pins { pins = "PG8", "PG9"; function = "uart3"; }; + + /omit-if-no-ref/ + uart4_pg_pins: uart4-pg-pins { + pins = "PG10", "PG11"; + function = "uart4"; + }; + + /omit-if-no-ref/ + uart5_ph_pins: uart5-ph-pins { + pins = "PH6", "PH7"; + function = "uart5"; + }; + + /omit-if-no-ref/ + uart7_pi_pins: uart7-pi-pins { + pins = "PI20", "PI21"; + function = "uart7"; + }; + }; + + timer@1c20c00 { + compatible = "allwinner,sun4i-a10-timer"; + reg = <0x01c20c00 0x90>; + interrupts = , + , + , + , + , + ; + clocks = <&osc24M>; }; wdt: watchdog@1c20c90 { diff --git a/arch/arm/boot/dts/sun8i-v3.dtsi b/arch/arm/boot/dts/sun8i-v3.dtsi index c279e13583ba..186c30cbe6ee 100644 --- a/arch/arm/boot/dts/sun8i-v3.dtsi +++ b/arch/arm/boot/dts/sun8i-v3.dtsi @@ -1,14 +1,40 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (C) 2019 Icenowy Zheng + * Copyright (C) 2021 Tobias Schramm */ #include "sun8i-v3s.dtsi" +/ { + soc { + i2s0: i2s@1c22000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-v3-i2s", + "allwinner,sun8i-h3-i2s"; + reg = <0x01c22000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>; + clock-names = "apb", "mod"; + dmas = <&dma 3>, <&dma 3>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_pins>; + resets = <&ccu RST_BUS_I2S0>; + status = "disabled"; + }; + }; +}; + &ccu { compatible = "allwinner,sun8i-v3-ccu"; }; +&codec_analog { + compatible = "allwinner,sun8i-v3-codec-analog", + "allwinner,sun8i-h3-codec-analog"; +}; + &emac { /delete-property/ phy-handle; /delete-property/ phy-mode; @@ -25,6 +51,11 @@ &pio { compatible = "allwinner,sun8i-v3-pinctrl"; + i2s0_pins: i2s0-pins { + pins = "PG10", "PG11", "PG12", "PG13"; + function = "i2s"; + }; + uart1_pg_pins: uart1-pg-pins { pins = "PG6", "PG7"; function = "uart1"; diff --git a/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dts b/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dts index db5cd0b8574b..752ad05c8f83 100644 --- a/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dts +++ b/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dts @@ -49,16 +49,18 @@ compatible = "licheepi,licheepi-zero-dock", "licheepi,licheepi-zero", "allwinner,sun8i-v3s"; + aliases { + ethernet0 = &emac; + }; + leds { /* The LEDs use PG0~2 pins, which conflict with MMC1 */ status = "disabled"; }; }; -&mmc1 { - broken-cd; - bus-width = <4>; - vmmc-supply = <®_vcc3v3>; +&emac { + allwinner,leds-active-low; status = "okay"; }; @@ -94,3 +96,10 @@ voltage = <800000>; }; }; + +&mmc1 { + broken-cd; + bus-width = <4>; + vmmc-supply = <®_vcc3v3>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index eb4cb63fef13..b30bc1a25ebb 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 Icenowy Zheng + * Copyright (C) 2021 Tobias Schramm * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual @@ -172,6 +173,15 @@ interrupts = ; }; + dma: dma-controller@1c02000 { + compatible = "allwinner,sun8i-v3s-dma"; + reg = <0x01c02000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_DMA>; + resets = <&ccu RST_BUS_DMA>; + #dma-cells = <1>; + }; + tcon0: lcd-controller@1c0c000 { compatible = "allwinner,sun8i-v3s-tcon"; reg = <0x01c0c000 0x1000>; @@ -275,6 +285,8 @@ interrupts = ; clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>; clock-names = "ahb", "mod"; + dmas = <&dma 16>, <&dma 16>; + dma-names = "rx", "tx"; resets = <&ccu RST_BUS_CE>; reset-names = "ahb"; }; @@ -422,6 +434,15 @@ clocks = <&osc24M>; }; + pwm: pwm@1c21400 { + compatible = "allwinner,sun8i-v3s-pwm", + "allwinner,sun7i-a20-pwm"; + reg = <0x01c21400 0xc>; + clocks = <&osc24M>; + #pwm-cells = <3>; + status = "disabled"; + }; + lradc: lradc@1c22800 { compatible = "allwinner,sun4i-a10-lradc-keys"; reg = <0x01c22800 0x400>; @@ -429,6 +450,25 @@ status = "disabled"; }; + codec: codec@1c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-v3s-codec"; + reg = <0x01c22c00 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "apb", "codec"; + resets = <&ccu RST_BUS_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + allwinner,codec-analog-controls = <&codec_analog>; + status = "disabled"; + }; + + codec_analog: codec-analog@1c23000 { + compatible = "allwinner,sun8i-v3s-codec-analog"; + reg = <0x01c23000 0x4>; + }; + uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; @@ -436,6 +476,8 @@ reg-shift = <2>; reg-io-width = <4>; clocks = <&ccu CLK_BUS_UART0>; + dmas = <&dma 6>, <&dma 6>; + dma-names = "rx", "tx"; resets = <&ccu RST_BUS_UART0>; status = "disabled"; }; @@ -447,6 +489,8 @@ reg-shift = <2>; reg-io-width = <4>; clocks = <&ccu CLK_BUS_UART1>; + dmas = <&dma 7>, <&dma 7>; + dma-names = "rx", "tx"; resets = <&ccu RST_BUS_UART1>; status = "disabled"; }; @@ -458,6 +502,8 @@ reg-shift = <2>; reg-io-width = <4>; clocks = <&ccu CLK_BUS_UART2>; + dmas = <&dma 8>, <&dma 8>; + dma-names = "rx", "tx"; resets = <&ccu RST_BUS_UART2>; pinctrl-0 = <&uart2_pins>; pinctrl-names = "default"; @@ -537,6 +583,8 @@ interrupts = ; clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; clock-names = "ahb", "mod"; + dmas = <&dma 23>, <&dma 23>; + dma-names = "rx", "tx"; pinctrl-names = "default"; pinctrl-0 = <&spi0_pins>; resets = <&ccu RST_BUS_SPI0>; diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 0b678afb2a5c..8b38f123f554 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -283,7 +283,7 @@ reg = <0x0 0x60007000 0x0 0x1000>; }; - actmon@6000c800 { + actmon: actmon@6000c800 { compatible = "nvidia,tegra124-actmon"; reg = <0x0 0x6000c800 0x0 0x400>; interrupts = ; @@ -295,6 +295,7 @@ operating-points-v2 = <&emc_bw_dfs_opp_table>; interconnects = <&mc TEGRA124_MC_MPCORER &emc>; interconnect-names = "cpu-read"; + #cooling-cells = <2>; }; gpio: gpio@6000d000 { diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index 2298fc034183..1976c383912a 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -420,11 +420,14 @@ reg = <0x1a>; interrupt-parent = <&gpio>; - interrupts = ; + interrupts = ; gpio-controller; #gpio-cells = <2>; + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0x0000 /* MIC_LR_OUT# GPIO, output, low */ 0x0000 /* FM2018-enable GPIO, output, low */ @@ -759,7 +762,7 @@ mmc-pwrseq = <&brcm_wifi_pwrseq>; vmmc-supply = <&vdd_3v3_sys>; - vqmmc-supply = <&vdd_3v3_sys>; + vqmmc-supply = <&vdd_1v8_sys>; /* Azurewave AW-NH611 BCM4329 */ wifi@1 { @@ -1030,7 +1033,7 @@ nvidia,audio-codec = <&wm8903>; nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_HIGH>; + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>; nvidia,int-mic-en-gpios = <&wm8903 1 GPIO_ACTIVE_HIGH>; nvidia,headset; @@ -1056,15 +1059,15 @@ trips { trip0: cpu-alert0 { - /* start throttling at 50C */ - temperature = <50000>; + /* start throttling at 60C */ + temperature = <60000>; hysteresis = <200>; type = "passive"; }; trip1: cpu-crit { - /* shut down at 60C */ - temperature = <60000>; + /* shut down at 70C */ + temperature = <70000>; hysteresis = <2000>; type = "critical"; }; @@ -1085,6 +1088,7 @@ emc-tables@0 { nvidia,ram-code = <0>; /* elpida-8gb */ + reg = <0>; #address-cells = <1>; #size-cells = <0>; @@ -1182,6 +1186,7 @@ emc-tables@1 { nvidia,ram-code = <1>; /* elpida-4gb */ + reg = <1>; #address-cells = <1>; #size-cells = <0>; @@ -1279,6 +1284,7 @@ emc-tables@2 { nvidia,ram-code = <2>; /* hynix-8gb */ + reg = <2>; #address-cells = <1>; #size-cells = <0>; @@ -1376,6 +1382,7 @@ emc-tables@3 { nvidia,ram-code = <3>; /* hynix-4gb */ + reg = <3>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 86494cb4d5a1..ae4312eedcbd 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -748,7 +748,7 @@ nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) - GPIO_ACTIVE_HIGH>; + GPIO_ACTIVE_LOW>; nvidia,int-mic-en-gpios = <&gpio TEGRA_GPIO(X, 0) GPIO_ACTIVE_HIGH>; nvidia,ext-mic-en-gpios = <&gpio TEGRA_GPIO(X, 1) diff --git a/arch/arm/boot/dts/tegra20-medcom-wide.dts b/arch/arm/boot/dts/tegra20-medcom-wide.dts index a348ca30e522..b31c9bca16e6 100644 --- a/arch/arm/boot/dts/tegra20-medcom-wide.dts +++ b/arch/arm/boot/dts/tegra20-medcom-wide.dts @@ -84,7 +84,7 @@ nvidia,audio-codec = <&wm8903>; nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_HIGH>; + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>; clocks = <&tegra_car TEGRA20_CLK_PLL_A>, <&tegra_car TEGRA20_CLK_PLL_A_OUT0>, diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 940a9f31cd86..3180bff90756 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -2,6 +2,8 @@ /dts-v1/; #include +#include + #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" #include "tegra20-cpu-opp-microvolt.dtsi" @@ -318,6 +320,7 @@ nvidia,ram-code = <0x0>; #address-cells = <1>; #size-cells = <0>; + reg = <0>; emc-table@166500 { reg = <166500>; @@ -497,9 +500,10 @@ }; }; - adt7461@4c { + adt7461: temperature-sensor@4c { compatible = "adi,adt7461"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; }; @@ -654,11 +658,46 @@ cpu0: cpu@0 { cpu-supply = <&cpu_vdd_reg>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; - cpu@1 { + cpu1: cpu@1 { cpu-supply = <&cpu_vdd_reg>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <500>; /* milliseconds */ + polling-delay = <1500>; /* milliseconds */ + + thermal-sensors = <&adt7461 1>; + + trips { + trip0: cpu-alert0 { + /* start throttling at 80C */ + temperature = <80000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 85C */ + temperature = <85000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; }; }; diff --git a/arch/arm/boot/dts/tegra20-plutux.dts b/arch/arm/boot/dts/tegra20-plutux.dts index 378f23b2958b..5811b7006a9b 100644 --- a/arch/arm/boot/dts/tegra20-plutux.dts +++ b/arch/arm/boot/dts/tegra20-plutux.dts @@ -52,7 +52,7 @@ nvidia,audio-codec = <&wm8903>; nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_HIGH>; + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>; clocks = <&tegra_car TEGRA20_CLK_PLL_A>, <&tegra_car TEGRA20_CLK_PLL_A_OUT0>, diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index c24d4a37613e..92d494b8c3d2 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -911,7 +911,7 @@ nvidia,audio-codec = <&wm8903>; nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(X, 1) GPIO_ACTIVE_HIGH>; + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(X, 1) GPIO_ACTIVE_LOW>; clocks = <&tegra_car TEGRA20_CLK_PLL_A>, <&tegra_car TEGRA20_CLK_PLL_A_OUT0>, diff --git a/arch/arm/boot/dts/tegra20-tec.dts b/arch/arm/boot/dts/tegra20-tec.dts index 44ced60315de..10ff09d86efa 100644 --- a/arch/arm/boot/dts/tegra20-tec.dts +++ b/arch/arm/boot/dts/tegra20-tec.dts @@ -61,7 +61,7 @@ nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) - GPIO_ACTIVE_HIGH>; + GPIO_ACTIVE_LOW>; clocks = <&tegra_car TEGRA20_CLK_PLL_A>, <&tegra_car TEGRA20_CLK_PLL_A_OUT0>, diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index 99a356c1ccec..5a2578b3707f 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -709,7 +709,7 @@ nvidia,audio-codec = <&wm8903>; nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_HIGH>; + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>; nvidia,int-mic-en-gpios = <&gpio TEGRA_GPIO(X, 0) GPIO_ACTIVE_HIGH>; nvidia,ext-mic-en-gpios = <&gpio TEGRA_GPIO(X, 1) diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi index dc773b1bf8ee..ae8300baa2d4 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi @@ -927,7 +927,6 @@ compatible = "ti,bq27541"; reg = <0x55>; power-supplies = <&power_supply>; - monitored-battery = <&battery_cell>; }; power_supply: charger@6a { @@ -1252,13 +1251,6 @@ }; thermal-zones { - skin-thermal { - polling-delay-passive = <1000>; /* milliseconds */ - polling-delay = <0>; /* milliseconds */ - - thermal-sensors = <&nct72 0>; - }; - cpu-thermal { polling-delay-passive = <1000>; /* milliseconds */ polling-delay = <5000>; /* milliseconds */ @@ -1274,8 +1266,8 @@ }; trip1: cpu-crit { - /* shut down at 60C */ - temperature = <60000>; + /* shut down at 65C */ + temperature = <65000>; hysteresis = <2000>; type = "critical"; }; @@ -1287,7 +1279,9 @@ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&actmon THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-maxim-pmic.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-maxim-pmic.dtsi index 17b6682ffce8..53966fa4eef2 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-maxim-pmic.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-maxim-pmic.dtsi @@ -182,4 +182,13 @@ enable-active-high; vin-supply = <&vdd_3v3_sys>; }; + + pmc@7000e400 { + i2c-thermtrip { + nvidia,i2c-controller-id = <4>; + nvidia,bus-addr = <0x3c>; + nvidia,reg-addr = <0x41>; + nvidia,reg-data = <0xe0>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi index b97da45ebdb4..9365ae607239 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-ti-pmic.dtsi @@ -144,7 +144,16 @@ }; vdd_3v3_sys: regulator@1 { - gpio = <&pmic 7 GPIO_ACTIVE_HIGH>; + gpio = <&pmic 6 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + pmc@7000e400 { + i2c-thermtrip { + nvidia,i2c-controller-id = <4>; + nvidia,bus-addr = <0x2d>; + nvidia,reg-addr = <0x3f>; + nvidia,reg-data = <0x80>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 2dff14b87f3e..d9dd11569d4b 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -630,7 +630,7 @@ nvidia,spkr-en-gpios = <&wm8903 2 GPIO_ACTIVE_HIGH>; nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(W, 2) - GPIO_ACTIVE_HIGH>; + GPIO_ACTIVE_LOW>; clocks = <&tegra_car TEGRA30_CLK_PLL_A>, <&tegra_car TEGRA30_CLK_PLL_A_OUT0>, diff --git a/arch/arm/boot/dts/tegra30-ouya.dts b/arch/arm/boot/dts/tegra30-ouya.dts index 9a10e0d69762..ab8744f3d72d 100644 --- a/arch/arm/boot/dts/tegra30-ouya.dts +++ b/arch/arm/boot/dts/tegra30-ouya.dts @@ -463,7 +463,9 @@ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&actmon THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 44a6dbba7081..c577c191be4b 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -410,7 +410,7 @@ reg = <0x6000c000 0x150>; /* AHB Arbitration + Gizmo Controller */ }; - actmon@6000c800 { + actmon: actmon@6000c800 { compatible = "nvidia,tegra30-actmon"; reg = <0x6000c800 0x400>; interrupts = ; @@ -422,6 +422,7 @@ operating-points-v2 = <&emc_bw_dfs_opp_table>; interconnects = <&mc TEGRA30_MC_MPCORER &emc>; interconnect-names = "cpu-read"; + #cooling-cells = <2>; }; gpio: gpio@6000d000 { diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig index 58d293b63581..a3ee647b1ebb 100644 --- a/arch/arm/configs/aspeed_g4_defconfig +++ b/arch/arm/configs/aspeed_g4_defconfig @@ -254,6 +254,7 @@ CONFIG_DEBUG_INFO_REDUCED=y CONFIG_DEBUG_INFO_DWARF4=y CONFIG_GDB_SCRIPTS=y CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_PANIC_ON_OOPS=y CONFIG_PANIC_TIMEOUT=-1 diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig index 047975eccefb..2db48438c5d2 100644 --- a/arch/arm/configs/aspeed_g5_defconfig +++ b/arch/arm/configs/aspeed_g5_defconfig @@ -247,6 +247,7 @@ CONFIG_FSI_MASTER_ASPEED=y CONFIG_FSI_SCOM=y CONFIG_FSI_SBEFIFO=y CONFIG_FSI_OCC=y +CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y CONFIG_OVERLAY_FS=y CONFIG_TMPFS=y @@ -276,6 +277,7 @@ CONFIG_DEBUG_INFO_REDUCED=y CONFIG_DEBUG_INFO_DWARF4=y CONFIG_GDB_SCRIPTS=y CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y CONFIG_SOFTLOCKUP_DETECTOR=y # CONFIG_DETECT_HUNG_TASK is not set CONFIG_WQ_WATCHDOG=y diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 06c888a45eb3..b1564e0aa000 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -1,6 +1,8 @@ # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 513f56b3c059..f4e1873912a3 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -236,6 +236,7 @@ CONFIG_DRM_SII9234=y CONFIG_DRM_TOSHIBA_TC358764=y CONFIG_DRM_LIMA=y CONFIG_DRM_PANFROST=y +CONFIG_FB=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=y CONFIG_BACKLIGHT_PWM=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 70928cc48939..079fcd8d1d11 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -150,6 +150,8 @@ CONFIG_USB_USBNET=y CONFIG_USB_NET_CDC_EEM=m CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_NET_MCS7830=y +CONFIG_ATH10K=m +CONFIG_ATH10K_SDIO=m CONFIG_BRCMFMAC=m CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 0d6edeb27659..9a7667383df9 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -109,6 +109,8 @@ CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP4XX=y CONFIG_MTD_RAW_NAND=m @@ -152,6 +154,7 @@ CONFIG_INPUT_IXP4XX_BEEPER=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_OF_PLATFORM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_SENSORS_W83781D=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 77b4bea12feb..2ac2418084ab 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -276,6 +276,7 @@ CONFIG_BT_MRVL_SDIO=m CONFIG_AF_RXRPC=m CONFIG_RXKAD=y CONFIG_CFG80211=m +CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=m CONFIG_PCI=y CONFIG_PCI_MSI=y @@ -374,6 +375,8 @@ CONFIG_LIBERTAS_DEBUG=y CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m CONFIG_MWIFIEX_USB=m +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m CONFIG_WL12XX=m CONFIG_WL18XX=m CONFIG_WLCORE_SPI=m @@ -617,6 +620,8 @@ CONFIG_LEDS_CLASS=m CONFIG_LEDS_CPCAP=m CONFIG_LEDS_LM3532=m CONFIG_LEDS_GPIO=m +CONFIG_LEDS_LP55XX_COMMON=m +CONFIG_LEDS_LP5523=m CONFIG_LEDS_PCA963X=m CONFIG_LEDS_PWM=m CONFIG_LEDS_TRIGGERS=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index f25b09efb816..66c8b0980a0a 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -202,7 +202,6 @@ CONFIG_AK8975=y CONFIG_PWM=y CONFIG_PWM_RCAR=y CONFIG_PWM_RENESAS_TPU=y -CONFIG_RESET_CONTROLLER=y CONFIG_PHY_RCAR_GEN2=y CONFIG_PHY_RCAR_GEN3_USB2=y # CONFIG_DNOTIFY is not set diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 13ef3e4dcbb7..3d8d8af9524d 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -167,6 +167,7 @@ CONFIG_SENSORS_LM95245=y CONFIG_THERMAL=y CONFIG_THERMAL_STATISTICS=y CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y CONFIG_TEGRA_SOCTHERM=m CONFIG_WATCHDOG=y CONFIG_MAX77620_WATCHDOG=y diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index 48ec1d0337da..a4dbac07e4ef 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -15,6 +15,9 @@ extern void __gnu_mcount_nc(void); #ifdef CONFIG_DYNAMIC_FTRACE struct dyn_arch_ftrace { +#ifdef CONFIG_ARM_MODULE_PLTS + struct module *mod; +#endif }; static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/arm/include/asm/insn.h b/arch/arm/include/asm/insn.h index f20e08ac85ae..5475cbf9fb6b 100644 --- a/arch/arm/include/asm/insn.h +++ b/arch/arm/include/asm/insn.h @@ -13,18 +13,18 @@ arm_gen_nop(void) } unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link); +__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool warn); static inline unsigned long arm_gen_branch(unsigned long pc, unsigned long addr) { - return __arm_gen_branch(pc, addr, false); + return __arm_gen_branch(pc, addr, false, true); } static inline unsigned long -arm_gen_branch_link(unsigned long pc, unsigned long addr) +arm_gen_branch_link(unsigned long pc, unsigned long addr, bool warn) { - return __arm_gen_branch(pc, addr, true); + return __arm_gen_branch(pc, addr, true, warn); } #endif diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index a711322d9f40..cfc9dfd70aad 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -20,8 +20,14 @@ #endif #include -/* PAGE_OFFSET - the virtual address of the start of the kernel image */ +/* + * PAGE_OFFSET: the virtual address of the start of lowmem, memory above + * the virtual address range for userspace. + * KERNEL_OFFSET: the virtual address of the start of the kernel image. + * we may further offset this with TEXT_OFFSET in practice. + */ #define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) +#define KERNEL_OFFSET (PAGE_OFFSET) #ifdef CONFIG_MMU @@ -152,6 +158,13 @@ extern unsigned long vectors_base; #ifndef __ASSEMBLY__ +/* + * Physical start and end address of the kernel sections. These addresses are + * 2MB-aligned to match the section mappings placed over the kernel. + */ +extern u32 kernel_sec_start; +extern u32 kernel_sec_end; + /* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index 4b0df09cbe67..cfffae67c04e 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h @@ -19,8 +19,18 @@ enum { }; #endif +#define PLT_ENT_STRIDE L1_CACHE_BYTES +#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32)) +#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT) + +struct plt_entries { + u32 ldr[PLT_ENT_COUNT]; + u32 lit[PLT_ENT_COUNT]; +}; + struct mod_plt_sec { struct elf32_shdr *plt; + struct plt_entries *plt_ent; int plt_count; }; diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index d4edab51a77c..eabe72ff7381 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -130,7 +130,7 @@ flush_pmd_entry(pudp); \ } while (0) -static inline pmd_t *pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); } diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index d63a5bb6bd0c..cd1f84bb40ae 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -306,7 +306,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) +#define __swp_entry_to_pte(swp) __pte((swp).val | PTE_TYPE_FAULT) /* * It is an error for the kernel to have more swap files than we can diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 9a79ef6b1876..3c83b5d29697 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -68,9 +68,10 @@ int ftrace_arch_code_modify_post_process(void) return 0; } -static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) +static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr, + bool warn) { - return arm_gen_branch_link(pc, addr); + return arm_gen_branch_link(pc, addr, warn); } static int ftrace_modify_code(unsigned long pc, unsigned long old, @@ -104,14 +105,14 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int ret; pc = (unsigned long)&ftrace_call; - new = ftrace_call_replace(pc, (unsigned long)func); + new = ftrace_call_replace(pc, (unsigned long)func, true); ret = ftrace_modify_code(pc, 0, new, false); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS if (!ret) { pc = (unsigned long)&ftrace_regs_call; - new = ftrace_call_replace(pc, (unsigned long)func); + new = ftrace_call_replace(pc, (unsigned long)func, true); ret = ftrace_modify_code(pc, 0, new, false); } @@ -124,10 +125,22 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned long new, old; unsigned long ip = rec->ip; + unsigned long aaddr = adjust_address(rec, addr); + struct module *mod = NULL; + +#ifdef CONFIG_ARM_MODULE_PLTS + mod = rec->arch.mod; +#endif old = ftrace_nop_replace(rec); - new = ftrace_call_replace(ip, adjust_address(rec, addr)); + new = ftrace_call_replace(ip, aaddr, !mod); +#ifdef CONFIG_ARM_MODULE_PLTS + if (!new && mod) { + aaddr = get_module_plt(mod, ip, aaddr); + new = ftrace_call_replace(ip, aaddr, true); + } +#endif return ftrace_modify_code(rec->ip, old, new, true); } @@ -140,9 +153,9 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long new, old; unsigned long ip = rec->ip; - old = ftrace_call_replace(ip, adjust_address(rec, old_addr)); + old = ftrace_call_replace(ip, adjust_address(rec, old_addr), true); - new = ftrace_call_replace(ip, adjust_address(rec, addr)); + new = ftrace_call_replace(ip, adjust_address(rec, addr), true); return ftrace_modify_code(rec->ip, old, new, true); } @@ -152,12 +165,29 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { + unsigned long aaddr = adjust_address(rec, addr); unsigned long ip = rec->ip; unsigned long old; unsigned long new; int ret; - old = ftrace_call_replace(ip, adjust_address(rec, addr)); +#ifdef CONFIG_ARM_MODULE_PLTS + /* mod is only supplied during module loading */ + if (!mod) + mod = rec->arch.mod; + else + rec->arch.mod = mod; +#endif + + old = ftrace_call_replace(ip, aaddr, + !IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || !mod); +#ifdef CONFIG_ARM_MODULE_PLTS + if (!old && mod) { + aaddr = get_module_plt(mod, ip, aaddr); + old = ftrace_call_replace(ip, aaddr, true); + } +#endif + new = ftrace_nop_replace(rec); ret = ftrace_modify_code(ip, old, new, true); diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 7f62c5eccdf3..9eb0b4dbcc12 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -23,7 +23,6 @@ #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING) #include CONFIG_DEBUG_LL_INCLUDE #endif - /* * swapper_pg_dir is the virtual address of the initial page table. * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must @@ -31,7 +30,7 @@ * the least significant 16 bits to be 0x8000, but we could probably * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. */ -#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) +#define KERNEL_RAM_VADDR (KERNEL_OFFSET + TEXT_OFFSET) #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 #error KERNEL_RAM_VADDR must start at 0xXXXX8000 #endif @@ -48,6 +47,20 @@ .globl swapper_pg_dir .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE + /* + * This needs to be assigned at runtime when the linker symbols are + * resolved. + */ + .pushsection .data + .align 2 + .globl kernel_sec_start + .globl kernel_sec_end +kernel_sec_start: + .long 0 +kernel_sec_end: + .long 0 + .popsection + .macro pgtbl, rd, phys add \rd, \phys, #TEXT_OFFSET sub \rd, \rd, #PG_DIR_SIZE @@ -230,16 +243,23 @@ __create_page_tables: blo 1b /* - * Map our RAM from the start to the end of the kernel .bss section. + * The main matter: map in the kernel using section mappings, and + * set two variables to indicate the physical start and end of the + * kernel. */ - add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER) + add r0, r4, #KERNEL_OFFSET >> (SECTION_SHIFT - PMD_ORDER) ldr r6, =(_end - 1) - orr r3, r8, r7 + adr_l r5, kernel_sec_start @ _pa(kernel_sec_start) + str r8, [r5] @ Save physical start of kernel + orr r3, r8, r7 @ Add the MMU flags add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER) 1: str r3, [r0], #1 << PMD_ORDER add r3, r3, #1 << SECTION_SHIFT cmp r0, r6 bls 1b + eor r3, r3, r7 @ Remove the MMU flags + adr_l r5, kernel_sec_end @ _pa(kernel_sec_end) + str r3, [r5] @ Save physical end of kernel #ifdef CONFIG_XIP_KERNEL /* diff --git a/arch/arm/kernel/insn.c b/arch/arm/kernel/insn.c index 2e844b70386b..db0acbb7d7a0 100644 --- a/arch/arm/kernel/insn.c +++ b/arch/arm/kernel/insn.c @@ -3,8 +3,9 @@ #include #include -static unsigned long -__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) +static unsigned long __arm_gen_branch_thumb2(unsigned long pc, + unsigned long addr, bool link, + bool warn) { unsigned long s, j1, j2, i1, i2, imm10, imm11; unsigned long first, second; @@ -12,7 +13,7 @@ __arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) offset = (long)addr - (long)(pc + 4); if (offset < -16777216 || offset > 16777214) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(warn); return 0; } @@ -33,8 +34,8 @@ __arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) return __opcode_thumb32_compose(first, second); } -static unsigned long -__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) +static unsigned long __arm_gen_branch_arm(unsigned long pc, unsigned long addr, + bool link, bool warn) { unsigned long opcode = 0xea000000; long offset; @@ -44,7 +45,7 @@ __arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) offset = (long)addr - (long)(pc + 8); if (unlikely(offset < -33554432 || offset > 33554428)) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(warn); return 0; } @@ -54,10 +55,10 @@ __arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) } unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link) +__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool warn) { if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) - return __arm_gen_branch_thumb2(pc, addr, link); + return __arm_gen_branch_thumb2(pc, addr, link, warn); else - return __arm_gen_branch_arm(pc, addr, link); + return __arm_gen_branch_arm(pc, addr, link, warn); } diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 6e626abaefc5..1fc309b41f94 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -12,10 +13,6 @@ #include #include -#define PLT_ENT_STRIDE L1_CACHE_BYTES -#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32)) -#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT) - #ifdef CONFIG_THUMB2_KERNEL #define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \ (PLT_ENT_STRIDE - 4)) @@ -24,9 +21,11 @@ (PLT_ENT_STRIDE - 8)) #endif -struct plt_entries { - u32 ldr[PLT_ENT_COUNT]; - u32 lit[PLT_ENT_COUNT]; +static const u32 fixed_plts[] = { +#ifdef CONFIG_DYNAMIC_FTRACE + FTRACE_ADDR, + MCOUNT_ADDR, +#endif }; static bool in_init(const struct module *mod, unsigned long loc) @@ -34,14 +33,40 @@ static bool in_init(const struct module *mod, unsigned long loc) return loc - (u32)mod->init_layout.base < mod->init_layout.size; } +static void prealloc_fixed(struct mod_plt_sec *pltsec, struct plt_entries *plt) +{ + int i; + + if (!ARRAY_SIZE(fixed_plts) || pltsec->plt_count) + return; + pltsec->plt_count = ARRAY_SIZE(fixed_plts); + + for (i = 0; i < ARRAY_SIZE(plt->ldr); ++i) + plt->ldr[i] = PLT_ENT_LDR; + + BUILD_BUG_ON(sizeof(fixed_plts) > sizeof(plt->lit)); + memcpy(plt->lit, fixed_plts, sizeof(fixed_plts)); +} + u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : &mod->arch.init; + struct plt_entries *plt; + int idx; - struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr; - int idx = 0; + /* cache the address, ELF header is available only during module load */ + if (!pltsec->plt_ent) + pltsec->plt_ent = (struct plt_entries *)pltsec->plt->sh_addr; + plt = pltsec->plt_ent; + prealloc_fixed(pltsec, plt); + + for (idx = 0; idx < ARRAY_SIZE(fixed_plts); ++idx) + if (plt->lit[idx] == val) + return (u32)&plt->ldr[idx]; + + idx = 0; /* * Look for an existing entry pointing to 'val'. Given that the * relocations are sorted, this will be the last entry we allocated. @@ -189,8 +214,8 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { - unsigned long core_plts = 0; - unsigned long init_plts = 0; + unsigned long core_plts = ARRAY_SIZE(fixed_plts); + unsigned long init_plts = ARRAY_SIZE(fixed_plts); Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; Elf32_Sym *syms = NULL; @@ -245,6 +270,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, sizeof(struct plt_entries)); mod->arch.core.plt_count = 0; + mod->arch.core.plt_ent = NULL; mod->arch.init.plt->sh_type = SHT_NOBITS; mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; @@ -252,6 +278,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, sizeof(struct plt_entries)); mod->arch.init.plt_count = 0; + mod->arch.init.plt_ent = NULL; pr_debug("%s: plt=%x, init.plt=%x\n", __func__, mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 7693a1f05ecc..f97eb2371672 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -1130,10 +1130,7 @@ void __init setup_arch(char **cmdline_p) if (mdesc->reboot_mode != REBOOT_HARD) reboot_mode = mdesc->reboot_mode; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_text, _etext, _edata, _end); /* populate cmd_line too for later use, preserving boot_command_line */ strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index f7f4620d59c3..20c4f6d20c7a 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -47,7 +47,7 @@ SECTIONS #endif } - . = PAGE_OFFSET + TEXT_OFFSET; + . = KERNEL_OFFSET + TEXT_OFFSET; .head.text : { _text = .; HEAD_TEXT diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 25b01da4771b..8b48326be9fd 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -55,6 +55,7 @@ void __init exynos_sysram_init(void) sysram_base_addr = of_iomap(node, 0); sysram_base_phys = of_translate_address(node, of_get_address(node, 0, NULL, NULL)); + of_node_put(node); break; } @@ -62,6 +63,7 @@ void __init exynos_sysram_init(void) if (!of_device_is_available(node)) continue; sysram_ns_base_addr = of_iomap(node, 0); + of_node_put(node); break; } } diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 9cebd360d58e..d1506ef7a537 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o -ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) +ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_IMX7D_CA7)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 474dedb73bc7..f0a073a71401 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -68,11 +68,13 @@ void imx_set_cpu_arg(int cpu, u32 arg); void v7_secondary_startup(void); void imx_scu_map_io(void); void imx_smp_prepare(void); +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn); #else static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} #endif void imx_src_init(void); +void imx7_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); @@ -131,6 +133,7 @@ static inline void imx_init_l2cache(void) {} #endif extern const struct smp_operations imx_smp_ops; +extern const struct smp_operations imx7_smp_ops; extern const struct smp_operations ls1021a_smp_ops; #endif diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 766dbdb2ae27..fcba58be8e79 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -21,6 +21,15 @@ diag_reg_offset: ENTRY(v7_secondary_startup) ARM_BE8(setend be) @ go BE8 if entered LE + mrc p15, 0, r0, c0, c0, 0 + lsl r0, r0, #16 + lsr r0, r0, #20 + /* 0xc07 is cortex A7's ID */ + mov r1, #0xc00 + orr r1, #0x7 + cmp r0, r1 + beq secondary_startup + set_diag_reg b secondary_startup ENDPROC(v7_secondary_startup) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 82e22398d43d..e24a46dc5703 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -11,6 +11,7 @@ #include #include "common.h" +#include "hardware.h" /* * platform-specific code to shutdown a CPU @@ -40,5 +41,7 @@ int imx_cpu_kill(unsigned int cpu) return 0; imx_enable_cpu(cpu, false); imx_set_cpu_arg(cpu, 0); + if (cpu_is_imx7d()) + imx_gpcv2_set_core1_pdn_pup_by_software(true); return 1; } diff --git a/arch/arm/mach-imx/mach-imx50.c b/arch/arm/mach-imx/mach-imx50.c index f4da205f57db..a2d35f9ba474 100644 --- a/arch/arm/mach-imx/mach-imx50.c +++ b/arch/arm/mach-imx/mach-imx50.c @@ -9,6 +9,12 @@ #include #include "common.h" +#include "hardware.h" + +static void __init imx50_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX50); +} static const char * const imx50_dt_board_compat[] __initconst = { "fsl,imx50", @@ -16,5 +22,6 @@ static const char * const imx50_dt_board_compat[] __initconst = { }; DT_MACHINE_START(IMX50_DT, "Freescale i.MX50 (Device Tree Support)") + .init_early = imx50_init_early, .dt_compat = imx50_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 703998ebb52e..11dcc369ec14 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -40,27 +40,6 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev) return 0; } -static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val) -{ - phy_write(dev, 0x0d, device); - phy_write(dev, 0x0e, reg); - phy_write(dev, 0x0d, (1 << 14) | device); - phy_write(dev, 0x0e, val); -} - -static int ksz9031rn_phy_fixup(struct phy_device *dev) -{ - /* - * min rx data delay, max rx/tx clock delay, - * min rx/tx control delay - */ - mmd_write_reg(dev, 2, 4, 0); - mmd_write_reg(dev, 2, 5, 0); - mmd_write_reg(dev, 2, 8, 0x003ff); - - return 0; -} - /* * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High * as they are used for slots1-7 PERST# @@ -89,75 +68,11 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup); -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* To enable AR8031 output a 125MHz clk from CLK_25M */ - phy_write(dev, 0xd, 0x7); - phy_write(dev, 0xe, 0x8016); - phy_write(dev, 0xd, 0x4007); - - val = phy_read(dev, 0xe); - val &= 0xffe3; - val |= 0x18; - phy_write(dev, 0xe, val); - - /* introduce tx clock delay */ - phy_write(dev, 0x1d, 0x5); - val = phy_read(dev, 0x1e); - val |= 0x0100; - phy_write(dev, 0x1e, val); - - return 0; -} - -#define PHY_ID_AR8031 0x004dd074 - -static int ar8035_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Ar803x phy SmartEEE feature cause link status generates glitch, - * which cause ethernet link down/up issue, so disable SmartEEE - */ - phy_write(dev, 0xd, 0x3); - phy_write(dev, 0xe, 0x805d); - phy_write(dev, 0xd, 0x4003); - - val = phy_read(dev, 0xe); - phy_write(dev, 0xe, val & ~(1 << 8)); - - /* - * Enable 125MHz clock from CLK_25M on the AR8031. This - * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad. - * Also, introduce a tx clock delay. - * - * This is the same as is the AR8031 fixup. - */ - ar8031_phy_fixup(dev); - - /*check phy power*/ - val = phy_read(dev, 0x0); - if (val & BMCR_PDOWN) - phy_write(dev, 0x0, val & ~BMCR_PDOWN); - - return 0; -} - -#define PHY_ID_AR8035 0x004dd072 - static void __init imx6q_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) { phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, ksz9021rn_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK, - ksz9031rn_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef, - ar8031_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef, - ar8035_phy_fixup); } } @@ -257,9 +172,6 @@ static void __init imx6q_init_machine(void) imx_get_soc_revision()); imx6q_enet_phy_init(); - - of_platform_default_populate(NULL, NULL, NULL); - imx_anatop_init(); cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); imx6q_1588_init(); diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index 781e2a94fdd7..e65ed5218f53 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -15,31 +15,6 @@ #include "common.h" #include "cpuidle.h" -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Set RGMII IO voltage to 1.8V */ - phy_write(dev, 0x1d, 0x1f); - phy_write(dev, 0x1e, 0x8); - - /* introduce tx clock delay */ - phy_write(dev, 0x1d, 0x5); - val = phy_read(dev, 0x1e); - val |= 0x0100; - phy_write(dev, 0x1e, val); - - return 0; -} - -#define PHY_ID_AR8031 0x004dd074 -static void __init imx6sx_enet_phy_init(void) -{ - if (IS_BUILTIN(CONFIG_PHYLIB)) - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, - ar8031_phy_fixup); -} - static void __init imx6sx_enet_clk_sel(void) { struct regmap *gpr; @@ -57,7 +32,6 @@ static void __init imx6sx_enet_clk_sel(void) static inline void imx6sx_enet_init(void) { - imx6sx_enet_phy_init(); imx6sx_enet_clk_sel(); } diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 879c35929a13..6fdd06bcf988 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -14,25 +14,6 @@ #include "common.h" -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Set RGMII IO voltage to 1.8V */ - phy_write(dev, 0x1d, 0x1f); - phy_write(dev, 0x1e, 0x8); - - /* disable phy AR8031 SmartEEE function. */ - phy_write(dev, 0xd, 0x3); - phy_write(dev, 0xe, 0x805d); - phy_write(dev, 0xd, 0x4003); - val = phy_read(dev, 0xe); - val &= ~(0x1 << 8); - phy_write(dev, 0xe, val); - - return 0; -} - static int bcm54220_phy_fixup(struct phy_device *dev) { /* enable RXC skew select RGMII copper mode */ @@ -44,14 +25,11 @@ static int bcm54220_phy_fixup(struct phy_device *dev) return 0; } -#define PHY_ID_AR8031 0x004dd074 #define PHY_ID_BCM54220 0x600d8589 static void __init imx7d_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) { - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, - ar8031_phy_fixup); phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff, bcm54220_phy_fixup); } @@ -91,7 +69,7 @@ static void __init imx7d_init_late(void) static void __init imx7d_init_irq(void) { imx_init_revision_from_anatop(); - imx_src_init(); + imx7_src_init(); irqchip_init(); } @@ -102,6 +80,7 @@ static const char *const imx7d_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") + .smp = smp_ops(imx7_smp_ops), .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .init_late = imx7d_init_late, diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index cf4e9335831c..972639038be5 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -92,6 +92,32 @@ const struct smp_operations imx_smp_ops __initconst = { #endif }; +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init imx7_smp_init_cpus(void) +{ + struct device_node *np; + int i, ncores = 0; + + /* The iMX7D SCU does not report core count, get it from DT */ + for_each_of_cpu_node(np) + ncores++; + + for (i = ncores; i < NR_CPUS; i++) + set_cpu_possible(i, false); +} + +const struct smp_operations imx7_smp_ops __initconst = { + .smp_init_cpus = imx7_smp_init_cpus, + .smp_boot_secondary = imx_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = imx_cpu_die, + .cpu_kill = imx_cpu_kill, +#endif +}; + #define DCFG_CCSR_SCRATCHRW1 0x200 static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle) diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index f52f371292ac..95fd1fbb0826 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -6,15 +6,19 @@ #include #include +#include #include #include #include #include #include #include "common.h" +#include "hardware.h" #define SRC_SCR 0x000 -#define SRC_GPR1 0x020 +#define SRC_GPR1_V1 0x020 +#define SRC_GPR1_V2 0x074 +#define SRC_GPR1(gpr_v2) ((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1) #define BP_SRC_SCR_WARM_RESET_ENABLE 0 #define BP_SRC_SCR_SW_GPU_RST 1 #define BP_SRC_SCR_SW_VPU_RST 2 @@ -23,9 +27,18 @@ #define BP_SRC_SCR_SW_IPU2_RST 12 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 +/* below is for i.MX7D */ +#define SRC_A7RCR1 0x008 +#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0 +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc +#define GPC_PGC_C1 0x840 +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2 static void __iomem *src_base; static DEFINE_SPINLOCK(scr_lock); +static bool gpr_v2; +static void __iomem *gpc_base; static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_GPU_RST, @@ -73,17 +86,64 @@ static struct reset_controller_dev imx_reset_controller = { .nr_resets = ARRAY_SIZE(sw_reset_bits), }; +static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset) +{ + writel_relaxed(enable, gpc_base + offset); +} + +/* + * The motivation for bringing up the second i.MX7D core inside the kernel + * is that legacy vendor bootloaders usually do not implement PSCI support. + * This is a significant blocker for systems in the field that are running old + * bootloader versions to upgrade to a modern mainline kernel version, as only + * one CPU of the i.MX7D would be brought up. + * Bring up the second i.MX7D core inside the kernel to make the migration + * path to mainline kernel easier for the existing iMX7D users. + */ +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) +{ + u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ; + u32 val, pup; + int ret; + + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val = readl_relaxed(gpc_base + reg); + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + reg); + + ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup, + !(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7), + 5, 1000000); + if (ret < 0) { + pr_err("i.MX7D: CORE1_A7 power up timeout\n"); + val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + reg); + } + + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); +} + void imx_enable_cpu(int cpu, bool enable) { u32 mask, val; cpu = cpu_logical_map(cpu); - mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); spin_lock(&scr_lock); - val = readl_relaxed(src_base + SRC_SCR); - val = enable ? val | mask : val & ~mask; - val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); - writel_relaxed(val, src_base + SRC_SCR); + if (gpr_v2) { + if (enable) + imx_gpcv2_set_core1_pdn_pup_by_software(false); + + mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_A7RCR1); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_A7RCR1); + } else { + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + } spin_unlock(&scr_lock); } @@ -91,19 +151,19 @@ void imx_set_cpu_jump(int cpu, void *jump_addr) { cpu = cpu_logical_map(cpu); writel_relaxed(__pa_symbol(jump_addr), - src_base + SRC_GPR1 + cpu * 8); + src_base + SRC_GPR1(gpr_v2) + cpu * 8); } u32 imx_get_cpu_arg(int cpu) { cpu = cpu_logical_map(cpu); - return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); + return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); } void imx_set_cpu_arg(int cpu, u32 arg) { cpu = cpu_logical_map(cpu); - writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); } void __init imx_src_init(void) @@ -131,3 +191,26 @@ void __init imx_src_init(void) writel_relaxed(val, src_base + SRC_SCR); spin_unlock(&scr_lock); } + +void __init imx7_src_init(void) +{ + struct device_node *np; + + gpr_v2 = true; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src"); + if (!np) + return; + + src_base = of_iomap(np, 0); + if (!src_base) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc"); + if (!np) + return; + + gpc_base = of_iomap(np, 0); + if (!gpc_base) + return; +} diff --git a/arch/arm/mach-imx/suspend-imx53.S b/arch/arm/mach-imx/suspend-imx53.S index 41b8aad65363..46570ec2fbcf 100644 --- a/arch/arm/mach-imx/suspend-imx53.S +++ b/arch/arm/mach-imx/suspend-imx53.S @@ -28,11 +28,11 @@ * ^ * ^ * imx53_suspend code - * PM_INFO structure(imx53_suspend_info) + * PM_INFO structure(imx5_cpu_suspend_info) * ======================== low address ======================= */ -/* Offsets of members of struct imx53_suspend_info */ +/* Offsets of members of struct imx5_cpu_suspend_info */ #define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0 #define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4 #define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8 diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 165c184801e1..bf14d65120b9 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -7,7 +7,7 @@ comment "IXP4xx Platforms" config MACH_IXP4XX_OF bool - prompt "Devce Tree IXP4xx boards" + prompt "Device Tree IXP4xx boards" default y select ARM_APPENDED_DTB # Old Redboot bootloaders deployed select I2C @@ -20,7 +20,7 @@ config MACH_IXP4XX_OF config MACH_NSLU2 bool prompt "Linksys NSLU2" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Linksys's NSLU2 NAS device. For more information on this platform, @@ -28,7 +28,7 @@ config MACH_NSLU2 config MACH_AVILA bool "Avila" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the Gateworks Avila Network Platform. For more information on this platform, @@ -44,7 +44,7 @@ config MACH_LOFT config ARCH_ADI_COYOTE bool "Coyote" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the ADI Engineering Coyote Gateway Reference Platform. For more @@ -52,7 +52,7 @@ config ARCH_ADI_COYOTE config MACH_GATEWAY7001 bool "Gateway 7001" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Gateway's 7001 Access Point. For more information on this platform, @@ -60,7 +60,7 @@ config MACH_GATEWAY7001 config MACH_WG302V2 bool "Netgear WG302 v2 / WAG302 v2" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Netgear's WG302 v2 or WAG302 v2 Access Points. For more information @@ -68,6 +68,7 @@ config MACH_WG302V2 config ARCH_IXDP425 bool "IXDP425" + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Intel's IXDP425 Development Platform (Also known as Richfield). @@ -75,6 +76,7 @@ config ARCH_IXDP425 config MACH_IXDPG425 bool "IXDPG425" + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Intel's IXDPG425 Development Platform (Also known as Montajade). @@ -120,7 +122,7 @@ config ARCH_PRPMC1100 config MACH_NAS100D bool prompt "NAS100D" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Iomega's NAS 100d device. For more information on this platform, @@ -129,7 +131,7 @@ config MACH_NAS100D config MACH_DSMG600 bool prompt "D-Link DSM-G600 RevA" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support D-Link's DSM-G600 RevA device. For more information on this platform, @@ -143,7 +145,7 @@ config ARCH_IXDP4XX config MACH_FSG bool prompt "Freecom FSG-3" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Freecom's FSG-3 device. For more information on this platform, @@ -152,7 +154,7 @@ config MACH_FSG config MACH_ARCOM_VULCAN bool prompt "Arcom/Eurotech Vulcan" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Arcom's Vulcan board. @@ -173,7 +175,7 @@ config CPU_IXP43X config MACH_GTWX5715 bool "Gemtek WX5715 (Linksys WRV54G)" depends on ARCH_IXP4XX - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help This board is currently inside the Linksys WRV54G Gateways. @@ -196,7 +198,7 @@ config MACH_DEVIXP config MACH_MICCPT bool "Omicron MICCPT" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the MICCPT board from OMICRON electronics GmbH. @@ -209,9 +211,16 @@ config MACH_MIC256 comment "IXP4xx Options" +config IXP4XX_PCI_LEGACY + bool "IXP4xx legacy PCI driver support" + depends on PCI + help + Selects legacy PCI driver. + Not recommended for new development. + config IXP4XX_INDIRECT_PCI bool "Use indirect PCI memory access" - depends on PCI + depends on IXP4XX_PCI_LEGACY help IXP4xx provides two methods of accessing PCI memory space: diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c index 1981b33109cb..ec1d3029f80c 100644 --- a/arch/arm/mach-ixp4xx/avila-setup.c +++ b/arch/arm/mach-ixp4xx/avila-setup.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 007a44412e24..b5eadd70d903 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -27,12 +27,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -44,6 +44,27 @@ #include "irqs.h" +u32 ixp4xx_read_feature_bits(void) +{ + u32 val = ~__raw_readl(IXP4XX_EXP_CFG2); + + if (cpu_is_ixp42x_rev_a0()) + return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP | + IXP4XX_FEATURE_AES); + if (cpu_is_ixp42x()) + return val & IXP42X_FEATURE_MASK; + if (cpu_is_ixp43x()) + return val & IXP43X_FEATURE_MASK; + return val & IXP46X_FEATURE_MASK; +} +EXPORT_SYMBOL(ixp4xx_read_feature_bits); + +void ixp4xx_write_feature_bits(u32 value) +{ + __raw_writel(~value, IXP4XX_EXP_CFG2); +} +EXPORT_SYMBOL(ixp4xx_write_feature_bits); + #define IXP4XX_TIMER_FREQ 66666000 /************************************************************************* @@ -215,6 +236,27 @@ static struct resource ixp46x_i2c_resources[] = { } }; +/* A single 32-bit register on IXP46x */ +#define IXP4XX_HWRANDOM_BASE_PHYS 0x70002100 + +static struct resource ixp46x_hwrandom_resource[] = { + { + .start = IXP4XX_HWRANDOM_BASE_PHYS, + .end = IXP4XX_HWRANDOM_BASE_PHYS + 0x3, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ixp46x_hwrandom_device = { + .name = "ixp4xx-hwrandom", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = ixp46x_hwrandom_resource, + .num_resources = ARRAY_SIZE(ixp46x_hwrandom_resource), +}; + /* * I2C controller. The IXP46x uses the same block as the IOP3xx, so * we just use the same device name. @@ -227,7 +269,8 @@ static struct platform_device ixp46x_i2c_controller = { }; static struct platform_device *ixp46x_devices[] __initdata = { - &ixp46x_i2c_controller + &ixp46x_hwrandom_device, + &ixp46x_i2c_controller, }; unsigned long ixp4xx_exp_bus_size; diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index 507ee3878769..844329c5610d 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "irqs.h" diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h deleted file mode 100644 index b872a5354ddd..000000000000 --- a/arch/arm/mach-ixp4xx/include/mach/cpu.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ixp4xx/include/mach/cpu.h - * - * IXP4XX cpu type detection - * - * Copyright (C) 2007 MontaVista Software, Inc. - */ - -#ifndef __ASM_ARCH_CPU_H__ -#define __ASM_ARCH_CPU_H__ - -#include -#include - -/* Processor id value in CP15 Register 0 */ -#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */ -#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0 - -#define IXP43X_PROCESSOR_ID_VALUE 0x69054040 -#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0 - -#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */ -#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0 - -#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \ - IXP42X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \ - IXP42X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \ - IXP43X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \ - IXP46X_PROCESSOR_ID_VALUE) - -static inline u32 ixp4xx_read_feature_bits(void) -{ - u32 val = ~__raw_readl(IXP4XX_EXP_CFG2); - - if (cpu_is_ixp42x_rev_a0()) - return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP | - IXP4XX_FEATURE_AES); - if (cpu_is_ixp42x()) - return val & IXP42X_FEATURE_MASK; - if (cpu_is_ixp43x()) - return val & IXP43X_FEATURE_MASK; - return val & IXP46X_FEATURE_MASK; -} - -static inline void ixp4xx_write_feature_bits(u32 value) -{ - __raw_writel(~value, IXP4XX_EXP_CFG2); -} - -#endif /* _ASM_ARCH_CPU_H */ diff --git a/arch/arm/mach-ixp4xx/include/mach/hardware.h b/arch/arm/mach-ixp4xx/include/mach/hardware.h index b884eedcd0fc..b2b7301ce503 100644 --- a/arch/arm/mach-ixp4xx/include/mach/hardware.h +++ b/arch/arm/mach-ixp4xx/include/mach/hardware.h @@ -23,7 +23,7 @@ #include "ixp4xx-regs.h" #ifndef __ASSEMBLER__ -#include +#include #endif /* Platform helper functions and definitions */ diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h index 708d085ce39f..abb07f105515 100644 --- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h @@ -45,21 +45,21 @@ * it can be used with the low-level debug code. */ #define IXP4XX_PERIPHERAL_BASE_PHYS 0xC8000000 -#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEF00000) +#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEC00000) #define IXP4XX_PERIPHERAL_REGION_SIZE 0x00013000 /* * PCI Config registers */ #define IXP4XX_PCI_CFG_BASE_PHYS 0xC0000000 -#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEF13000) +#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEC13000) #define IXP4XX_PCI_CFG_REGION_SIZE 0x00001000 /* * Expansion BUS Configuration registers */ #define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000 -#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEF14000 +#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000 #define IXP4XX_EXP_CFG_REGION_SIZE 0x00001000 #define IXP4XX_EXP_CS0_OFFSET 0x00 @@ -120,6 +120,7 @@ #define IXP4XX_SSP_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x12000) +/* The UART is explicitly put in the beginning of fixmap */ #define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000) #define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000) #define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000) @@ -299,58 +300,4 @@ #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ -/* "fuse" bits of IXP_EXP_CFG2 */ -/* All IXP4xx CPUs */ -#define IXP4XX_FEATURE_RCOMP (1 << 0) -#define IXP4XX_FEATURE_USB_DEVICE (1 << 1) -#define IXP4XX_FEATURE_HASH (1 << 2) -#define IXP4XX_FEATURE_AES (1 << 3) -#define IXP4XX_FEATURE_DES (1 << 4) -#define IXP4XX_FEATURE_HDLC (1 << 5) -#define IXP4XX_FEATURE_AAL (1 << 6) -#define IXP4XX_FEATURE_HSS (1 << 7) -#define IXP4XX_FEATURE_UTOPIA (1 << 8) -#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9) -#define IXP4XX_FEATURE_NPEC_ETH (1 << 10) -#define IXP4XX_FEATURE_RESET_NPEA (1 << 11) -#define IXP4XX_FEATURE_RESET_NPEB (1 << 12) -#define IXP4XX_FEATURE_RESET_NPEC (1 << 13) -#define IXP4XX_FEATURE_PCI (1 << 14) -#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16) -#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) -#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \ - IXP4XX_FEATURE_USB_DEVICE | \ - IXP4XX_FEATURE_HASH | \ - IXP4XX_FEATURE_AES | \ - IXP4XX_FEATURE_DES | \ - IXP4XX_FEATURE_HDLC | \ - IXP4XX_FEATURE_AAL | \ - IXP4XX_FEATURE_HSS | \ - IXP4XX_FEATURE_UTOPIA | \ - IXP4XX_FEATURE_NPEB_ETH0 | \ - IXP4XX_FEATURE_NPEC_ETH | \ - IXP4XX_FEATURE_RESET_NPEA | \ - IXP4XX_FEATURE_RESET_NPEB | \ - IXP4XX_FEATURE_RESET_NPEC | \ - IXP4XX_FEATURE_PCI | \ - IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \ - IXP4XX_FEATURE_XSCALE_MAX_FREQ) - - -/* IXP43x/46x CPUs */ -#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15) -#define IXP4XX_FEATURE_USB_HOST (1 << 18) -#define IXP4XX_FEATURE_NPEA_ETH (1 << 19) -#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \ - IXP4XX_FEATURE_ECC_TIMESYNC | \ - IXP4XX_FEATURE_USB_HOST | \ - IXP4XX_FEATURE_NPEA_ETH) - -/* IXP46x CPU (including IXP455) only */ -#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20) -#define IXP4XX_FEATURE_RSA (1 << 21) -#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \ - IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ - IXP4XX_FEATURE_RSA) - #endif diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h index 6d403fe0bf52..d8b4df96db08 100644 --- a/arch/arm/mach-ixp4xx/include/mach/platform.h +++ b/arch/arm/mach-ixp4xx/include/mach/platform.h @@ -79,20 +79,6 @@ extern unsigned long ixp4xx_exp_bus_size; #define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66MHzi APB BUS */ #define IXP4XX_UART_XTAL 14745600 -/* - * This structure provide a means for the board setup code - * to give information to th pata_ixp4xx driver. It is - * passed as platform_data. - */ -struct ixp4xx_pata_data { - volatile u32 *cs0_cfg; - volatile u32 *cs1_cfg; - unsigned long cs0_bits; - unsigned long cs1_bits; - void __iomem *cs0; - void __iomem *cs1; -}; - /* * Frequency of clock used for primary clocksource */ diff --git a/arch/arm/mach-ixp4xx/ixp4xx-of.c b/arch/arm/mach-ixp4xx/ixp4xx-of.c index 7449b8319c8a..f9904716ec7f 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx-of.c +++ b/arch/arm/mach-ixp4xx/ixp4xx-of.c @@ -9,8 +9,12 @@ #include #include -#include -#include +/* + * These are the only fixed phys to virt mappings we ever need + * we put it right after the UART mapping at 0xffc80000-0xffc81fff + */ +#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000 +#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000 static struct map_desc ixp4xx_of_io_desc[] __initdata = { /* diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 6959ad2e3aec..6133cf01cbe4 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "irqs.h" diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index a428bb918703..8526a70e401b 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "irqs.h" diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 9536b8f3c07d..208c700c2455 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -65,14 +65,14 @@ config MACH_OMAP_INNOVATOR config MACH_OMAP_H2 bool "TI H2 Support" depends on ARCH_OMAP16XX - help + help TI OMAP 1610/1611B H2 board support. Say Y here if you have such a board. config MACH_OMAP_H3 bool "TI H3 Support" depends on ARCH_OMAP16XX - help + help TI OMAP 1710 H3 board support. Say Y here if you have such a board. @@ -85,14 +85,14 @@ config MACH_HERALD config MACH_OMAP_OSK bool "TI OSK Support" depends on ARCH_OMAP16XX - help + help TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here if you have such a board. config OMAP_OSK_MISTRAL bool "Mistral QVGA board Support" depends on MACH_OMAP_OSK - help + help The OSK supports an optional add-on board with a Quarter-VGA touchscreen, PDA-ish buttons, a resume button, bicolor LED, and camera connector. Say Y here if you have this board. @@ -100,14 +100,14 @@ config OMAP_OSK_MISTRAL config MACH_OMAP_PERSEUS2 bool "TI Perseus2" depends on ARCH_OMAP730 - help + help Support for TI OMAP 730 Perseus2 board. Say Y here if you have such a board. config MACH_OMAP_FSAMPLE bool "TI F-Sample" depends on ARCH_OMAP730 - help + help Support for TI OMAP 850 F-Sample board. Say Y here if you have such a board. diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index d02fe63dab59..14beb59e5f7b 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -26,7 +26,6 @@ extern struct omap_domain_base cm_base; extern struct omap_domain_base cm2_base; -extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); # endif /* diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index b7ea609386d5..e2d069fe67f1 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -37,19 +37,6 @@ struct omap_domain_base cm2_base; #define CM_NO_CLOCKS 0x1 #define CM_SINGLE_INSTANCE 0x2 -/** - * omap2_set_globals_cm - set the CM/CM2 base addresses (for early use) - * @cm: CM base virtual address - * @cm2: CM2 base virtual address (if present on the booted SoC) - * - * XXX Will be replaced when the PRM/CM drivers are completed. - */ -void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2) -{ - cm_base.va = cm; - cm2_base.va = cm2; -} - /** * cm_split_idlest_reg - split CM_IDLEST reg addr into its components * @idlest_reg: CM_IDLEST* virtual address diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index db446f271f5d..32f58f58515e 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -130,7 +130,6 @@ void am33xx_init_early(void); void am35xx_init_early(void); void ti814x_init_early(void); void ti816x_init_early(void); -void am33xx_init_early(void); void am43xx_init_early(void); void am43xx_init_late(void); void omap4430_init_early(void); diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 73338cf80d76..062d431fc33a 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -136,11 +136,6 @@ struct omap3_control_regs { static struct omap3_control_regs control_context; #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ -void __init omap2_set_globals_control(void __iomem *ctrl) -{ - omap2_ctrl_base = ctrl; -} - u8 omap_ctrl_readb(u16 offset) { u32 val; diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index eceb4b09adb2..c4ca30ba1790 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -528,7 +528,6 @@ extern int omap3_ctrl_save_padconf(void); void omap3_ctrl_init(void); int omap2_control_base_init(void); int omap_control_init(void); -void omap2_set_globals_control(void __iomem *ctrl); void __init omap3_control_legacy_iomap_init(void); #else #define omap_ctrl_readb(x) 0 diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c index 56f2c0bcae5a..bf0d25fd2cea 100644 --- a/arch/arm/mach-omap2/pm33xx-core.c +++ b/arch/arm/mach-omap2/pm33xx-core.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -324,6 +325,44 @@ static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) return NULL; } +#ifdef CONFIG_SUSPEND +/* + * Block system suspend initially. Later on pm33xx sets up it's own + * platform_suspend_ops after probe. That depends also on loaded + * wkup_m3_ipc and booted am335x-pm-firmware.elf. + */ +static int amx3_suspend_block(suspend_state_t state) +{ + pr_warn("PM not initialized for pm33xx, wkup_m3_ipc, or am335x-pm-firmware.elf\n"); + + return -EINVAL; +} + +static int amx3_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + return 1; + default: + return 0; + } +} + +static const struct platform_suspend_ops amx3_blocked_pm_ops = { + .begin = amx3_suspend_block, + .valid = amx3_pm_valid, +}; + +static void __init amx3_block_suspend(void) +{ + suspend_set_ops(&amx3_blocked_pm_ops); +} +#else +static inline void amx3_block_suspend(void) +{ +} +#endif /* CONFIG_SUSPEND */ + int __init amx3_common_pm_init(void) { struct am33xx_pm_platform_data *pdata; @@ -337,6 +376,7 @@ int __init amx3_common_pm_init(void) devinfo.size_data = sizeof(*pdata); devinfo.id = -1; platform_device_register_full(&devinfo); + amx3_block_suspend(); return 0; } diff --git a/arch/arm/mach-s3c/mach-rx1950.c b/arch/arm/mach-s3c/mach-rx1950.c index a3f46aa61c45..313e080e179e 100644 --- a/arch/arm/mach-s3c/mach-rx1950.c +++ b/arch/arm/mach-s3c/mach-rx1950.c @@ -271,7 +271,6 @@ static int rx1950_led_blink_set(struct gpio_desc *desc, int state, break; default: return -EINVAL; - break; } if (delay_on && delay_off && !*delay_on && !*delay_off) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 35f43d0aa056..8355c3895894 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -601,8 +601,6 @@ config CPU_TLB_V6 config CPU_TLB_V7 bool -config VERIFY_PERMISSION_FAULT - bool endif config CPU_HAS_ASID diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index f7cc5d68444b..f81bceacc660 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -17,31 +17,5 @@ ENTRY(v7_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR uaccess_disable ip @ disable userspace access - - /* - * V6 code adjusts the returned DFSR. - * New designs should not need to patch up faults. - */ - -#if defined(CONFIG_VERIFY_PERMISSION_FAULT) - /* - * Detect erroneous permission failures and fix - */ - ldr r3, =0x40d @ On permission fault - and r3, r1, r3 - cmp r3, #0x0d - bne do_DataAbort - - mcr p15, 0, r0, c7, c8, 0 @ Retranslate FAR - isb - mrc p15, 0, ip, c7, c4, 0 @ Read the PAR - and r3, ip, #0x7b @ On translation fault - cmp r3, #0x0b - bne do_DataAbort - bic r1, r1, #0xf @ Fix up FSR FS[5:0] - and ip, ip, #0x7e - orr r1, r1, ip, LSR #1 -#endif - b do_DataAbort ENDPROC(v7_early_abort) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 000e8210000b..80fb5a4a5c05 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -284,7 +285,8 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, * Don't allow RAM to be mapped with mismatched attributes - this * causes problems with ARMv6+ */ - if (WARN_ON(pfn_valid(pfn) && mtype != MT_MEMORY_RW)) + if (WARN_ON(memblock_is_map_memory(PFN_PHYS(pfn)) && + mtype != MT_MEMORY_RW)) return NULL; area = get_vm_area_caller(size, VM_IOREMAP, caller); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index c1e12aab67b8..7583bda5ea7d 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1121,31 +1121,32 @@ void __init debug_ll_io_init(void) } #endif -static void * __initdata vmalloc_min = - (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET); +static unsigned long __initdata vmalloc_size = 240 * SZ_1M; /* * vmalloc=size forces the vmalloc area to be exactly 'size' * bytes. This can be used to increase (or decrease) the vmalloc - * area - the default is 240m. + * area - the default is 240MiB. */ static int __init early_vmalloc(char *arg) { unsigned long vmalloc_reserve = memparse(arg, NULL); + unsigned long vmalloc_max; if (vmalloc_reserve < SZ_16M) { vmalloc_reserve = SZ_16M; - pr_warn("vmalloc area too small, limiting to %luMB\n", + pr_warn("vmalloc area is too small, limiting to %luMiB\n", vmalloc_reserve >> 20); } - if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) { - vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M); - pr_warn("vmalloc area is too big, limiting to %luMB\n", + vmalloc_max = VMALLOC_END - (PAGE_OFFSET + SZ_32M + VMALLOC_OFFSET); + if (vmalloc_reserve > vmalloc_max) { + vmalloc_reserve = vmalloc_max; + pr_warn("vmalloc area is too big, limiting to %luMiB\n", vmalloc_reserve >> 20); } - vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve); + vmalloc_size = vmalloc_reserve; return 0; } early_param("vmalloc", early_vmalloc); @@ -1165,7 +1166,8 @@ void __init adjust_lowmem_bounds(void) * and may itself be outside the valid range for which phys_addr_t * and therefore __pa() is defined. */ - vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET; + vmalloc_limit = (u64)VMALLOC_END - vmalloc_size - VMALLOC_OFFSET - + PAGE_OFFSET + PHYS_OFFSET; /* * The first usable region must be PMD aligned. Mark its start @@ -1246,7 +1248,7 @@ void __init adjust_lowmem_bounds(void) memblock_set_current_limit(memblock_limit); } -static inline void prepare_page_table(void) +static __init void prepare_page_table(void) { unsigned long addr; phys_addr_t end; @@ -1457,8 +1459,6 @@ static void __init kmap_init(void) static void __init map_lowmem(void) { - phys_addr_t kernel_x_start = round_down(__pa(KERNEL_START), SECTION_SIZE); - phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); phys_addr_t start, end; u64 i; @@ -1466,55 +1466,126 @@ static void __init map_lowmem(void) for_each_mem_range(i, &start, &end) { struct map_desc map; + pr_debug("map lowmem start: 0x%08llx, end: 0x%08llx\n", + (long long)start, (long long)end); if (end > arm_lowmem_limit) end = arm_lowmem_limit; if (start >= end) break; - if (end < kernel_x_start) { - map.pfn = __phys_to_pfn(start); - map.virtual = __phys_to_virt(start); - map.length = end - start; - map.type = MT_MEMORY_RWX; + /* + * If our kernel image is in the VMALLOC area we need to remove + * the kernel physical memory from lowmem since the kernel will + * be mapped separately. + * + * The kernel will typically be at the very start of lowmem, + * but any placement relative to memory ranges is possible. + * + * If the memblock contains the kernel, we have to chisel out + * the kernel memory from it and map each part separately. We + * get 6 different theoretical cases: + * + * +--------+ +--------+ + * +-- start --+ +--------+ | Kernel | | Kernel | + * | | | Kernel | | case 2 | | case 5 | + * | | | case 1 | +--------+ | | +--------+ + * | Memory | +--------+ | | | Kernel | + * | range | +--------+ | | | case 6 | + * | | | Kernel | +--------+ | | +--------+ + * | | | case 3 | | Kernel | | | + * +-- end ----+ +--------+ | case 4 | | | + * +--------+ +--------+ + */ - create_mapping(&map); - } else if (start >= kernel_x_end) { - map.pfn = __phys_to_pfn(start); - map.virtual = __phys_to_virt(start); - map.length = end - start; - map.type = MT_MEMORY_RW; + /* Case 5: kernel covers range, don't map anything, should be rare */ + if ((start > kernel_sec_start) && (end < kernel_sec_end)) + break; - create_mapping(&map); - } else { - /* This better cover the entire kernel */ - if (start < kernel_x_start) { + /* Cases where the kernel is starting inside the range */ + if ((kernel_sec_start >= start) && (kernel_sec_start <= end)) { + /* Case 6: kernel is embedded in the range, we need two mappings */ + if ((start < kernel_sec_start) && (end > kernel_sec_end)) { + /* Map memory below the kernel */ map.pfn = __phys_to_pfn(start); map.virtual = __phys_to_virt(start); - map.length = kernel_x_start - start; + map.length = kernel_sec_start - start; map.type = MT_MEMORY_RW; - create_mapping(&map); - } - - map.pfn = __phys_to_pfn(kernel_x_start); - map.virtual = __phys_to_virt(kernel_x_start); - map.length = kernel_x_end - kernel_x_start; - map.type = MT_MEMORY_RWX; - - create_mapping(&map); - - if (kernel_x_end < end) { - map.pfn = __phys_to_pfn(kernel_x_end); - map.virtual = __phys_to_virt(kernel_x_end); - map.length = end - kernel_x_end; + /* Map memory above the kernel */ + map.pfn = __phys_to_pfn(kernel_sec_end); + map.virtual = __phys_to_virt(kernel_sec_end); + map.length = end - kernel_sec_end; map.type = MT_MEMORY_RW; - create_mapping(&map); + break; } + /* Case 1: kernel and range start at the same address, should be common */ + if (kernel_sec_start == start) + start = kernel_sec_end; + /* Case 3: kernel and range end at the same address, should be rare */ + if (kernel_sec_end == end) + end = kernel_sec_start; + } else if ((kernel_sec_start < start) && (kernel_sec_end > start) && (kernel_sec_end < end)) { + /* Case 2: kernel ends inside range, starts below it */ + start = kernel_sec_end; + } else if ((kernel_sec_start > start) && (kernel_sec_start < end) && (kernel_sec_end > end)) { + /* Case 4: kernel starts inside range, ends above it */ + end = kernel_sec_start; } + map.pfn = __phys_to_pfn(start); + map.virtual = __phys_to_virt(start); + map.length = end - start; + map.type = MT_MEMORY_RW; + create_mapping(&map); } } +static void __init map_kernel(void) +{ + /* + * We use the well known kernel section start and end and split the area in the + * middle like this: + * . . + * | RW memory | + * +----------------+ kernel_x_start + * | Executable | + * | kernel memory | + * +----------------+ kernel_x_end / kernel_nx_start + * | Non-executable | + * | kernel memory | + * +----------------+ kernel_nx_end + * | RW memory | + * . . + * + * Notice that we are dealing with section sized mappings here so all of this + * will be bumped to the closest section boundary. This means that some of the + * non-executable part of the kernel memory is actually mapped as executable. + * This will only persist until we turn on proper memory management later on + * and we remap the whole kernel with page granularity. + */ + phys_addr_t kernel_x_start = kernel_sec_start; + phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); + phys_addr_t kernel_nx_start = kernel_x_end; + phys_addr_t kernel_nx_end = kernel_sec_end; + struct map_desc map; + + map.pfn = __phys_to_pfn(kernel_x_start); + map.virtual = __phys_to_virt(kernel_x_start); + map.length = kernel_x_end - kernel_x_start; + map.type = MT_MEMORY_RWX; + create_mapping(&map); + + /* If the nx part is small it may end up covered by the tail of the RWX section */ + if (kernel_x_end == kernel_nx_end) + return; + + map.pfn = __phys_to_pfn(kernel_nx_start); + map.virtual = __phys_to_virt(kernel_nx_start); + map.length = kernel_nx_end - kernel_nx_start; + map.type = MT_MEMORY_RW; + create_mapping(&map); +} + #ifdef CONFIG_ARM_PV_FIXUP typedef void pgtables_remap(long long offset, unsigned long pgd); pgtables_remap lpae_pgtables_remap_asm; @@ -1645,9 +1716,18 @@ void __init paging_init(const struct machine_desc *mdesc) { void *zero_page; + pr_debug("physical kernel sections: 0x%08x-0x%08x\n", + kernel_sec_start, kernel_sec_end); + prepare_page_table(); map_lowmem(); memblock_set_current_limit(arm_lowmem_limit); + pr_debug("lowmem limit is %08llx\n", (long long)arm_lowmem_limit); + /* + * After this point early_alloc(), i.e. the memblock allocator, can + * be used + */ + map_kernel(); dma_contiguous_remap(); early_fixmap_shutdown(); devicemaps_init(mdesc); diff --git a/arch/arm/probes/kprobes/test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c index 456c181a7bfe..4e11f0b760f8 100644 --- a/arch/arm/probes/kprobes/test-thumb.c +++ b/arch/arm/probes/kprobes/test-thumb.c @@ -441,21 +441,21 @@ void kprobe_thumb32_test_cases(void) "3: mvn r0, r0 \n\t" "2: nop \n\t") - TEST_RX("tbh [pc, r",7, (9f-(1f+4))>>1,"]", + TEST_RX("tbh [pc, r",7, (9f-(1f+4))>>1,", lsl #1]", "9: \n\t" ".short (2f-1b-4)>>1 \n\t" ".short (3f-1b-4)>>1 \n\t" "3: mvn r0, r0 \n\t" "2: nop \n\t") - TEST_RX("tbh [pc, r",12, ((9f-(1f+4))>>1)+1,"]", + TEST_RX("tbh [pc, r",12, ((9f-(1f+4))>>1)+1,", lsl #1]", "9: \n\t" ".short (2f-1b-4)>>1 \n\t" ".short (3f-1b-4)>>1 \n\t" "3: mvn r0, r0 \n\t" "2: nop \n\t") - TEST_RRX("tbh [r",1,9f, ", r",14,1,"]", + TEST_RRX("tbh [r",1,9f, ", r",14,1,", lsl #1]", "9: \n\t" ".short (2f-1b-4)>>1 \n\t" ".short (3f-1b-4)>>1 \n\t" @@ -468,10 +468,10 @@ void kprobe_thumb32_test_cases(void) TEST_UNSUPPORTED("strexb r0, r1, [r2]") TEST_UNSUPPORTED("strexh r0, r1, [r2]") - TEST_UNSUPPORTED("strexd r0, r1, [r2]") + TEST_UNSUPPORTED("strexd r0, r1, r2, [r2]") TEST_UNSUPPORTED("ldrexb r0, [r1]") TEST_UNSUPPORTED("ldrexh r0, [r1]") - TEST_UNSUPPORTED("ldrexd r0, [r1]") + TEST_UNSUPPORTED("ldrexd r0, r1, [r1]") TEST_GROUP("Data-processing (shifted register) and (modified immediate)") diff --git a/arch/arm/tools/Makefile b/arch/arm/tools/Makefile index 87de1f63f649..4a5c50f67ced 100644 --- a/arch/arm/tools/Makefile +++ b/arch/arm/tools/Makefile @@ -33,39 +33,26 @@ _dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)') \ $(shell [ -d '$(uapi)' ] || mkdir -p '$(uapi)') quiet_cmd_gen_mach = GEN $@ - cmd_gen_mach = mkdir -p $(dir $@) && \ - $(AWK) -f $(filter-out $(PHONY),$^) > $@ + cmd_gen_mach = $(AWK) -f $(real-prereqs) > $@ $(kapi)/mach-types.h: $(src)/gen-mach-types $(src)/mach-types FORCE $(call if_changed,gen_mach) quiet_cmd_syshdr = SYSHDR $@ - cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --abis $(abis) \ + cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --abis common,$* \ --offset __NR_SYSCALL_BASE $< $@ quiet_cmd_systbl = SYSTBL $@ - cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis $(abis) $< $@ + cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis common,$* $< $@ quiet_cmd_sysnr = SYSNR $@ - cmd_sysnr = $(CONFIG_SHELL) '$(sysnr)' '$<' '$@' \ - '$(syshdr_abi_$(basetarget))' + cmd_sysnr = $(CONFIG_SHELL) $(sysnr) $< $@ -$(uapi)/unistd-oabi.h: abis := common,oabi -$(uapi)/unistd-oabi.h: $(syscall) $(syshdr) FORCE +$(uapi)/unistd-%.h: $(syscall) $(syshdr) FORCE $(call if_changed,syshdr) -$(uapi)/unistd-eabi.h: abis := common,eabi -$(uapi)/unistd-eabi.h: $(syscall) $(syshdr) FORCE - $(call if_changed,syshdr) - -sysnr_abi_unistd-nr := common,oabi,eabi,compat $(kapi)/unistd-nr.h: $(syscall) $(sysnr) FORCE $(call if_changed,sysnr) -$(gen)/calls-oabi.S: abis := common,oabi -$(gen)/calls-oabi.S: $(syscall) $(systbl) FORCE - $(call if_changed,systbl) - -$(gen)/calls-eabi.S: abis := common,eabi -$(gen)/calls-eabi.S: $(syscall) $(systbl) FORCE +$(gen)/calls-%.S: $(syscall) $(systbl) FORCE $(call if_changed,systbl) diff --git a/arch/arm/tools/syscallnr.sh b/arch/arm/tools/syscallnr.sh index df3ccd0ca831..9e386770b6b3 100644 --- a/arch/arm/tools/syscallnr.sh +++ b/arch/arm/tools/syscallnr.sh @@ -2,14 +2,13 @@ # SPDX-License-Identifier: GPL-2.0 in="$1" out="$2" -my_abis=`echo "($3)" | tr ',' '|'` align=1 fileguard=_ASM_ARM_`basename "$out" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` -grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | tail -n1 | ( +grep -E "^[0-9A-Fa-fXx]+[[:space:]]+" "$in" | sort -n | tail -n1 | ( echo "#ifndef ${fileguard} #define ${fileguard} 1 diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index aa3e020f5bbd..ff2d83fbbde1 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -16,6 +16,7 @@ config ARCH_SUNXI select IRQ_FASTEOI_HIERARCHY_HANDLERS select PINCTRL select RESET_CONTROLLER + select SUN4I_TIMER help This enables support for Allwinner sunxi based SoCs like the A64. diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index a63ffe84dbcb..4efce1748695 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -149,7 +149,6 @@ KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) -core-y += arch/arm64/ libs-y := arch/arm64/lib/ $(libs-y) libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile index 41ce680e5f8d..a96d9d2d8dd8 100644 --- a/arch/arm64/boot/dts/allwinner/Makefile +++ b/arch/arm64/boot/dts/allwinner/Makefile @@ -25,6 +25,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-libretech-all-h3-it.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-libretech-all-h5-cc.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo2.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo-plus2.dtb +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-r1s-h5.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-pc2.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-prime.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus.dtb diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi index 79adea3f8cc1..5b44a979f250 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi @@ -25,6 +25,11 @@ /* Backlight configuration differs per PinePhone revision. */ }; + bt_sco_codec: bt-sco-codec { + #sound-dai-cells = <1>; + compatible = "linux,bt-sco"; + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -91,6 +96,8 @@ }; &codec { + pinctrl-names = "default"; + pinctrl-0 = <&aif3_pins>; status = "okay"; }; @@ -426,6 +433,7 @@ &sound { status = "okay"; + simple-audio-card,name = "PinePhone"; simple-audio-card,aux-devs = <&codec_analog>, <&speaker_amp>; simple-audio-card,widgets = "Microphone", "Headset Microphone", "Microphone", "Internal Microphone", @@ -447,6 +455,23 @@ "MIC1", "Internal Microphone", "Headset Microphone", "HBIAS", "MIC2", "Headset Microphone"; + + simple-audio-card,dai-link@2 { + format = "dsp_a"; + frame-master = <&link2_codec>; + bitclock-master = <&link2_codec>; + bitclock-inversion; + + link2_cpu: cpu { + sound-dai = <&bt_sco_codec 0>; + }; + + link2_codec: codec { + sound-dai = <&codec 2>; + dai-tdm-slot-num = <1>; + dai-tdm-slot-width = <32>; + }; + }; }; &uart0 { diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index e22b94c83647..5e66ce1a334f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -79,7 +79,7 @@ &emac { pinctrl-names = "default"; pinctrl-0 = <&rgmii_pins>; - phy-mode = "rgmii-id"; + phy-mode = "rgmii-txid"; phy-handle = <&ext_rgmii_phy>; phy-supply = <®_dc1sw>; status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 5b30e6c1fa05..6ddb717f2f98 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -131,12 +131,10 @@ }; sound: sound { + #address-cells = <1>; + #size-cells = <0>; compatible = "simple-audio-card"; simple-audio-card,name = "sun50i-a64-audio"; - simple-audio-card,format = "i2s"; - simple-audio-card,frame-master = <&cpudai>; - simple-audio-card,bitclock-master = <&cpudai>; - simple-audio-card,mclk-fs = <128>; simple-audio-card,aux-devs = <&codec_analog>; simple-audio-card,routing = "Left DAC", "DACL", @@ -145,12 +143,19 @@ "ADCR", "Right ADC"; status = "disabled"; - cpudai: simple-audio-card,cpu { - sound-dai = <&dai>; - }; + simple-audio-card,dai-link@0 { + format = "i2s"; + frame-master = <&link0_cpu>; + bitclock-master = <&link0_cpu>; + mclk-fs = <128>; - link_codec: simple-audio-card,codec { - sound-dai = <&codec>; + link0_cpu: cpu { + sound-dai = <&dai>; + }; + + link0_codec: codec { + sound-dai = <&codec 0>; + }; }; }; @@ -659,6 +664,18 @@ interrupt-controller; #interrupt-cells = <3>; + /omit-if-no-ref/ + aif2_pins: aif2-pins { + pins = "PB4", "PB5", "PB6", "PB7"; + function = "aif2"; + }; + + /omit-if-no-ref/ + aif3_pins: aif3-pins { + pins = "PG10", "PG11", "PG12", "PG13"; + function = "aif3"; + }; + csi_pins: csi-pins { pins = "PE0", "PE2", "PE3", "PE4", "PE5", "PE6", "PE7", "PE8", "PE9", "PE10", "PE11"; @@ -799,6 +816,23 @@ }; }; + timer@1c20c00 { + compatible = "allwinner,sun50i-a64-timer", + "allwinner,sun8i-a23-timer"; + reg = <0x01c20c00 0xa0>; + interrupts = , + ; + clocks = <&osc24M>; + }; + + wdt0: watchdog@1c20ca0 { + compatible = "allwinner,sun50i-a64-wdt", + "allwinner,sun6i-a31-wdt"; + reg = <0x01c20ca0 0x20>; + interrupts = ; + clocks = <&osc24M>; + }; + spdif: spdif@1c21000 { #sound-dai-cells = <0>; compatible = "allwinner,sun50i-a64-spdif", @@ -880,7 +914,7 @@ }; codec: codec@1c22e00 { - #sound-dai-cells = <0>; + #sound-dai-cells = <1>; compatible = "allwinner,sun50i-a64-codec", "allwinner,sun8i-a33-codec"; reg = <0x01c22e00 0x600>; @@ -1325,13 +1359,5 @@ #address-cells = <1>; #size-cells = <0>; }; - - wdt0: watchdog@1c20ca0 { - compatible = "allwinner,sun50i-a64-wdt", - "allwinner,sun6i-a31-wdt"; - reg = <0x01c20ca0 0x20>; - interrupts = ; - clocks = <&osc24M>; - }; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts new file mode 100644 index 000000000000..55bcdf8d1a07 --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2021 Chukun Pan + * + * Based on sun50i-h5-nanopi-neo-plus2.dts, which is: + * Copyright (C) 2017 Antony Antony + * Copyright (C) 2016 ARM Ltd. + */ + +/dts-v1/; +#include "sun50i-h5.dtsi" +#include "sun50i-h5-cpu-opp.dtsi" + +#include +#include +#include + +/ { + model = "FriendlyARM NanoPi R1S H5"; + compatible = "friendlyarm,nanopi-r1s-h5", "allwinner,sun50i-h5"; + + aliases { + ethernet0 = &emac; + ethernet1 = &rtl8189etv; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + function = LED_FUNCTION_LAN; + color = ; + gpios = <&pio 0 9 GPIO_ACTIVE_HIGH>; + }; + + led-1 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led-2 { + function = LED_FUNCTION_WAN; + color = ; + gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; + }; + }; + + r-gpio-keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + linux,code = ; + gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; + }; + }; + + reg_gmac_3v3: gmac-3v3 { + compatible = "regulator-fixed"; + regulator-name = "gmac-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + enable-active-high; + gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; + }; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_usb0_vbus: usb0-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb0-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */ + status = "okay"; + }; + + vdd_cpux: gpio-regulator { + compatible = "regulator-gpio"; + regulator-name = "vdd-cpux"; + regulator-type = "voltage"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-ramp-delay = <50>; /* 4ms */ + gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; + gpios-states = <0x1>; + states = <1100000 0x0>, <1300000 0x1>; + }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ + post-power-on-delay-ms = <200>; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_cpux>; +}; + +&ehci1 { + status = "okay"; +}; + +&ehci2 { + status = "okay"; +}; + +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&emac_rgmii_pins>; + phy-supply = <®_gmac_3v3>; + phy-handle = <&ext_rgmii_phy>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@7 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <7>; + }; +}; + +&i2c0 { + status = "okay"; + + eeprom@51 { + compatible = "microchip,24c02"; + reg = <0x51>; + pagesize = <16>; + }; +}; + +&mmc0 { + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + status = "okay"; +}; + +&mmc1 { + vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + status = "okay"; + + rtl8189etv: sdio_wifi@1 { + reg = <1>; + }; +}; + +&ohci1 { + status = "okay"; +}; + +&ohci2 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pa_pins>; + status = "okay"; +}; + +&usb_otg { + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + /* USB Type-A port's VBUS is always on */ + usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ + usb0_vbus-supply = <®_usb0_vbus>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi index 50815867ce7b..30d396e8c762 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -271,6 +271,15 @@ }; }; + timer@3009000 { + compatible = "allwinner,sun50i-h6-timer", + "allwinner,sun8i-a23-timer"; + reg = <0x03009000 0xa0>; + interrupts = , + ; + clocks = <&osc24M>; + }; + watchdog: watchdog@30090a0 { compatible = "allwinner,sun50i-h6-wdt", "allwinner,sun6i-a31-wdt"; diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 43b9eed921fa..0f4b503a99d8 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -50,6 +50,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-libretech-pc.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-vega-s96.dtb dtb-$(CONFIG_ARCH_MESON) += meson-gxm-wetek-core2.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-sm1-bananapi-m5.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l-android.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-odroid-c4.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi index 895c43c7af9f..3f5254eeb47b 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi @@ -1871,6 +1871,7 @@ status = "disabled"; clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; clock-names = "xtal", "pclk", "baud"; + fifo-size = <128>; }; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi index 793d48f72390..00c6f53290d4 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -2317,6 +2317,7 @@ clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; clock-names = "xtal", "pclk", "baud"; status = "disabled"; + fifo-size = <128>; }; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi index 3d00404aae0f..6b457b2c30a4 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -301,6 +301,7 @@ reg = <0x0 0x84c0 0x0 0x18>; interrupts = ; status = "disabled"; + fifo-size = <128>; }; uart_B: serial@84dc { diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi index 66d67524b031..3cf4ecb6d52e 100644 --- a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi @@ -171,11 +171,16 @@ sound { compatible = "amlogic,axg-sound-card"; model = "KHADAS-VIM3"; - audio-aux-devs = <&tdmout_a>; + audio-aux-devs = <&tdmin_a>, <&tdmout_a>; audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", "TDMOUT_A IN 1", "FRDDR_B OUT 0", "TDMOUT_A IN 2", "FRDDR_C OUT 0", - "TDM_A Playback", "TDMOUT_A OUT"; + "TDM_A Playback", "TDMOUT_A OUT", + "TDMIN_A IN 0", "TDM_A Capture", + "TDMIN_A IN 3", "TDM_A Loopback", + "TODDR_A IN 0", "TDMIN_A OUT", + "TODDR_B IN 0", "TDMIN_A OUT", + "TODDR_C IN 0", "TDMIN_A OUT"; assigned-clocks = <&clkc CLKID_MPLL2>, <&clkc CLKID_MPLL0>, @@ -198,8 +203,20 @@ sound-dai = <&frddr_c>; }; - /* 8ch hdmi interface */ dai-link-3 { + sound-dai = <&toddr_a>; + }; + + dai-link-4 { + sound-dai = <&toddr_b>; + }; + + dai-link-5 { + sound-dai = <&toddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-6 { sound-dai = <&tdmif_a>; dai-format = "i2s"; dai-tdm-slot-tx-mask-0 = <1 1>; @@ -214,7 +231,7 @@ }; /* hdmi glue */ - dai-link-4 { + dai-link-7 { sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; codec { @@ -454,10 +471,26 @@ status = "okay"; }; +&tdmin_a { + status = "okay"; +}; + &tdmout_a { status = "okay"; }; +&toddr_a { + status = "okay"; +}; + +&toddr_b { + status = "okay"; +}; + +&toddr_c { + status = "okay"; +}; + &tohdmitx { status = "okay"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts new file mode 100644 index 000000000000..effaa138b5f9 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 BayLibre SAS + * Author: Neil Armstrong + */ + +/dts-v1/; + +#include "meson-sm1.dtsi" +#include +#include +#include +#include +#include + +/ { + compatible = "bananapi,bpi-m5", "amlogic,sm1"; + model = "Banana Pi BPI-M5"; + + adc_keys { + compatible = "adc-keys"; + io-channels = <&saradc 2>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + + key { + label = "SW3"; + linux,code = ; + press-threshold-microvolt = <1700000>; + }; + }; + + aliases { + serial0 = &uart_AO; + ethernet0 = ðmac; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + /* TOFIX: handle CVBS_DET on SARADC channel 0 */ + cvbs-connector { + compatible = "composite-video-connector"; + + port { + cvbs_connector_in: endpoint { + remote-endpoint = <&cvbs_vdac_out>; + }; + }; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + key { + label = "SW1"; + linux,code = ; + gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>; + interrupt-parent = <&gpio_intc>; + interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + }; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + green { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; + }; + + blue { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; + + emmc_1v8: regulator-emmc_1v8 { + compatible = "regulator-fixed"; + regulator-name = "EMMC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; + + dc_in: regulator-dc_in { + compatible = "regulator-fixed"; + regulator-name = "DC_IN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + vddio_c: regulator-vddio_c { + compatible = "regulator-gpio"; + regulator-name = "VDDIO_C"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + + gpios = <&gpio_ao GPIOAO_6 GPIO_OPEN_DRAIN>; + gpios-states = <1>; + + states = <1800000 0>, + <3300000 1>; + }; + + tflash_vdd: regulator-tflash_vdd { + compatible = "regulator-fixed"; + regulator-name = "TFLASH_VDD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; + regulator-always-on; + }; + + vddao_1v8: regulator-vddao_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; + + vddao_3v3: regulator-vddao_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + vddcpu: regulator-vddcpu { + /* + * SY8120B1ABC DC/DC Regulator. + */ + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU"; + regulator-min-microvolt = <690000>; + regulator-max-microvolt = <1050000>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + /* USB Hub Power Enable */ + vl_pwr_en: regulator-vl_pwr_en { + compatible = "regulator-fixed"; + regulator-name = "VL_PWR_EN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_in>; + + gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "BPI-M5"; + audio-widgets = "Line", "Lineout"; + audio-aux-devs = <&tdmout_b>, <&tdmout_c>, + <&tdmin_a>, <&tdmin_b>, <&tdmin_c>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT", + "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "TDMOUT_C IN 1", "FRDDR_B OUT 2", + "TDMOUT_C IN 2", "FRDDR_C OUT 2", + "TDM_C Playback", "TDMOUT_C OUT", + "TDMIN_A IN 4", "TDM_B Loopback", + "TDMIN_B IN 4", "TDM_B Loopback", + "TDMIN_C IN 4", "TDM_B Loopback", + "TDMIN_A IN 5", "TDM_C Loopback", + "TDMIN_B IN 5", "TDM_C Loopback", + "TDMIN_C IN 5", "TDM_C Loopback", + "TODDR_A IN 0", "TDMIN_A OUT", + "TODDR_B IN 0", "TDMIN_A OUT", + "TODDR_C IN 0", "TDMIN_A OUT", + "TODDR_A IN 1", "TDMIN_B OUT", + "TODDR_B IN 1", "TDMIN_B OUT", + "TODDR_C IN 1", "TDMIN_B OUT", + "TODDR_A IN 2", "TDMIN_C OUT", + "TODDR_B IN 2", "TDMIN_C OUT", + "TODDR_C IN 2", "TDMIN_C OUT", + "Lineout", "ACODEC LOLP", + "Lineout", "ACODEC LORP"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + dai-link-3 { + sound-dai = <&toddr_a>; + }; + + dai-link-4 { + sound-dai = <&toddr_b>; + }; + + dai-link-5 { + sound-dai = <&toddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-6 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_B>; + }; + }; + + /* i2s jack output interface */ + dai-link-7 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>; + }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_C>; + }; + }; + + /* hdmi glue */ + dai-link-8 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + + /* acodec glue */ + dai-link-9 { + sound-dai = <&toacodec TOACODEC_OUT>; + + codec { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&acodec { + AVDD-supply = <&vddao_1v8>; + status = "okay"; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU1_CLK>; + clock-latency = <50000>; +}; + +&cpu2 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU2_CLK>; + clock-latency = <50000>; +}; + +&cpu3 { + cpu-supply = <&vddcpu>; + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU3_CLK>; + clock-latency = <50000>; +}; + +&cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; + }; +}; + +&ext_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_14 */ + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; + pinctrl-names = "default"; + status = "okay"; + phy-mode = "rgmii-txid"; + phy-handle = <&external_phy>; +}; + +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + +&gpio { + gpio-line-names = + /* GPIOZ */ + "ETH_MDIO", /* GPIOZ_0 */ + "ETH_MDC", /* GPIOZ_1 */ + "ETH_RXCLK", /* GPIOZ_2 */ + "ETH_RX_DV", /* GPIOZ_3 */ + "ETH_RXD0", /* GPIOZ_4 */ + "ETH_RXD1", /* GPIOZ_5 */ + "ETH_RXD2", /* GPIOZ_6 */ + "ETH_RXD3", /* GPIOZ_7 */ + "ETH_TXCLK", /* GPIOZ_8 */ + "ETH_TXEN", /* GPIOZ_9 */ + "ETH_TXD0", /* GPIOZ_10 */ + "ETH_TXD1", /* GPIOZ_11 */ + "ETH_TXD2", /* GPIOZ_12 */ + "ETH_TXD3", /* GPIOZ_13 */ + "ETH_INTR", /* GPIOZ_14 */ + "ETH_NRST", /* GPIOZ_15 */ + /* GPIOH */ + "HDMI_SDA", /* GPIOH_0 */ + "HDMI_SCL", /* GPIOH_1 */ + "HDMI_HPD", /* GPIOH_2 */ + "HDMI_CEC", /* GPIOH_3 */ + "VL-RST_N", /* GPIOH_4 */ + "CON1-P36", /* GPIOH_5 */ + "VL-PWREN", /* GPIOH_6 */ + "WiFi_3V3_1V8", /* GPIOH_7 */ + "TFLASH_VDD_EN", /* GPIOH_8 */ + /* BOOT */ + "eMMC_D0", /* BOOT_0 */ + "eMMC_D1", /* BOOT_1 */ + "eMMC_D2", /* BOOT_2 */ + "eMMC_D3", /* BOOT_3 */ + "eMMC_D4", /* BOOT_4 */ + "eMMC_D5", /* BOOT_5 */ + "eMMC_D6", /* BOOT_6 */ + "eMMC_D7", /* BOOT_7 */ + "eMMC_CLK", /* BOOT_8 */ + "", + "eMMC_CMD", /* BOOT_10 */ + "", + "eMMC_RST#", /* BOOT_12 */ + "eMMC_DS", /* BOOT_13 */ + /* GPIOC */ + "SD_D0_B", /* GPIOC_0 */ + "SD_D1_B", /* GPIOC_1 */ + "SD_D2_B", /* GPIOC_2 */ + "SD_D3_B", /* GPIOC_3 */ + "SD_CLK_B", /* GPIOC_4 */ + "SD_CMD_B", /* GPIOC_5 */ + "CARD_EN_DET", /* GPIOC_6 */ + "", + /* GPIOA */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", + "CON1-P27", /* GPIOA_14 */ + "CON1-P28", /* GPIOA_15 */ + /* GPIOX */ + "CON1-P16", /* GPIOX_0 */ + "CON1-P18", /* GPIOX_1 */ + "CON1-P22", /* GPIOX_2 */ + "CON1-P11", /* GPIOX_3 */ + "CON1-P13", /* GPIOX_4 */ + "CON1-P07", /* GPIOX_5 */ + "CON1-P33", /* GPIOX_6 */ + "CON1-P15", /* GPIOX_7 */ + "CON1-P19", /* GPIOX_8 */ + "CON1-P21", /* GPIOX_9 */ + "CON1-P24", /* GPIOX_10 */ + "CON1-P23", /* GPIOX_11 */ + "CON1-P08", /* GPIOX_12 */ + "CON1-P10", /* GPIOX_13 */ + "CON1-P29", /* GPIOX_14 */ + "CON1-P31", /* GPIOX_15 */ + "CON1-P26", /* GPIOX_16 */ + "CON1-P03", /* GPIOX_17 */ + "CON1-P05", /* GPIOX_18 */ + "CON1-P32"; /* GPIOX_19 */ + + /* + * WARNING: The USB Hub on the BPI-M5 needs a reset signal + * to be turned high in order to be detected by the USB Controller + * This signal should be handled by a USB specific power sequence + * in order to reset the Hub when USB bus is powered down. + */ + usb-hub { + gpio-hog; + gpios = ; + output-high; + line-name = "usb-hub-reset"; + }; +}; + +&gpio_ao { + gpio-line-names = + /* GPIOAO */ + "DEBUG TX", /* GPIOAO_0 */ + "DEBUG RX", /* GPIOAO_1 */ + "SYS_LED2", /* GPIOAO_2 */ + "UPDATE_KEY", /* GPIOAO_3 */ + "CON1-P40", /* GPIOAO_4 */ + "IR_IN", /* GPIOAO_5 */ + "TF_3V3N_1V8_EN", /* GPIOAO_6 */ + "CON1-P35", /* GPIOAO_7 */ + "CON1-P12", /* GPIOAO_8 */ + "CON1-P37", /* GPIOAO_9 */ + "CON1-P38", /* GPIOAO_10 */ + "SYS_LED", /* GPIOAO_11 */ + /* GPIOE */ + "VDDEE_PWM", /* GPIOE_0 */ + "VDDCPU_PWM", /* GPIOE_1 */ + "TF_PWR_EN"; /* GPIOE_2 */ +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; + hdmi-supply = <&dc_in>; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_c_pins>; + pinctrl-1 = <&sdcard_clk_gate_c_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <50000000>; + disable-wp; + + /* TOFIX: SD card is barely usable in SDR modes */ + + cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; + vmmc-supply = <&tflash_vdd>; + vqmmc-supply = <&vddio_c>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + max-frequency = <200000000>; + disable-wp; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&emmc_1v8>; +}; + +&tdmif_b { + status = "okay"; +}; + +&tdmif_c { + status = "okay"; +}; + +&tdmin_a { + status = "okay"; +}; + +&tdmin_b { + status = "okay"; +}; + +&tdmin_c { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tdmout_c { + status = "okay"; +}; + +&toacodec { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + +&toddr_a { + status = "okay"; +}; + +&toddr_b { + status = "okay"; +}; + +&toddr_c { + status = "okay"; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; +}; + +&usb { + status = "okay"; +}; + +&usb2_phy0 { + phy-supply = <&dc_in>; +}; + +&usb2_phy1 { + /* Enable the hub which is connected to this port */ + phy-supply = <&vl_pwr_en>; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts index 06de0b1ce726..f2c098143594 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-khadas-vim3l.dts @@ -32,6 +32,19 @@ regulator-boot-on; regulator-always-on; }; + + sound { + model = "G12B-KHADAS-VIM3L"; + audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", + "TDMOUT_A IN 1", "FRDDR_B OUT 0", + "TDMOUT_A IN 2", "FRDDR_C OUT 0", + "TDM_A Playback", "TDMOUT_A OUT", + "TDMIN_A IN 0", "TDM_A Capture", + "TDMIN_A IN 13", "TDM_A Loopback", + "TODDR_A IN 0", "TDMIN_A OUT", + "TODDR_B IN 0", "TDMIN_A OUT", + "TODDR_C IN 0", "TDMIN_A OUT"; + }; }; &cpu0 { diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts index 8c327c03d845..8c30ce63686e 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts @@ -23,18 +23,6 @@ }; }; - hub_5v: regulator-hub_5v { - compatible = "regulator-fixed"; - regulator-name = "HUB_5V"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc_5v>; - - /* Connected to the Hub CHIPENABLE, LOW sets low power state */ - gpio = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; - sound { model = "ODROID-C4"; }; @@ -58,8 +46,3 @@ &ir { linux,rc-map-name = "rc-odroid"; }; - -&usb2_phy1 { - /* Enable the hub which is connected to this port */ - phy-supply = <&hub_5v>; -}; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts index bf15700c4b15..f3f953225bf5 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts @@ -44,6 +44,32 @@ }; }; + /* Powers the SATA Disk 0 regulator, which is enabled when a disk load is detected */ + p12v_0: regulator-p12v_0 { + compatible = "regulator-fixed"; + regulator-name = "P12V_0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + vin-supply = <&main_12v>; + + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; + regulator-always-on; + }; + + /* Powers the SATA Disk 1 regulator, which is enabled when a disk load is detected */ + p12v_1: regulator-p12v_1 { + compatible = "regulator-fixed"; + regulator-name = "P12V_1"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + vin-supply = <&main_12v>; + + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; + regulator-always-on; + }; + sound { model = "ODROID-HC4"; }; @@ -90,7 +116,25 @@ status = "disabled"; }; -&usb { - phys = <&usb2_phy0>, <&usb2_phy1>; - phy-names = "usb2-phy0", "usb2-phy1"; +&spifc { + status = "okay"; + pinctrl-0 = <&nor_pins>; + pinctrl-names = "default"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <104000000>; + }; +}; + +&usb { + phys = <&usb2_phy1>; + phy-names = "usb2-phy1"; +}; + +&usb2_phy0 { + status = "disabled"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi index d14716b3d0f1..fd0ad85c165b 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi @@ -46,8 +46,13 @@ regulator-name = "TF_IO"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_5v>; - gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; + enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + + gpios = <&gpio_ao GPIOAO_6 GPIO_OPEN_SOURCE>; gpios-states = <0>; states = <3300000 0>, @@ -78,6 +83,8 @@ regulator-max-microvolt = <5000000>; regulator-always-on; vin-supply = <&main_12v>; + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; }; vcc_1v8: regulator-vcc_1v8 { diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi index c309517abae3..3d8b1f4f2001 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi @@ -401,6 +401,16 @@ status = "disabled"; }; + toacodec: audio-controller@740 { + compatible = "amlogic,sm1-toacodec", + "amlogic,g12a-toacodec"; + reg = <0x0 0x740 0x0 0x4>; + #sound-dai-cells = <1>; + sound-name-prefix = "TOACODEC"; + resets = <&clkc_audio AUD_RESET_TOACODEC>; + status = "disabled"; + }; + tohdmitx: audio-controller@744 { compatible = "amlogic,sm1-tohdmitx", "amlogic,g12a-tohdmitx"; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index 1cc7fdcec51b..8e7a66943b01 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -568,13 +568,13 @@ clocks { compatible = "arm,scpi-clocks"; - scpi_dvfs: scpi-dvfs { + scpi_dvfs: clocks-0 { compatible = "arm,scpi-dvfs-clocks"; #clock-cells = <1>; clock-indices = <0>, <1>, <2>; clock-output-names = "atlclk", "aplclk","gpuclk"; }; - scpi_clk: scpi-clk { + scpi_clk: clocks-1 { compatible = "arm,scpi-variable-clocks"; #clock-cells = <1>; clock-indices = <3>; @@ -582,7 +582,7 @@ }; }; - scpi_devpd: scpi-power-domains { + scpi_devpd: power-controller { compatible = "arm,scpi-power-domains"; num-domains = <2>; #power-domain-cells = <1>; diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile index 998e240aa698..11eae3e3a944 100644 --- a/arch/arm64/boot/dts/broadcom/Makefile +++ b/arch/arm64/boot/dts/broadcom/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb \ +dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \ + bcm2711-rpi-4-b.dtb \ bcm2837-rpi-3-a-plus.dtb \ bcm2837-rpi-3-b.dtb \ bcm2837-rpi-3-b-plus.dtb \ diff --git a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts new file mode 100644 index 000000000000..b9000f58beb5 --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-400.dts @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "arm/bcm2711-rpi-400.dts" diff --git a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi index 8060178b365d..a5a64d17d9ea 100644 --- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi @@ -306,7 +306,7 @@ interrupt-names = "nand"; status = "okay"; - nandcs: nandcs@0 { + nandcs: nand@0 { compatible = "brcm,nandcs"; reg = <0>; }; diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi index 2ffb2c92182a..7b04dfe67bef 100644 --- a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi +++ b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi @@ -470,7 +470,7 @@ status = "disabled"; }; - uart0: uart@100000 { + uart0: serial@100000 { device_type = "serial"; compatible = "snps,dw-apb-uart"; reg = <0x00100000 0x1000>; @@ -481,7 +481,7 @@ status = "disabled"; }; - uart1: uart@110000 { + uart1: serial@110000 { device_type = "serial"; compatible = "snps,dw-apb-uart"; reg = <0x00110000 0x1000>; @@ -492,7 +492,7 @@ status = "disabled"; }; - uart2: uart@120000 { + uart2: serial@120000 { device_type = "serial"; compatible = "snps,dw-apb-uart"; reg = <0x00120000 0x1000>; @@ -503,7 +503,7 @@ status = "disabled"; }; - uart3: uart@130000 { + uart3: serial@130000 { device_type = "serial"; compatible = "snps,dw-apb-uart"; reg = <0x00130000 0x1000>; diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index 773d9abe3a44..cbcc01a66aab 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi @@ -391,6 +391,7 @@ interrupts = <7 IRQ_TYPE_LEVEL_LOW>; reg = <0x66>; samsung,s2mps11-wrstbi-ground; + wakeup-source; s2mps13_osc: clocks { compatible = "samsung,s2mps13-clk"; diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 44890d56c194..25806c4924cb 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -41,6 +41,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-var-som-symphony.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw71xx-0x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw72xx-0x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw73xx-0x.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7901.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-beacon-kit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts index 6290e2f9de6a..e8562585d4ac 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frwy.dts @@ -24,6 +24,10 @@ status = "okay"; }; +&pcie1 { + status = "okay"; +}; + &qspi { status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 9058cfa4980f..50a72cda4727 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -238,35 +238,35 @@ "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; - reg = <0x60000 0x100 0x60e00 0x18>; + reg = <0x60000 0x100>, <0x60e00 0x18>; ranges = <0x0 0x60100 0x500>; rtic_a: rtic-a@0 { compatible = "fsl,sec-v5.4-rtic-memory", "fsl,sec-v5.0-rtic-memory", "fsl,sec-v4.0-rtic-memory"; - reg = <0x00 0x20 0x100 0x100>; + reg = <0x00 0x20>, <0x100 0x100>; }; rtic_b: rtic-b@20 { compatible = "fsl,sec-v5.4-rtic-memory", "fsl,sec-v5.0-rtic-memory", "fsl,sec-v4.0-rtic-memory"; - reg = <0x20 0x20 0x200 0x100>; + reg = <0x20 0x20>, <0x200 0x100>; }; rtic_c: rtic-c@40 { compatible = "fsl,sec-v5.4-rtic-memory", "fsl,sec-v5.0-rtic-memory", "fsl,sec-v4.0-rtic-memory"; - reg = <0x40 0x20 0x300 0x100>; + reg = <0x40 0x20>, <0x300 0x100>; }; rtic_d: rtic-d@60 { compatible = "fsl,sec-v5.4-rtic-memory", "fsl,sec-v5.0-rtic-memory", "fsl,sec-v4.0-rtic-memory"; - reg = <0x60 0x20 0x400 0x100>; + reg = <0x60 0x20>, <0x400 0x100>; }; }; }; @@ -522,8 +522,8 @@ pcie1: pcie@3400000 { compatible = "fsl,ls1012a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x40 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts index 9322c6ad8e4a..d7b527272500 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts @@ -275,6 +275,10 @@ status = "okay"; }; +&optee { + status = "okay"; +}; + &sai4 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi index a30249ebffa8..b2e3e5d2a108 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi @@ -88,7 +88,7 @@ }; firmware { - optee { + optee: optee { compatible = "linaro,optee-tz"; method = "smc"; status = "disabled"; @@ -617,8 +617,8 @@ pcie1: pcie@3400000 { compatible = "fsl,ls1028a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x80 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x80 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = , /* PME interrupt */ ; /* aer interrupt */ @@ -644,8 +644,8 @@ pcie2: pcie@3500000 { compatible = "fsl,ls1028a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x88 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x88 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = , ; @@ -990,19 +990,19 @@ msi-map = <0 &its 0x17 0xe>; iommu-map = <0 &smmu 0x17 0xe>; /* PF0-6 BAR0 - non-prefetchable memory */ - ranges = <0x82000000 0x0 0x00000000 0x1 0xf8000000 0x0 0x160000 + ranges = <0x82000000 0x1 0xf8000000 0x1 0xf8000000 0x0 0x160000 /* PF0-6 BAR2 - prefetchable memory */ - 0xc2000000 0x0 0x00000000 0x1 0xf8160000 0x0 0x070000 + 0xc2000000 0x1 0xf8160000 0x1 0xf8160000 0x0 0x070000 /* PF0: VF0-1 BAR0 - non-prefetchable memory */ - 0x82000000 0x0 0x00000000 0x1 0xf81d0000 0x0 0x020000 + 0x82000000 0x1 0xf81d0000 0x1 0xf81d0000 0x0 0x020000 /* PF0: VF0-1 BAR2 - prefetchable memory */ - 0xc2000000 0x0 0x00000000 0x1 0xf81f0000 0x0 0x020000 + 0xc2000000 0x1 0xf81f0000 0x1 0xf81f0000 0x0 0x020000 /* PF1: VF0-1 BAR0 - non-prefetchable memory */ - 0x82000000 0x0 0x00000000 0x1 0xf8210000 0x0 0x020000 + 0x82000000 0x1 0xf8210000 0x1 0xf8210000 0x0 0x020000 /* PF1: VF0-1 BAR2 - prefetchable memory */ - 0xc2000000 0x0 0x00000000 0x1 0xf8230000 0x0 0x020000 + 0xc2000000 0x1 0xf8230000 0x1 0xf8230000 0x0 0x020000 /* BAR4 (PF5) - non-prefetchable memory */ - 0x82000000 0x0 0x00000000 0x1 0xfc000000 0x0 0x400000>; + 0x82000000 0x1 0xfc000000 0x1 0xfc000000 0x0 0x400000>; enetc_port0: ethernet@0,0 { compatible = "fsl,enetc"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 28c51e521cb2..01b01e320411 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -869,8 +869,8 @@ pcie1: pcie@3400000 { compatible = "fsl,ls1043a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x40 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ @@ -895,8 +895,8 @@ pcie2: pcie@3500000 { compatible = "fsl,ls1043a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x48 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 128 0x4>, <0 127 0x4>; @@ -921,8 +921,8 @@ pcie3: pcie@3600000 { compatible = "fsl,ls1043a-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x50 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x50 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 162 0x4>, <0 161 0x4>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 39458305e333..687fea6d8afa 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -773,8 +773,8 @@ pcie1: pcie@3400000 { compatible = "fsl,ls1046a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x40 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = , /* controller interrupt */ ; /* PME interrupt */ @@ -799,8 +799,8 @@ pcie_ep1: pcie_ep@3400000 { compatible = "fsl,ls1046a-pcie-ep","fsl,ls-pcie-ep"; - reg = <0x00 0x03400000 0x0 0x00100000 - 0x40 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03400000 0x0 0x00100000>, + <0x40 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <6>; num-ob-windows = <8>; @@ -809,8 +809,8 @@ pcie2: pcie@3500000 { compatible = "fsl,ls1046a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x48 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = , /* controller interrupt */ ; /* PME interrupt */ @@ -835,8 +835,8 @@ pcie_ep2: pcie_ep@3500000 { compatible = "fsl,ls1046a-pcie-ep","fsl,ls-pcie-ep"; - reg = <0x00 0x03500000 0x0 0x00100000 - 0x48 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03500000 0x0 0x00100000>, + <0x48 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <6>; num-ob-windows = <8>; @@ -845,8 +845,8 @@ pcie3: pcie@3600000 { compatible = "fsl,ls1046a-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x50 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x50 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = , /* controller interrupt */ ; /* PME interrupt */ @@ -871,8 +871,8 @@ pcie_ep3: pcie_ep@3600000 { compatible = "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"; - reg = <0x00 0x03600000 0x0 0x00100000 - 0x50 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03600000 0x0 0x00100000>, + <0x50 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <6>; num-ob-windows = <8>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index 8ffbc9fde041..2fa6cfbef01f 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -536,8 +536,8 @@ pcie1: pcie@3400000 { compatible = "fsl,ls1088a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x20 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x20 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ interrupt-names = "aer"; @@ -562,8 +562,8 @@ pcie_ep1: pcie-ep@3400000 { compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; - reg = <0x00 0x03400000 0x0 0x00100000 - 0x20 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03400000 0x0 0x00100000>, + <0x20 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <24>; num-ob-windows = <256>; @@ -573,8 +573,8 @@ pcie2: pcie@3500000 { compatible = "fsl,ls1088a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x28 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x28 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 113 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ interrupt-names = "aer"; @@ -599,8 +599,8 @@ pcie_ep2: pcie-ep@3500000 { compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; - reg = <0x00 0x03500000 0x0 0x00100000 - 0x28 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03500000 0x0 0x00100000>, + <0x28 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <6>; num-ob-windows = <6>; @@ -609,8 +609,8 @@ pcie3: pcie@3600000 { compatible = "fsl,ls1088a-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x30 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x30 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "regs", "config"; interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ interrupt-names = "aer"; @@ -635,8 +635,8 @@ pcie_ep3: pcie-ep@3600000 { compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; - reg = <0x00 0x03600000 0x0 0x00100000 - 0x30 0x00000000 0x8 0x00000000>; + reg = <0x00 0x03600000 0x0 0x00100000>, + <0x30 0x00000000 0x8 0x00000000>; reg-names = "regs", "addr_space"; num-ib-windows = <6>; num-ob-windows = <6>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index 76ab68d2de0b..6f6667b70028 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -120,32 +120,32 @@ }; &pcie1 { - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x10 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x10 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ }; &pcie2 { - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x12 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x12 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ }; &pcie3 { - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x14 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x14 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ }; &pcie4 { - reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ - 0x16 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03700000 0x0 0x00100000>, /* controller registers */ + <0x16 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi index da24dc127698..c3dc38188c17 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi @@ -121,8 +121,8 @@ &pcie1 { compatible = "fsl,ls2088a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x20 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x20 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000 0x82000000 0x0 0x40000000 0x20 0x40000000 0x0 0x40000000>; @@ -130,8 +130,8 @@ &pcie2 { compatible = "fsl,ls2088a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x28 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x28 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000 0x82000000 0x0 0x40000000 0x28 0x40000000 0x0 0x40000000>; @@ -139,8 +139,8 @@ &pcie3 { compatible = "fsl,ls2088a-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x30 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x30 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000 0x82000000 0x0 0x40000000 0x30 0x40000000 0x0 0x40000000>; @@ -148,8 +148,8 @@ &pcie4 { compatible = "fsl,ls2088a-pcie"; - reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ - 0x38 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03700000 0x0 0x00100000>, /* controller registers */ + <0x38 0x00000000 0x0 0x00002000>; /* configuration space */ ranges = <0x81000000 0x0 0x00000000 0x38 0x00010000 0x0 0x00010000 0x82000000 0x0 0x40000000 0x38 0x40000000 0x0 0x40000000>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index 135ac8210871..801ba9612d36 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -929,7 +929,6 @@ QORIQ_CLK_PLL_DIV(4)>; clock-names = "dspi"; spi-num-chipselects = <5>; - bus-num = <0>; }; esdhc: esdhc@2140000 { diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi index 0551f6f4c313..c4b1a59ba424 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi @@ -1089,8 +1089,8 @@ pcie1: pcie@3400000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ - 0x80 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03400000 0x0 0x00100000>, /* controller registers */ + <0x80 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ @@ -1117,8 +1117,8 @@ pcie2: pcie@3500000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ - 0x88 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03500000 0x0 0x00100000>, /* controller registers */ + <0x88 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ @@ -1145,8 +1145,8 @@ pcie3: pcie@3600000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ - 0x90 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03600000 0x0 0x00100000>, /* controller registers */ + <0x90 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ @@ -1173,8 +1173,8 @@ pcie4: pcie@3700000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ - 0x98 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03700000 0x0 0x00100000>, /* controller registers */ + <0x98 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ @@ -1201,8 +1201,8 @@ pcie5: pcie@3800000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03800000 0x0 0x00100000 /* controller registers */ - 0xa0 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03800000 0x0 0x00100000>, /* controller registers */ + <0xa0 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ @@ -1229,8 +1229,8 @@ pcie6: pcie@3900000 { compatible = "fsl,lx2160a-pcie"; - reg = <0x00 0x03900000 0x0 0x00100000 /* controller registers */ - 0xa8 0x00000000 0x0 0x00002000>; /* configuration space */ + reg = <0x00 0x03900000 0x0 0x00100000>, /* controller registers */ + <0xa8 0x00000000 0x0 0x00002000>; /* configuration space */ reg-names = "csr_axi_slave", "config_axi_slave"; interrupts = , /* AER interrupt */ , /* PME interrupt */ diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi index e1e81ca0ca69..a79f42a9618e 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi @@ -77,9 +77,12 @@ conn_subsys: bus@5b000000 { ; clocks = <&enet0_lpcg IMX_LPCG_CLK_4>, <&enet0_lpcg IMX_LPCG_CLK_2>, - <&enet0_lpcg IMX_LPCG_CLK_1>, + <&enet0_lpcg IMX_LPCG_CLK_3>, <&enet0_lpcg IMX_LPCG_CLK_0>; clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; + assigned-clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_ENET_0 IMX_SC_C_CLKDIV>; + assigned-clock-rates = <250000000>, <125000000>; fsl,num-tx-queues=<3>; fsl,num-rx-queues=<3>; power-domains = <&pd IMX_SC_R_ENET_0>; @@ -94,9 +97,12 @@ conn_subsys: bus@5b000000 { ; clocks = <&enet1_lpcg IMX_LPCG_CLK_4>, <&enet1_lpcg IMX_LPCG_CLK_2>, - <&enet1_lpcg IMX_LPCG_CLK_1>, + <&enet1_lpcg IMX_LPCG_CLK_3>, <&enet1_lpcg IMX_LPCG_CLK_0>; clock-names = "ipg", "ahb", "enet_clk_ref", "ptp"; + assigned-clocks = <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>, + <&clk IMX_SC_R_ENET_1 IMX_SC_C_CLKDIV>; + assigned-clock-rates = <250000000>, <125000000>; fsl,num-tx-queues=<3>; fsl,num-rx-queues=<3>; power-domains = <&pd IMX_SC_R_ENET_1>; @@ -152,15 +158,19 @@ conn_subsys: bus@5b000000 { #clock-cells = <1>; clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>, <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>, - <&conn_axi_clk>, <&conn_ipg_clk>, <&conn_ipg_clk>; + <&conn_axi_clk>, + <&clk IMX_SC_R_ENET_0 IMX_SC_C_TXCLK>, + <&conn_ipg_clk>, + <&conn_ipg_clk>; clock-indices = , , - , , - ; - clock-output-names = "enet0_ipg_root_clk", - "enet0_tx_clk", - "enet0_ahb_clk", - "enet0_ipg_clk", - "enet0_ipg_s_clk"; + , , + , ; + clock-output-names = "enet0_lpcg_timer_clk", + "enet0_lpcg_txc_sampling_clk", + "enet0_lpcg_ahb_clk", + "enet0_lpcg_rgmii_txc_clk", + "enet0_lpcg_ipg_clk", + "enet0_lpcg_ipg_s_clk"; power-domains = <&pd IMX_SC_R_ENET_0>; }; @@ -170,15 +180,19 @@ conn_subsys: bus@5b000000 { #clock-cells = <1>; clocks = <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>, <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>, - <&conn_axi_clk>, <&conn_ipg_clk>, <&conn_ipg_clk>; + <&conn_axi_clk>, + <&clk IMX_SC_R_ENET_1 IMX_SC_C_TXCLK>, + <&conn_ipg_clk>, + <&conn_ipg_clk>; clock-indices = , , - , , - ; - clock-output-names = "enet1_ipg_root_clk", - "enet1_tx_clk", - "enet1_ahb_clk", - "enet1_ipg_clk", - "enet1_ipg_s_clk"; + , , + , ; + clock-output-names = "enet1_lpcg_timer_clk", + "enet1_lpcg_txc_sampling_clk", + "enet1_lpcg_ahb_clk", + "enet1_lpcg_rgmii_txc_clk", + "enet1_lpcg_ipg_clk", + "enet1_lpcg_ipg_s_clk"; power-domains = <&pd IMX_SC_R_ENET_1>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi index 6518f088b2c2..e033d0257b5a 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi @@ -314,6 +314,7 @@ srp-disable; adp-disable; usb-role-switch; + disable-over-current; samsung,picophy-pre-emp-curr-control = <3>; samsung,picophy-dc-vol-level-adjust = <7>; status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts new file mode 100644 index 000000000000..5a1e9df39bec --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts @@ -0,0 +1,1019 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2020 Gateworks Corporation + */ + +/dts-v1/; + +#include +#include +#include + +#include "imx8mm.dtsi" + +/ { + model = "Gateworks Venice GW7901 i.MX8MM board"; + compatible = "gw,imx8mm-gw7901", "fsl,imx8mm"; + + aliases { + ethernet0 = &fec1; + ethernet1 = &lan1; + ethernet2 = &lan2; + ethernet3 = &lan3; + ethernet4 = &lan4; + usb0 = &usbotg1; + usb1 = &usbotg2; + }; + + chosen { + stdout-path = &uart2; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0 0x80000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + user-pb { + label = "user_pb"; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + user-pb1x { + label = "user_pb1x"; + linux,code = ; + interrupt-parent = <&gsc>; + interrupts = <0>; + }; + + key-erased { + label = "key_erased"; + linux,code = ; + interrupt-parent = <&gsc>; + interrupts = <1>; + }; + + eeprom-wp { + label = "eeprom_wp"; + linux,code = ; + interrupt-parent = <&gsc>; + interrupts = <2>; + }; + + tamper { + label = "tamper"; + linux,code = ; + interrupt-parent = <&gsc>; + interrupts = <5>; + }; + + switch-hold { + label = "switch_hold"; + linux,code = ; + interrupt-parent = <&gsc>; + interrupts = <7>; + }; + }; + + led-controller { + compatible = "gpio-leds"; + + led-0 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led01_red"; + gpios = <&leds_gpio 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-1 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led01_grn"; + gpios = <&leds_gpio 1 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-2 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led02_red"; + gpios = <&leds_gpio 2 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-3 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led02_grn"; + gpios = <&leds_gpio 3 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-4 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led03_red"; + gpios = <&leds_gpio 4 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-5 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led03_grn"; + gpios = <&leds_gpio 5 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-6 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led04_red"; + gpios = <&leds_gpio 8 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-7 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led04_grn"; + gpios = <&leds_gpio 9 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-8 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led05_red"; + gpios = <&leds_gpio 10 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-9 { + function = LED_FUNCTION_STATUS; + color = ; + label = "led05_grn"; + gpios = <&leds_gpio 11 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-a { + function = LED_FUNCTION_STATUS; + color = ; + label = "led06_red"; + gpios = <&leds_gpio 12 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-b { + function = LED_FUNCTION_STATUS; + color = ; + label = "led06_grn"; + gpios = <&leds_gpio 13 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + regulator-ioexp { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_ioexp>; + compatible = "regulator-fixed"; + regulator-name = "ioexp"; + gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + startup-delay-us = <100>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + regulator-isouart { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_isouart>; + compatible = "regulator-fixed"; + regulator-name = "iso_uart"; + gpio = <&gpio1 13 GPIO_ACTIVE_LOW>; + startup-delay-us = <100>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_usb2_vbus: regulator-usb2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usb2>; + compatible = "regulator-fixed"; + regulator-name = "usb_usb2_vbus"; + gpio = <&gpio4 17 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_wifi: regulator-wifi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_wl>; + compatible = "regulator-fixed"; + regulator-name = "wifi"; + gpio = <&gpio3 25 GPIO_ACTIVE_HIGH>; + enable-active-high; + startup-delay-us = <100>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + +&ddrc { + operating-points-v2 = <&ddrc_opp_table>; + + ddrc_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-25M { + opp-hz = /bits/ 64 <25000000>; + }; + + opp-100M { + opp-hz = /bits/ 64 <100000000>; + }; + + opp-750M { + opp-hz = /bits/ 64 <750000000>; + }; + }; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + status = "okay"; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + local-mac-address = [00 00 00 00 00 00]; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + gsc: gsc@20 { + compatible = "gw,gsc"; + reg = <0x20>; + pinctrl-0 = <&pinctrl_gsc>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + adc { + compatible = "gw,gsc-adc"; + #address-cells = <1>; + #size-cells = <0>; + + channel@6 { + gw,mode = <0>; + reg = <0x06>; + label = "temp"; + }; + + channel@8 { + gw,mode = <1>; + reg = <0x08>; + label = "vdd_bat"; + }; + + channel@82 { + gw,mode = <2>; + reg = <0x82>; + label = "vin_aux1"; + gw,voltage-divider-ohms = <22100 1000>; + }; + + channel@84 { + gw,mode = <2>; + reg = <0x84>; + label = "vin_aux2"; + gw,voltage-divider-ohms = <22100 1000>; + }; + + channel@86 { + gw,mode = <2>; + reg = <0x86>; + label = "vdd_vin"; + gw,voltage-divider-ohms = <22100 1000>; + }; + + channel@88 { + gw,mode = <2>; + reg = <0x88>; + label = "vdd_3p3"; + gw,voltage-divider-ohms = <10000 10000>; + }; + + channel@8c { + gw,mode = <2>; + reg = <0x8c>; + label = "vdd_2p5"; + gw,voltage-divider-ohms = <10000 10000>; + }; + + channel@8e { + gw,mode = <2>; + reg = <0x8e>; + label = "vdd_0p95"; + }; + + channel@90 { + gw,mode = <2>; + reg = <0x90>; + label = "vdd_soc"; + }; + + channel@92 { + gw,mode = <2>; + reg = <0x92>; + label = "vdd_arm"; + }; + + channel@98 { + gw,mode = <2>; + reg = <0x98>; + label = "vdd_1p8"; + }; + + channel@9a { + gw,mode = <2>; + reg = <0x9a>; + label = "vdd_1p2"; + }; + + channel@9c { + gw,mode = <2>; + reg = <0x9c>; + label = "vdd_dram"; + }; + + channel@a2 { + gw,mode = <2>; + reg = <0xa2>; + label = "vdd_gsc"; + gw,voltage-divider-ohms = <10000 10000>; + }; + }; + }; + + gpio: gpio@23 { + compatible = "nxp,pca9555"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&gsc>; + interrupts = <4>; + }; + + eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + pagesize = <16>; + }; + + eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + pagesize = <16>; + }; + + eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + pagesize = <16>; + }; + + rtc@68 { + compatible = "dallas,ds1672"; + reg = <0x68>; + }; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic@4b { + compatible = "rohm,bd71847"; + reg = <0x4b>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio3>; + interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + rohm,reset-snvs-powered; + #clock-cells = <0>; + clocks = <&osc_32k 0>; + clock-output-names = "clk-32k-out"; + + regulators { + /* vdd_soc: 0.805-0.900V (typ=0.8V) */ + BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + }; + + /* vdd_arm: 0.805-1.0V (typ=0.9V) */ + BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <1000000>; + rohm,dvs-idle-voltage = <900000>; + }; + + /* vdd_0p9: 0.805-1.0V (typ=0.9V) */ + BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdd_3p3 */ + BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdd_1p8 */ + BUCK5 { + regulator-name = "buck5"; + regulator-min-microvolt = <1605000>; + regulator-max-microvolt = <1995000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdd_dram */ + BUCK6 { + regulator-name = "buck6"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + + /* nvcc_snvs_1p8 */ + LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1900000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdd_snvs_0p8 */ + LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + }; + + /* vdda_1p8 */ + LDO3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + leds_gpio: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + switch: switch@5f { + compatible = "microchip,ksz9897"; + reg = <0x5f>; + pinctrl-0 = <&pinctrl_ksz>; + interrupt-parent = <&gpio4>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + phy-mode = "rgmii-id"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + lan1: port@0 { + reg = <0>; + label = "lan1"; + local-mac-address = [00 00 00 00 00 00]; + }; + + lan2: port@1 { + reg = <1>; + label = "lan2"; + local-mac-address = [00 00 00 00 00 00]; + }; + + lan3: port@2 { + reg = <2>; + label = "lan3"; + local-mac-address = [00 00 00 00 00 00]; + }; + + lan4: port@3 { + reg = <3>; + label = "lan4"; + local-mac-address = [00 00 00 00 00 00]; + }; + + port@5 { + reg = <5>; + label = "cpu"; + ethernet = <&fec1>; + phy-mode = "rgmii-id"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + + crypto@60 { + compatible = "atmel,atecc508a"; + reg = <0x60>; + }; +}; + +&i2c4 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>; + rts-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + cts-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + dtr-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +/* console */ +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>; + cts-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>, <&pinctrl_uart4_gpio>; + cts-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio5 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&usbotg1 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&usbotg2 { + dr_mode = "host"; + vbus-supply = <®_usb2_vbus>; + status = "okay"; +}; + +/* SDIO WiFi */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + bus-width = <4>; + non-removable; + vmmc-supply = <®_wifi>; + status = "okay"; +}; + +/* microSD */ +&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>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + vmmc-supply = <®_3p3v>; + status = "okay"; +}; + +/* eMMC */ +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_TX_GPIO5_IO3 0x40000041 /* DIG2_OUT */ + MX8MM_IOMUXC_SPDIF_RX_GPIO5_IO4 0x40000041 /* DIG2_IN */ + MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x40000041 /* DIG1_IN */ + MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x40000041 /* DIG1_OUT */ + MX8MM_IOMUXC_SAI3_RXD_GPIO4_IO30 0x40000041 /* SIM2DET# */ + MX8MM_IOMUXC_SAI3_RXC_GPIO4_IO29 0x40000041 /* SIM1DET# */ + MX8MM_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5 0x40000041 /* SIM2SEL */ + >; + }; + + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x3 + MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MM_IOMUXC_SAI1_TXD6_GPIO4_IO18 0x19 /* IRQ# */ + MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19 0x19 /* RST# */ + >; + }; + + pinctrl_gsc: gscgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16 0x159 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 + MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3 + MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA 0x400001c3 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_ksz: kszgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_TXD6_GPIO4_IO18 0x41 + MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19 0x41 /* RST# */ + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20 0x41 + >; + }; + + pinctrl_reg_isouart: regisouartgrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 + >; + }; + + pinctrl_reg_ioexp: regioexpgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x40000041 + >; + }; + + pinctrl_reg_wl: regwlgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25 0x40000041 + >; + }; + + pinctrl_reg_usb2: regusb1grp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_TXD5_GPIO4_IO17 0x41 + MX8MM_IOMUXC_GPIO1_IO15_USB2_OTG_OC 0x41 + >; + }; + + pinctrl_spi1: spi1grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK 0x82 + MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI 0x82 + MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO 0x82 + MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x140 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140 + MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140 + MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1 0x140 + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x140 + MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x140 + MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x140 + MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x140 + >; + }; + + pinctrl_uart1_gpio: uart1gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO00_GPIO1_IO0 0x40000041 /* RS422# */ + MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x40000041 /* RS485# */ + MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x40000041 /* RS232# */ + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX 0x140 + MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX 0x140 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX 0x140 + MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX 0x140 + MX8MM_IOMUXC_SAI1_RXD7_GPIO4_IO9 0x140 + MX8MM_IOMUXC_SAI1_TXFS_GPIO4_IO10 0x140 + >; + }; + + pinctrl_uart3_gpio: uart3gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6 0x40000041 /* RS232# */ + MX8MM_IOMUXC_SAI1_RXD5_GPIO4_IO7 0x40000041 /* RS422# */ + MX8MM_IOMUXC_SAI1_RXD6_GPIO4_IO8 0x40000041 /* RS485# */ + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 + MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140 + MX8MM_IOMUXC_ECSPI2_MOSI_GPIO5_IO11 0x140 + MX8MM_IOMUXC_ECSPI2_MISO_GPIO5_IO12 0x140 + >; + }; + + pinctrl_uart4_gpio: uart4gpiogrp { + fsl,pins = < + + MX8MM_IOMUXC_ECSPI2_SCLK_GPIO5_IO10 0x40000041 /* RS232# */ + MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x40000041 /* RS422# */ + MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27 0x40000041 /* RS485# */ + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x190 + MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d0 + MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d0 + MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d0 + MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d0 + MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2-gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x1c4 + MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x190 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d0 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d0 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d0 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d0 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d0 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d0 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d0 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d0 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d0 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x194 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d4 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d4 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d4 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d4 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d4 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d4 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d4 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d4 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d4 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x196 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d6 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d6 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d6 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d6 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d6 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d6 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d6 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d6 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d6 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x196 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; +}; + +&cpu_alert0 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; +}; + +&cpu_crit0 { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index a27e02bee6b4..e7648c3b8390 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -261,6 +261,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x0 0x0 0x3e000000>; + dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>; nvmem-cells = <&imx8mm_uid>; nvmem-cell-names = "soc_unique_id"; @@ -271,117 +272,125 @@ #size-cells = <1>; ranges = <0x30000000 0x30000000 0x400000>; - sai1: sai@30010000 { - #sound-dai-cells = <0>; - compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; - reg = <0x30010000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_SAI1_IPG>, - <&clk IMX8MM_CLK_SAI1_ROOT>, - <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dmas = <&sdma2 0 2 0>, <&sdma2 1 2 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + spba2: spba-bus@30000000 { + compatible = "fsl,spba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x30000000 0x100000>; + ranges; - sai2: sai@30020000 { - #sound-dai-cells = <0>; - compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; - reg = <0x30020000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_SAI2_IPG>, - <&clk IMX8MM_CLK_SAI2_ROOT>, - <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dmas = <&sdma2 2 2 0>, <&sdma2 3 2 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + sai1: sai@30010000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30010000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI1_IPG>, + <&clk IMX8MM_CLK_SAI1_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 0 2 0>, <&sdma2 1 2 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - sai3: sai@30030000 { - #sound-dai-cells = <0>; - compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; - reg = <0x30030000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_SAI3_IPG>, - <&clk IMX8MM_CLK_SAI3_ROOT>, - <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dmas = <&sdma2 4 2 0>, <&sdma2 5 2 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + sai2: sai@30020000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30020000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI2_IPG>, + <&clk IMX8MM_CLK_SAI2_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 2 2 0>, <&sdma2 3 2 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - sai5: sai@30050000 { - #sound-dai-cells = <0>; - compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; - reg = <0x30050000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_SAI5_IPG>, - <&clk IMX8MM_CLK_SAI5_ROOT>, - <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dmas = <&sdma2 8 2 0>, <&sdma2 9 2 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + sai3: sai@30030000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30030000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI3_IPG>, + <&clk IMX8MM_CLK_SAI3_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 4 2 0>, <&sdma2 5 2 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - sai6: sai@30060000 { - #sound-dai-cells = <0>; - compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; - reg = <0x30060000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_SAI6_IPG>, - <&clk IMX8MM_CLK_SAI6_ROOT>, - <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dmas = <&sdma2 10 2 0>, <&sdma2 11 2 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + sai5: sai@30050000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30050000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI5_IPG>, + <&clk IMX8MM_CLK_SAI5_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 8 2 0>, <&sdma2 9 2 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - micfil: audio-controller@30080000 { - compatible = "fsl,imx8mm-micfil"; - reg = <0x30080000 0x10000>; - interrupts = , - , - , - ; - clocks = <&clk IMX8MM_CLK_PDM_IPG>, - <&clk IMX8MM_CLK_PDM_ROOT>, - <&clk IMX8MM_AUDIO_PLL1_OUT>, - <&clk IMX8MM_AUDIO_PLL2_OUT>, - <&clk IMX8MM_CLK_EXT3>; - clock-names = "ipg_clk", "ipg_clk_app", - "pll8k", "pll11k", "clkext3"; - dmas = <&sdma2 24 25 0x80000000>; - dma-names = "rx"; - status = "disabled"; - }; + sai6: sai@30060000 { + #sound-dai-cells = <0>; + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30060000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI6_IPG>, + <&clk IMX8MM_CLK_SAI6_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 10 2 0>, <&sdma2 11 2 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - spdif1: spdif@30090000 { - compatible = "fsl,imx35-spdif"; - reg = <0x30090000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, /* core */ - <&clk IMX8MM_CLK_24M>, /* rxtx0 */ - <&clk IMX8MM_CLK_SPDIF1>, /* rxtx1 */ - <&clk IMX8MM_CLK_DUMMY>, /* rxtx2 */ - <&clk IMX8MM_CLK_DUMMY>, /* rxtx3 */ - <&clk IMX8MM_CLK_DUMMY>, /* rxtx4 */ - <&clk IMX8MM_CLK_AUDIO_AHB>, /* rxtx5 */ - <&clk IMX8MM_CLK_DUMMY>, /* rxtx6 */ - <&clk IMX8MM_CLK_DUMMY>, /* rxtx7 */ - <&clk IMX8MM_CLK_DUMMY>; /* spba */ - clock-names = "core", "rxtx0", - "rxtx1", "rxtx2", - "rxtx3", "rxtx4", - "rxtx5", "rxtx6", - "rxtx7", "spba"; - dmas = <&sdma2 28 18 0>, <&sdma2 29 18 0>; - dma-names = "rx", "tx"; - status = "disabled"; + micfil: audio-controller@30080000 { + compatible = "fsl,imx8mm-micfil"; + reg = <0x30080000 0x10000>; + interrupts = , + , + , + ; + clocks = <&clk IMX8MM_CLK_PDM_IPG>, + <&clk IMX8MM_CLK_PDM_ROOT>, + <&clk IMX8MM_AUDIO_PLL1_OUT>, + <&clk IMX8MM_AUDIO_PLL2_OUT>, + <&clk IMX8MM_CLK_EXT3>; + clock-names = "ipg_clk", "ipg_clk_app", + "pll8k", "pll11k", "clkext3"; + dmas = <&sdma2 24 25 0x80000000>; + dma-names = "rx"; + status = "disabled"; + }; + + spdif1: spdif@30090000 { + compatible = "fsl,imx35-spdif"; + reg = <0x30090000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, /* core */ + <&clk IMX8MM_CLK_24M>, /* rxtx0 */ + <&clk IMX8MM_CLK_SPDIF1>, /* rxtx1 */ + <&clk IMX8MM_CLK_DUMMY>, /* rxtx2 */ + <&clk IMX8MM_CLK_DUMMY>, /* rxtx3 */ + <&clk IMX8MM_CLK_DUMMY>, /* rxtx4 */ + <&clk IMX8MM_CLK_AUDIO_AHB>, /* rxtx5 */ + <&clk IMX8MM_CLK_DUMMY>, /* rxtx6 */ + <&clk IMX8MM_CLK_DUMMY>, /* rxtx7 */ + <&clk IMX8MM_CLK_DUMMY>; /* spba */ + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7", "spba"; + dmas = <&sdma2 28 18 0>, <&sdma2 29 18 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; }; gpio1: gpio@30200000 { @@ -670,80 +679,88 @@ ranges = <0x30800000 0x30800000 0x400000>, <0x8000000 0x8000000 0x10000000>; - ecspi1: spi@30820000 { - compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; + spba1: spba-bus@30800000 { + compatible = "fsl,spba-bus", "simple-bus"; #address-cells = <1>; - #size-cells = <0>; - reg = <0x30820000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_ECSPI1_ROOT>, - <&clk IMX8MM_CLK_ECSPI1_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + #size-cells = <1>; + reg = <0x30800000 0x100000>; + ranges; - ecspi2: spi@30830000 { - compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x30830000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_ECSPI2_ROOT>, - <&clk IMX8MM_CLK_ECSPI2_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi1: spi@30820000 { + compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30820000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_ECSPI1_ROOT>, + <&clk IMX8MM_CLK_ECSPI1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - ecspi3: spi@30840000 { - compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x30840000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_ECSPI3_ROOT>, - <&clk IMX8MM_CLK_ECSPI3_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi2: spi@30830000 { + compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30830000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_ECSPI2_ROOT>, + <&clk IMX8MM_CLK_ECSPI2_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart1: serial@30860000 { - compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; - reg = <0x30860000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_UART1_ROOT>, - <&clk IMX8MM_CLK_UART1_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi3: spi@30840000 { + compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30840000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_ECSPI3_ROOT>, + <&clk IMX8MM_CLK_ECSPI3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart3: serial@30880000 { - compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; - reg = <0x30880000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_UART3_ROOT>, - <&clk IMX8MM_CLK_UART3_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + uart1: serial@30860000 { + compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; + reg = <0x30860000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_UART1_ROOT>, + <&clk IMX8MM_CLK_UART1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart2: serial@30890000 { - compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; - reg = <0x30890000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MM_CLK_UART2_ROOT>, - <&clk IMX8MM_CLK_UART2_ROOT>; - clock-names = "ipg", "per"; - status = "disabled"; + uart3: serial@30880000 { + compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; + reg = <0x30880000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_UART3_ROOT>, + <&clk IMX8MM_CLK_UART3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart2: serial@30890000 { + compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; + reg = <0x30890000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_UART2_ROOT>, + <&clk IMX8MM_CLK_UART2_ROOT>; + clock-names = "ipg", "per"; + status = "disabled"; + }; }; crypto: crypto@30900000 { diff --git a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi index c35eeaff958f..54eaf3d6055b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi @@ -120,6 +120,9 @@ interrupt-parent = <&gpio1>; interrupts = <3 IRQ_TYPE_LEVEL_LOW>; rohm,reset-snvs-powered; + #clock-cells = <0>; + clocks = <&osc_32k 0>; + clock-output-names = "clk-32k-out"; regulators { buck1_reg: BUCK1 { diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi index a0dddba2e561..85e65f8719ea 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi @@ -193,6 +193,7 @@ srp-disable; adp-disable; usb-role-switch; + disable-over-current; samsung,picophy-pre-emp-curr-control = <3>; samsung,picophy-dc-vol-level-adjust = <7>; status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index 4dac4da38f4c..d4231e061403 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -245,6 +245,7 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x0 0x0 0x3e000000>; + dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>; nvmem-cells = <&imx8mn_uid>; nvmem-cell-names = "soc_unique_id"; @@ -255,7 +256,7 @@ #size-cells = <1>; ranges; - spba: spba-bus@30000000 { + spba2: spba-bus@30000000 { compatible = "fsl,spba-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -681,80 +682,88 @@ #size-cells = <1>; ranges; - ecspi1: spi@30820000 { - compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + spba1: spba-bus@30800000 { + compatible = "fsl,spba-bus", "simple-bus"; #address-cells = <1>; - #size-cells = <0>; - reg = <0x30820000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_ECSPI1_ROOT>, - <&clk IMX8MN_CLK_ECSPI1_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + #size-cells = <1>; + reg = <0x30800000 0x100000>; + ranges; - ecspi2: spi@30830000 { - compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x30830000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_ECSPI2_ROOT>, - <&clk IMX8MN_CLK_ECSPI2_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi1: spi@30820000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30820000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI1_ROOT>, + <&clk IMX8MN_CLK_ECSPI1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - ecspi3: spi@30840000 { - compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x30840000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_ECSPI3_ROOT>, - <&clk IMX8MN_CLK_ECSPI3_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi2: spi@30830000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30830000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI2_ROOT>, + <&clk IMX8MN_CLK_ECSPI2_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart1: serial@30860000 { - compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; - reg = <0x30860000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_UART1_ROOT>, - <&clk IMX8MN_CLK_UART1_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + ecspi3: spi@30840000 { + compatible = "fsl,imx8mn-ecspi", "fsl,imx51-ecspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30840000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_ECSPI3_ROOT>, + <&clk IMX8MN_CLK_ECSPI3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart3: serial@30880000 { - compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; - reg = <0x30880000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_UART3_ROOT>, - <&clk IMX8MN_CLK_UART3_ROOT>; - clock-names = "ipg", "per"; - dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>; - dma-names = "rx", "tx"; - status = "disabled"; - }; + uart1: serial@30860000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30860000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART1_ROOT>, + <&clk IMX8MN_CLK_UART1_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; - uart2: serial@30890000 { - compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; - reg = <0x30890000 0x10000>; - interrupts = ; - clocks = <&clk IMX8MN_CLK_UART2_ROOT>, - <&clk IMX8MN_CLK_UART2_ROOT>; - clock-names = "ipg", "per"; - status = "disabled"; + uart3: serial@30880000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30880000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART3_ROOT>, + <&clk IMX8MN_CLK_UART3_ROOT>; + clock-names = "ipg", "per"; + dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart2: serial@30890000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30890000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MN_CLK_UART2_ROOT>, + <&clk IMX8MN_CLK_UART2_ROOT>; + clock-names = "ipg", "per"; + status = "disabled"; + }; }; crypto: crypto@30900000 { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index 2c28e589677e..7b99fad6e4d6 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -81,6 +81,26 @@ status = "disabled";/* can2 pin conflict with pdm */ }; +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + eee-broken-1000t; + }; + }; +}; + &fec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec>; @@ -104,6 +124,92 @@ }; }; +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + regulators { + BUCK1 { + regulator-name = "BUCK1"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1000000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + }; + + BUCK2 { + regulator-name = "BUCK2"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1025000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + BUCK4 { + regulator-name = "BUCK4"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3600000>; + regulator-boot-on; + regulator-always-on; + }; + + BUCK5 { + regulator-name = "BUCK5"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; + regulator-boot-on; + regulator-always-on; + }; + + BUCK6 { + regulator-name = "BUCK6"; + regulator-min-microvolt = <1045000>; + regulator-max-microvolt = <1155000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1890000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO5 { + regulator-name = "LDO5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + &i2c3 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -177,6 +283,26 @@ }; &iomuxc { + pinctrl_eqos: eqosgrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x3 + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x3 + 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 + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x19 + >; + }; + pinctrl_fec: fecgrp { fsl,pins = < MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x3 @@ -229,6 +355,13 @@ >; }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + >; + }; + pinctrl_i2c3: i2c3grp { fsl,pins = < MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c3 @@ -236,6 +369,12 @@ >; }; + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x000001c0 + >; + }; + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { fsl,pins = < MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x41 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi index f3965ec5b31d..aa78e0d8c72b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi @@ -65,6 +65,20 @@ }; }; +&flexspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexspi0>; + status = "okay"; + + som_flash: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <80000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; +}; + &i2c1 { clock-frequency = <400000>; pinctrl-names = "default", "gpio"; @@ -217,6 +231,17 @@ >; }; + pinctrl_flexspi0: flexspi0grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK 0x1c2 + MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B 0x82 + MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00 0x82 + MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01 0x82 + MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02 0x82 + MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03 0x82 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3 diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index c2d51a46cb3c..9f7c7f587d38 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -37,6 +37,7 @@ serial1 = &uart2; serial2 = &uart3; serial3 = &uart4; + spi0 = &flexspi; }; cpus { @@ -407,7 +408,6 @@ <&clk IMX8MP_CLK_GIC>, <&clk IMX8MP_CLK_AUDIO_AHB>, <&clk IMX8MP_CLK_AUDIO_AXI_SRC>, - <&clk IMX8MP_CLK_IPG_AUDIO_ROOT>, <&clk IMX8MP_AUDIO_PLL1>, <&clk IMX8MP_AUDIO_PLL2>; assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, @@ -423,7 +423,6 @@ <500000000>, <400000000>, <800000000>, - <400000000>, <393216000>, <361267200>; }; @@ -761,6 +760,21 @@ status = "disabled"; }; + flexspi: spi@30bb0000 { + compatible = "nxp,imx8mp-fspi"; + reg = <0x30bb0000 0x10000>, <0x8000000 0x10000000>; + reg-names = "fspi_base", "fspi_mmap"; + interrupts = ; + clocks = <&clk IMX8MP_CLK_QSPI_ROOT>, + <&clk IMX8MP_CLK_QSPI_ROOT>; + clock-names = "fspi", "fspi_en"; + assigned-clock-rates = <80000000>; + assigned-clocks = <&clk IMX8MP_CLK_QSPI>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + sdma1: dma-controller@30bd0000 { compatible = "fsl,imx8mp-sdma", "fsl,imx8mq-sdma"; reg = <0x30bd0000 0x10000>; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts index 85b045253a0e..4d2035e3dd7c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts @@ -318,6 +318,7 @@ <&clk IMX8MQ_CLK_PCIE1_PHY>, <&pcie0_refclk>; clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus"; + vph-supply = <&vgen5_reg>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts b/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts index 81d269296610..f70fb32b96b0 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts @@ -34,6 +34,30 @@ }; }; + hdmi-connector { + compatible = "hdmi-connector"; + ddc-i2c-bus = <&ddc_i2c_bus>; + label = "hdmi"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <<8912_out>; + }; + }; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usbotg_vbus>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + reg_vref_0v9: regulator-vref-0v9 { compatible = "regulator-fixed"; regulator-name = "vref-0v9"; @@ -70,6 +94,9 @@ }; }; +&dphy { + status = "okay"; +}; &fec1 { pinctrl-names = "default"; @@ -91,6 +118,15 @@ }; }; +/* Release reset of the USB Host HUB */ +&gpio1 { + usb-host-reset-hog { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + &i2c1 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -174,6 +210,98 @@ }; }; +&i2c4 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + pca9546: i2cmux@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c4@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + + hdmi-bridge@48 { + compatible = "lontium,lt8912b"; + reg = <0x48> ; + reset-gpios = <&max7323 0 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hdmi_out_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&mipi_dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + lt8912_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + }; + + ddc_i2c_bus: i2c4@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; + + i2c4@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + + max7323: gpio-expander@68 { + compatible = "maxim,max7323"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_max7323>; + gpio-controller; + reg = <0x68>; + #gpio-cells = <2>; + }; + }; + }; +}; + +&lcdif { + status = "okay"; +}; + +&mipi_dsi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ports { + port@1 { + reg = <1>; + + mipi_dsi_out: endpoint { + remote-endpoint = <&hdmi_out_in>; + }; + }; + }; +}; + &uart1 { /* console */ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1>; @@ -190,6 +318,29 @@ status = "okay"; }; +&usb_dwc3_0 { + dr_mode = "otg"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb3_0>; + status = "okay"; +}; + +&usb3_phy0 { + vbus-supply = <®_usb_otg_vbus>; + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +&usb3_phy1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb3_1>; + status = "okay"; +}; + &usdhc1 { assigned-clocks = <&clk IMX8MQ_CLK_USDHC1>; assigned-clock-rates = <400000000>; @@ -321,6 +472,19 @@ >; }; + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MQ_IOMUXC_I2C4_SCL_I2C4_SCL 0x4000007f + MX8MQ_IOMUXC_I2C4_SDA_I2C4_SDA 0x4000007f + >; + }; + + pinctrl_max7323: max7323grp { + fsl,pins = < + MX8MQ_IOMUXC_NAND_RE_B_GPIO3_IO15 0x19 + >; + }; + pinctrl_reg_arm_dram: reg-arm-dramgrp { fsl,pins = < MX8MQ_IOMUXC_SAI5_RXD3_GPIO3_IO24 0x16 @@ -339,6 +503,12 @@ >; }; + pinctrl_reg_usbotg_vbus: reg-usbotg-vbusgrp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x16 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x45 @@ -353,6 +523,18 @@ >; }; + pinctrl_usb3_0: usb3-0grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x16 + >; + }; + + pinctrl_usb3_1: usb3-1grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x16 + >; + }; + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK 0x83 diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index 17c449e12c2e..91df9c5350ae 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -1383,6 +1383,14 @@ <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>, <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>; reset-names = "pciephy", "apps", "turnoff"; + assigned-clocks = <&clk IMX8MQ_CLK_PCIE1_CTRL>, + <&clk IMX8MQ_CLK_PCIE1_PHY>, + <&clk IMX8MQ_CLK_PCIE1_AUX>; + assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_250M>, + <&clk IMX8MQ_SYS2_PLL_100M>, + <&clk IMX8MQ_SYS1_PLL_80M>; + assigned-clock-rates = <250000000>, <100000000>, + <10000000>; status = "disabled"; }; @@ -1413,6 +1421,14 @@ <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_EN>, <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF>; reset-names = "pciephy", "apps", "turnoff"; + assigned-clocks = <&clk IMX8MQ_CLK_PCIE2_CTRL>, + <&clk IMX8MQ_CLK_PCIE2_PHY>, + <&clk IMX8MQ_CLK_PCIE2_AUX>; + assigned-clock-parents = <&clk IMX8MQ_SYS2_PLL_250M>, + <&clk IMX8MQ_SYS2_PLL_100M>, + <&clk IMX8MQ_SYS1_PLL_80M>; + assigned-clock-rates = <250000000>, <100000000>, + <10000000>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi index d607f2f6698c..79a55a0fa2f1 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660-coresight.dtsi @@ -3,7 +3,7 @@ /* * dtsi for Hisilicon Hi3660 Coresight * - * Copyright (C) 2016-2018 Hisilicon Ltd. + * Copyright (C) 2016-2018 HiSilicon Ltd. * * Author: Wanglai Shi * diff --git a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts index 963300eede17..f68580dc87d8 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts +++ b/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts @@ -2,7 +2,7 @@ /* * dts file for Hisilicon HiKey960 Development Board * - * Copyright (C) 2016, Hisilicon Ltd. + * Copyright (C) 2016, HiSilicon Ltd. * */ diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi index cab89dc6f596..f1ec87c05842 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi @@ -2,7 +2,7 @@ /* * dts file for Hisilicon Hi3660 SoC * - * Copyright (C) 2016, Hisilicon Ltd. + * Copyright (C) 2016, HiSilicon Ltd. */ #include diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts index 7f9f9886c349..d8abf442ee7e 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts +++ b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts @@ -2,7 +2,7 @@ /* * dts file for Hisilicon HiKey970 Development Board * - * Copyright (C) 2016, Hisilicon Ltd. + * Copyright (C) 2016, HiSilicon Ltd. * Copyright (C) 2018, Linaro Ltd. * */ diff --git a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi index 8830795c8efc..20698cfd0637 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi @@ -2,7 +2,7 @@ /* * dts file for Hisilicon Hi3670 SoC * - * Copyright (C) 2016, Hisilicon Ltd. + * Copyright (C) 2016, HiSilicon Ltd. * Copyright (C) 2018, Linaro Ltd. */ diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi index 7b3010f448c5..3f387f4cf5e0 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220-coresight.dtsi @@ -2,7 +2,7 @@ /* * dtsi file for Hisilicon Hi6220 coresight * - * Copyright (C) 2017 Hisilicon Ltd. + * Copyright (C) 2017 HiSilicon Ltd. * * Author: Pengcheng Li * Leo Yan diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts index 91d08673c02e..3df2afb2f637 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts +++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts @@ -2,7 +2,7 @@ /* * dts file for Hisilicon HiKey Development Board * - * Copyright (C) 2015, Hisilicon Ltd. + * Copyright (C) 2015, HiSilicon Ltd. * */ diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index d426c6c8722b..dde9371dc545 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -2,7 +2,7 @@ /* * dts file for Hisilicon Hi6220 SoC * - * Copyright (C) 2015, Hisilicon Ltd. + * Copyright (C) 2015, HiSilicon Ltd. */ #include diff --git a/arch/arm64/boot/dts/hisilicon/hip05-d02.dts b/arch/arm64/boot/dts/hisilicon/hip05-d02.dts index 369b69b17b91..40f3e00ac832 100644 --- a/arch/arm64/boot/dts/hisilicon/hip05-d02.dts +++ b/arch/arm64/boot/dts/hisilicon/hip05-d02.dts @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D02 Development Board * - * Copyright (C) 2014,2015 Hisilicon Ltd. + * Copyright (C) 2014,2015 HiSilicon Ltd. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi index 4aed8d440b3a..7b2abd10d3d6 100644 --- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D02 Development Board * - * Copyright (C) 2014,2015 Hisilicon Ltd. + * Copyright (C) 2014,2015 HiSilicon Ltd. */ #include diff --git a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts index 9f4a930e734d..35af5d3821e8 100644 --- a/arch/arm64/boot/dts/hisilicon/hip06-d03.dts +++ b/arch/arm64/boot/dts/hisilicon/hip06-d03.dts @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D03 Development Board * - * Copyright (C) 2016 Hisilicon Ltd. + * Copyright (C) 2016 HiSilicon Ltd. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi index 7deca5f763d5..70d7732dd348 100644 --- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D03 Development Board * - * Copyright (C) 2016 Hisilicon Ltd. + * Copyright (C) 2016 HiSilicon Ltd. */ #include diff --git a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts index 81a2312c8a26..c3df67845f03 100644 --- a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts +++ b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D05 Development Board * - * Copyright (C) 2016 Hisilicon Ltd. + * Copyright (C) 2016 HiSilicon Ltd. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi index 2172d8071181..6baf6a686450 100644 --- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi @@ -2,7 +2,7 @@ /** * dts file for Hisilicon D05 Development Board * - * Copyright (C) 2016 Hisilicon Ltd. + * Copyright (C) 2016 HiSilicon Ltd. */ #include diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts index 53e817c5f6f3..ce2bcddf396f 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts @@ -109,10 +109,8 @@ }; firmware { - turris-mox-rwtm { - compatible = "cznic,turris-mox-rwtm"; - mboxes = <&rwtm 0>; - status = "okay"; + armada-3700-rwtm { + compatible = "marvell,armada-3700-rwtm-firmware", "cznic,turris-mox-rwtm"; }; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi index 6ffbb099fcac..5db81a416cd6 100644 --- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi @@ -504,4 +504,12 @@ }; }; }; + + firmware { + armada-3700-rwtm { + compatible = "marvell,armada-3700-rwtm-firmware"; + mboxes = <&rwtm 0>; + status = "okay"; + }; + }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-ap807.dtsi b/arch/arm64/boot/dts/marvell/armada-ap807.dtsi index d9bbbfa4b4eb..4a23f65d475f 100644 --- a/arch/arm64/boot/dts/marvell/armada-ap807.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-ap807.dtsi @@ -29,6 +29,7 @@ }; &ap_sdhci0 { - compatible = "marvell,armada-ap807-sdhci"; + compatible = "marvell,armada-ap807-sdhci", + "marvell,armada-ap806-sdhci"; /* Backward compatibility */ }; diff --git a/arch/arm64/boot/dts/marvell/cn9130-db.dts b/arch/arm64/boot/dts/marvell/cn9130-db.dts index 2c2af001619b..9758609541c7 100644 --- a/arch/arm64/boot/dts/marvell/cn9130-db.dts +++ b/arch/arm64/boot/dts/marvell/cn9130-db.dts @@ -260,7 +260,7 @@ }; partition@200000 { label = "Linux"; - reg = <0x200000 0xd00000>; + reg = <0x200000 0xe00000>; }; partition@1000000 { label = "Filesystem"; diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index a1c50adc98fa..4f68ebed2e31 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -13,8 +13,16 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana-rev7.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-burnet.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-damu.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-fennel-sku1.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-fennel-sku6.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-fennel14.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-juniper-sku16.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-kappa.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-kenzo.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-willow-sku0.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-willow-sku1.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kakadu.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku16.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku272.dtb diff --git a/arch/arm64/boot/dts/mediatek/mt8167.dtsi b/arch/arm64/boot/dts/mediatek/mt8167.dtsi index 1c5639ead622..9029051624a6 100644 --- a/arch/arm64/boot/dts/mediatek/mt8167.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8167.dtsi @@ -7,6 +7,7 @@ #include #include +#include #include "mt8167-pinfunc.h" @@ -34,6 +35,73 @@ #clock-cells = <1>; }; + scpsys: syscon@10006000 { + compatible = "syscon", "simple-mfd"; + reg = <0 0x10006000 0 0x1000>; + #power-domain-cells = <1>; + + spm: power-controller { + compatible = "mediatek,mt8167-power-controller"; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + /* power domains of the SoC */ + power-domain@MT8167_POWER_DOMAIN_MM { + reg = ; + clocks = <&topckgen CLK_TOP_SMI_MM>; + clock-names = "mm"; + #power-domain-cells = <0>; + mediatek,infracfg = <&infracfg>; + }; + + power-domain@MT8167_POWER_DOMAIN_VDEC { + reg = ; + clocks = <&topckgen CLK_TOP_SMI_MM>, + <&topckgen CLK_TOP_RG_VDEC>; + clock-names = "mm", "vdec"; + #power-domain-cells = <0>; + }; + + power-domain@MT8167_POWER_DOMAIN_ISP { + reg = ; + clocks = <&topckgen CLK_TOP_SMI_MM>; + clock-names = "mm"; + #power-domain-cells = <0>; + }; + + power-domain@MT8167_POWER_DOMAIN_MFG_ASYNC { + reg = ; + clocks = <&topckgen CLK_TOP_RG_AXI_MFG>, + <&topckgen CLK_TOP_RG_SLOW_MFG>; + clock-names = "axi_mfg", "mfg"; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + mediatek,infracfg = <&infracfg>; + + power-domain@MT8167_POWER_DOMAIN_MFG_2D { + reg = ; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + power-domain@MT8167_POWER_DOMAIN_MFG { + reg = ; + #power-domain-cells = <0>; + mediatek,infracfg = <&infracfg>; + }; + }; + }; + + power-domain@MT8167_POWER_DOMAIN_CONN { + reg = ; + #power-domain-cells = <0>; + mediatek,infracfg = <&infracfg>; + }; + }; + }; + imgsys: syscon@15000000 { compatible = "mediatek,mt8167-imgsys", "syscon"; reg = <0 0x15000000 0 0x1000>; @@ -57,5 +125,58 @@ #interrupt-cells = <2>; interrupts = ; }; + + mmsys: mmsys@14000000 { + compatible = "mediatek,mt8167-mmsys", "syscon"; + reg = <0 0x14000000 0 0x1000>; + #clock-cells = <1>; + }; + + smi_common: smi@14017000 { + compatible = "mediatek,mt8167-smi-common"; + reg = <0 0x14017000 0 0x1000>; + clocks = <&mmsys CLK_MM_SMI_COMMON>, + <&mmsys CLK_MM_SMI_COMMON>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8167_POWER_DOMAIN_MM>; + }; + + larb0: larb@14016000 { + compatible = "mediatek,mt8167-smi-larb"; + reg = <0 0x14016000 0 0x1000>; + mediatek,smi = <&smi_common>; + clocks = <&mmsys CLK_MM_SMI_LARB0>, + <&mmsys CLK_MM_SMI_LARB0>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8167_POWER_DOMAIN_MM>; + }; + + larb1: larb@15001000 { + compatible = "mediatek,mt8167-smi-larb"; + reg = <0 0x15001000 0 0x1000>; + mediatek,smi = <&smi_common>; + clocks = <&imgsys CLK_IMG_LARB1_SMI>, + <&imgsys CLK_IMG_LARB1_SMI>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8167_POWER_DOMAIN_ISP>; + }; + + larb2: larb@16010000 { + compatible = "mediatek,mt8167-smi-larb"; + reg = <0 0x16010000 0 0x1000>; + mediatek,smi = <&smi_common>; + clocks = <&vdecsys CLK_VDEC_CKEN>, + <&vdecsys CLK_VDEC_LARB1_CKEN>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8167_POWER_DOMAIN_VDEC>; + }; + + iommu: m4u@10203000 { + compatible = "mediatek,mt8167-m4u"; + reg = <0 0x10203000 0 0x1000>; + mediatek,larbs = <&larb0 &larb1 &larb2>; + interrupts = ; + #iommu-cells = <1>; + }; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index 003a5653c505..22f271b1f5b0 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -1459,14 +1459,11 @@ clock-names = "apb", "smi"; }; - vcodec_enc: vcodec@18002000 { + vcodec_enc_avc: vcodec@18002000 { compatible = "mediatek,mt8173-vcodec-enc"; - reg = <0 0x18002000 0 0x1000>, /* VENC_SYS */ - <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */ - interrupts = , - ; - mediatek,larb = <&larb3>, - <&larb5>; + reg = <0 0x18002000 0 0x1000>; /* VENC_SYS */ + interrupts = ; + mediatek,larb = <&larb3>; iommus = <&iommu M4U_PORT_VENC_RCPU>, <&iommu M4U_PORT_VENC_REC>, <&iommu M4U_PORT_VENC_BSDMA>, @@ -1477,29 +1474,12 @@ <&iommu M4U_PORT_VENC_REF_LUMA>, <&iommu M4U_PORT_VENC_REF_CHROMA>, <&iommu M4U_PORT_VENC_NBM_RDMA>, - <&iommu M4U_PORT_VENC_NBM_WDMA>, - <&iommu M4U_PORT_VENC_RCPU_SET2>, - <&iommu M4U_PORT_VENC_REC_FRM_SET2>, - <&iommu M4U_PORT_VENC_BSDMA_SET2>, - <&iommu M4U_PORT_VENC_SV_COMA_SET2>, - <&iommu M4U_PORT_VENC_RD_COMA_SET2>, - <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>, - <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>, - <&iommu M4U_PORT_VENC_REF_LUMA_SET2>, - <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>; + <&iommu M4U_PORT_VENC_NBM_WDMA>; mediatek,vpu = <&vpu>; - clocks = <&topckgen CLK_TOP_VENCPLL_D2>, - <&topckgen CLK_TOP_VENC_SEL>, - <&topckgen CLK_TOP_UNIVPLL1_D2>, - <&topckgen CLK_TOP_VENC_LT_SEL>; - clock-names = "venc_sel_src", - "venc_sel", - "venc_lt_sel_src", - "venc_lt_sel"; - assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>, - <&topckgen CLK_TOP_VENC_LT_SEL>; - assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL>, - <&topckgen CLK_TOP_VCODECPLL_370P5>; + clocks = <&topckgen CLK_TOP_VENC_SEL>; + clock-names = "venc_sel"; + assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL>; }; jpegdec: jpegdec@18004000 { @@ -1531,5 +1511,27 @@ <&vencltsys CLK_VENCLT_CKE0>; clock-names = "apb", "smi"; }; + + vcodec_enc_vp8: vcodec@19002000 { + compatible = "mediatek,mt8173-vcodec-enc-vp8"; + reg = <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */ + interrupts = ; + iommus = <&iommu M4U_PORT_VENC_RCPU_SET2>, + <&iommu M4U_PORT_VENC_REC_FRM_SET2>, + <&iommu M4U_PORT_VENC_BSDMA_SET2>, + <&iommu M4U_PORT_VENC_SV_COMA_SET2>, + <&iommu M4U_PORT_VENC_RD_COMA_SET2>, + <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>, + <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>, + <&iommu M4U_PORT_VENC_REF_LUMA_SET2>, + <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>; + mediatek,larb = <&larb5>; + mediatek,vpu = <&vpu>; + clocks = <&topckgen CLK_TOP_VENC_LT_SEL>; + clock-names = "venc_lt_sel"; + assigned-clocks = <&topckgen CLK_TOP_VENC_LT_SEL>; + assigned-clock-parents = + <&topckgen CLK_TOP_VCODECPLL_370P5>; + }; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts index edff1e03e6fe..7bc0a6a7fadf 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts @@ -42,6 +42,11 @@ status = "okay"; }; +&gpu { + mali-supply = <&mt6358_vgpu_reg>; + sram-supply = <&mt6358_vsram_gpu_reg>; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c_pins_0>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts new file mode 100644 index 000000000000..a8d6f32ade8d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +/ { + model = "Google burnet board"; + compatible = "google,burnet", "mediatek,mt8183"; +}; + +&mt6358codec { + mediatek,dmic-mode = <1>; /* one-wire */ +}; + +&i2c0 { + touchscreen@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; + + post-power-on-delay-ms = <200>; + hid-descr-addr = <0x0020>; + }; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts new file mode 100644 index 000000000000..ef6257c9a2d2 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-fennel.dtsi" + +/ { + model = "Google fennel sku1 board"; + compatible = "google,fennel-sku1", "google,fennel", "mediatek,mt8183"; + + pwmleds { + compatible = "pwm-leds"; + keyboard_backlight: keyboard-backlight { + label = "cros_ec::kbd_backlight"; + pwms = <&cros_ec_pwm 0>; + max-brightness = <1023>; + }; + }; +}; + +&cros_ec_pwm { + status = "okay"; +}; + +&touchscreen { + status = "okay"; + + compatible = "hid-over-i2c"; + reg = <0x10>; + interrupt-parent = <&pio>; + interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_FENNEL"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts new file mode 100644 index 000000000000..899c2e42385c --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-fennel.dtsi" + +/ { + model = "Google fennel sku6 board"; + compatible = "google,fennel-sku6", "google,fennel", "mediatek,mt8183"; +}; + +&touchscreen { + status = "okay"; + + compatible = "hid-over-i2c"; + reg = <0x10>; + interrupt-parent = <&pio>; + interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; +}; + + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_FENNEL"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi new file mode 100644 index 000000000000..bbe6c338f465 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +&mt6358codec { + mediatek,dmic-mode = <1>; /* one-wire */ +}; + +&i2c2 { + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel14.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel14.dts new file mode 100644 index 000000000000..e8c41f6b4b0d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel14.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-fennel.dtsi" + +/ { + model = "Google fennel14 sku0 board"; + compatible = "google,fennel-sku0", "google,fennel", "mediatek,mt8183"; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_FENNEL14"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kappa.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kappa.dts new file mode 100644 index 000000000000..b3f46c16e5d7 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kappa.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +/ { + model = "Google kappa board"; + compatible = "google,kappa", "mediatek,mt8183"; +}; + +&mt6358codec { + mediatek,dmic-mode = <1>; /* one-wire */ +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kenzo.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kenzo.dts new file mode 100644 index 000000000000..6f1aa692753a --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-kenzo.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-juniper.dtsi" + +/ { + model = "Google kenzo sku17 board"; + compatible = "google,juniper-sku17", "google,juniper", "mediatek,mt8183"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku0.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku0.dts new file mode 100644 index 000000000000..281265f082db --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku0.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-willow.dtsi" + +/ { + model = "Google willow board sku0"; + compatible = "google,willow-sku0", "google,willow", "mediatek,mt8183"; +}; + diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku1.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku1.dts new file mode 100644 index 000000000000..22e56bdc1ee3 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow-sku1.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-willow.dtsi" + +/ { + model = "Google willow board sku1"; + compatible = "google,willow-sku1", "google,willow", "mediatek,mt8183"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow.dtsi new file mode 100644 index 000000000000..76d33540166f --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-willow.dtsi @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" + +&i2c2 { + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_JUNIPER"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi index 4049dff8464b..d8826c82bcda 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi @@ -92,6 +92,14 @@ }; }; +&cros_ec { + cros_ec_pwm: ec-pwm { + compatible = "google,cros-ec-pwm"; + #pwm-cells = <1>; + status = "disabled"; + }; +}; + &dsi0 { status = "okay"; /delete-node/panel@0; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi index b442e38a3156..28966a65391b 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi @@ -88,11 +88,13 @@ pinctrl-0 = <&i2c2_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcamio_reg>; eeprom@58 { compatible = "atmel,24c32"; reg = <0x58>; pagesize = <32>; + vcc-supply = <&mt6358_vcama2_reg>; }; }; @@ -101,11 +103,13 @@ pinctrl-0 = <&i2c4_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcn18_reg>; eeprom@54 { compatible = "atmel,24c32"; reg = <0x54>; pagesize = <32>; + vcc-supply = <&mt6358_vcn18_reg>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi index 2f5234a16ead..3aa79403c0c2 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi @@ -62,11 +62,13 @@ pinctrl-0 = <&i2c2_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcamio_reg>; eeprom@58 { compatible = "atmel,24c64"; reg = <0x58>; pagesize = <32>; + vcc-supply = <&mt6358_vcamio_reg>; }; }; @@ -75,11 +77,13 @@ pinctrl-0 = <&i2c4_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcn18_reg>; eeprom@54 { compatible = "atmel,24c64"; reg = <0x54>; pagesize = <32>; + vcc-supply = <&mt6358_vcn18_reg>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi index fbc471ccf805..30c183c96a54 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi @@ -71,11 +71,13 @@ pinctrl-0 = <&i2c2_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcamio_reg>; eeprom@58 { compatible = "atmel,24c32"; reg = <0x58>; pagesize = <32>; + vcc-supply = <&mt6358_vcama2_reg>; }; }; @@ -84,11 +86,13 @@ pinctrl-0 = <&i2c4_pins>; status = "okay"; clock-frequency = <400000>; + vbus-supply = <&mt6358_vcn18_reg>; eeprom@54 { compatible = "atmel,24c32"; reg = <0x54>; pagesize = <32>; + vcc-supply = <&mt6358_vcn18_reg>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index ff56bcfa3370..ae549d55a94f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -279,6 +279,11 @@ }; }; +&gpu { + mali-supply = <&mt6358_vgpu_reg>; + sram-supply = <&mt6358_vsram_gpu_reg>; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; @@ -816,6 +821,10 @@ compatible = "google,extcon-usbc-cros-ec"; google,usb-port-id = <0>; }; + + cbas { + compatible = "google,cros-cbas"; + }; }; }; @@ -847,6 +856,20 @@ status = "okay"; }; +&thermal_zones { + tboard1 { + polling-delay = <1000>; /* milliseconds */ + polling-delay-passive = <0>; /* milliseconds */ + thermal-sensors = <&tboard_thermistor1>; + }; + + tboard2 { + polling-delay = <1000>; /* milliseconds */ + polling-delay-passive = <0>; /* milliseconds */ + thermal-sensors = <&tboard_thermistor2>; + }; +}; + &u3phy { status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts index 0aff5eb52e88..ee912825cfc6 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts @@ -68,6 +68,11 @@ status = "okay"; }; +&gpu { + mali-supply = <&mt6358_vgpu_reg>; + sram-supply = <&mt6358_vsram_gpu_reg>; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c_pins_0>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi index c5e822b6b77a..f90df6439c08 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi @@ -197,6 +197,91 @@ }; }; + gpu_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <625000>, <850000>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + opp-microvolt = <631250>, <850000>; + }; + + opp-340000000 { + opp-hz = /bits/ 64 <340000000>; + opp-microvolt = <637500>, <850000>; + }; + + opp-360000000 { + opp-hz = /bits/ 64 <360000000>; + opp-microvolt = <643750>, <850000>; + }; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; + opp-microvolt = <650000>, <850000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <656250>, <850000>; + }; + + opp-420000000 { + opp-hz = /bits/ 64 <420000000>; + opp-microvolt = <662500>, <850000>; + }; + + opp-460000000 { + opp-hz = /bits/ 64 <460000000>; + opp-microvolt = <675000>, <850000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <687500>, <850000>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + opp-microvolt = <700000>, <850000>; + }; + + opp-580000000 { + opp-hz = /bits/ 64 <580000000>; + opp-microvolt = <712500>, <850000>; + }; + + opp-620000000 { + opp-hz = /bits/ 64 <620000000>; + opp-microvolt = <725000>, <850000>; + }; + + opp-653000000 { + opp-hz = /bits/ 64 <653000000>; + opp-microvolt = <743750>, <850000>; + }; + + opp-698000000 { + opp-hz = /bits/ 64 <698000000>; + opp-microvolt = <768750>, <868750>; + }; + + opp-743000000 { + opp-hz = /bits/ 64 <743000000>; + opp-microvolt = <793750>, <893750>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <825000>, <925000>; + }; + }; + pmu-a53 { compatible = "arm,cortex-a53-pmu"; interrupt-parent = <&gic>; @@ -673,7 +758,7 @@ nvmem-cell-names = "calibration-data"; }; - thermal-zones { + thermal_zones: thermal-zones { cpu_thermal: cpu_thermal { polling-delay-passive = <100>; polling-delay = <500>; @@ -1118,6 +1203,26 @@ #clock-cells = <1>; }; + gpu: gpu@13040000 { + compatible = "mediatek,mt8183-mali", "arm,mali-bifrost"; + reg = <0 0x13040000 0 0x4000>; + interrupts = + , + , + ; + interrupt-names = "job", "mmu", "gpu"; + + clocks = <&topckgen CLK_TOP_MFGPLL_CK>; + + power-domains = + <&spm MT8183_POWER_DOMAIN_MFG_CORE0>, + <&spm MT8183_POWER_DOMAIN_MFG_CORE1>, + <&spm MT8183_POWER_DOMAIN_MFG_2D>; + power-domain-names = "core0", "core1", "core2"; + + operating-points-v2 = <&gpu_opp_table>; + }; + mmsys: syscon@14000000 { compatible = "mediatek,mt8183-mmsys", "syscon"; reg = <0 0x14000000 0 0x1000>; @@ -1263,13 +1368,14 @@ }; smi_common: smi@14019000 { - compatible = "mediatek,mt8183-smi-common", "syscon"; + compatible = "mediatek,mt8183-smi-common"; reg = <0 0x14019000 0 0x1000>; clocks = <&mmsys CLK_MM_SMI_COMMON>, <&mmsys CLK_MM_SMI_COMMON>, <&mmsys CLK_MM_GALS_COMM0>, <&mmsys CLK_MM_GALS_COMM1>; clock-names = "apb", "smi", "gals0", "gals1"; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; }; imgsys: syscon@15020000 { diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts index 683743f81849..74c1a5df3fdb 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts @@ -817,7 +817,7 @@ }; hda@3510000 { - nvidia,model = "jetson-tx2-hda"; + nvidia,model = "NVIDIA Jetson TX2 HDA"; status = "okay"; }; @@ -1109,6 +1109,6 @@ <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>, <&dspk1_port>, <&dspk2_port>; - label = "jetson-tx2-ape"; + label = "NVIDIA Jetson TX2 APE"; }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi index 9f75bbf00cf7..d02f6bf3e2ca 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi @@ -1082,7 +1082,7 @@ }; smmu: iommu@12000000 { - compatible = "arm,mmu-500"; + compatible = "nvidia,tegra186-smmu", "nvidia,smmu-500"; reg = <0 0x12000000 0 0x800000>; interrupts = , , @@ -1152,6 +1152,8 @@ stream-match-mask = <0x7f80>; #global-interrupts = <1>; #iommu-cells = <1>; + + nvidia,memory-controller = <&mc>; }; host1x@13e00000 { diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts index d618f197a1d3..96bd01cadb18 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts @@ -554,7 +554,7 @@ }; hda@3510000 { - nvidia,model = "jetson-xavier-hda"; + nvidia,model = "NVIDIA Jetson AGX Xavier HDA"; status = "okay"; }; @@ -831,7 +831,7 @@ <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>, <&dmic3_port>; - label = "jetson-xavier-ape"; + label = "NVIDIA Jetson AGX Xavier APE"; widgets = "Microphone", "CVB-RT MIC Jack", diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi index d1d77220154f..836a7e0a4267 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi @@ -15,6 +15,577 @@ interrupt-controller@2a40000 { status = "okay"; }; + + ahub@2900800 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0x0>; + + xbar_admaif0_ep: endpoint { + remote-endpoint = <&admaif0_ep>; + }; + }; + + port@1 { + reg = <0x1>; + + xbar_admaif1_ep: endpoint { + remote-endpoint = <&admaif1_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + xbar_admaif2_ep: endpoint { + remote-endpoint = <&admaif2_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + xbar_admaif3_ep: endpoint { + remote-endpoint = <&admaif3_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + xbar_admaif4_ep: endpoint { + remote-endpoint = <&admaif4_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + xbar_admaif5_ep: endpoint { + remote-endpoint = <&admaif5_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + xbar_admaif6_ep: endpoint { + remote-endpoint = <&admaif6_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + xbar_admaif7_ep: endpoint { + remote-endpoint = <&admaif7_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + xbar_admaif8_ep: endpoint { + remote-endpoint = <&admaif8_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + xbar_admaif9_ep: endpoint { + remote-endpoint = <&admaif9_ep>; + }; + }; + + port@a { + reg = <0xa>; + + xbar_admaif10_ep: endpoint { + remote-endpoint = <&admaif10_ep>; + }; + }; + + port@b { + reg = <0xb>; + + xbar_admaif11_ep: endpoint { + remote-endpoint = <&admaif11_ep>; + }; + }; + + port@c { + reg = <0xc>; + + xbar_admaif12_ep: endpoint { + remote-endpoint = <&admaif12_ep>; + }; + }; + + port@d { + reg = <0xd>; + + xbar_admaif13_ep: endpoint { + remote-endpoint = <&admaif13_ep>; + }; + }; + + port@e { + reg = <0xe>; + + xbar_admaif14_ep: endpoint { + remote-endpoint = <&admaif14_ep>; + }; + }; + + port@f { + reg = <0xf>; + + xbar_admaif15_ep: endpoint { + remote-endpoint = <&admaif15_ep>; + }; + }; + + port@10 { + reg = <0x10>; + + xbar_admaif16_ep: endpoint { + remote-endpoint = <&admaif16_ep>; + }; + }; + + port@11 { + reg = <0x11>; + + xbar_admaif17_ep: endpoint { + remote-endpoint = <&admaif17_ep>; + }; + }; + + port@12 { + reg = <0x12>; + + xbar_admaif18_ep: endpoint { + remote-endpoint = <&admaif18_ep>; + }; + }; + + port@13 { + reg = <0x13>; + + xbar_admaif19_ep: endpoint { + remote-endpoint = <&admaif19_ep>; + }; + }; + + xbar_i2s3_port: port@16 { + reg = <0x16>; + + xbar_i2s3_ep: endpoint { + remote-endpoint = <&i2s3_cif_ep>; + }; + }; + + xbar_i2s5_port: port@18 { + reg = <0x18>; + + xbar_i2s5_ep: endpoint { + remote-endpoint = <&i2s5_cif_ep>; + }; + }; + + xbar_dmic1_port: port@1a { + reg = <0x1a>; + + xbar_dmic1_ep: endpoint { + remote-endpoint = <&dmic1_cif_ep>; + }; + }; + + xbar_dmic2_port: port@1b { + reg = <0x1b>; + + xbar_dmic2_ep: endpoint { + remote-endpoint = <&dmic2_cif_ep>; + }; + }; + + xbar_dmic4_port: port@1d { + reg = <0x1d>; + + xbar_dmic4_ep: endpoint { + remote-endpoint = <&dmic4_cif_ep>; + }; + }; + + xbar_dspk1_port: port@1e { + reg = <0x1e>; + + xbar_dspk1_ep: endpoint { + remote-endpoint = <&dspk1_cif_ep>; + }; + }; + + xbar_dspk2_port: port@1f { + reg = <0x1f>; + + xbar_dspk2_ep: endpoint { + remote-endpoint = <&dspk2_cif_ep>; + }; + }; + }; + + admaif@290f000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + admaif0_port: port@0 { + reg = <0x0>; + + admaif0_ep: endpoint { + remote-endpoint = <&xbar_admaif0_ep>; + }; + }; + + admaif1_port: port@1 { + reg = <0x1>; + + admaif1_ep: endpoint { + remote-endpoint = <&xbar_admaif1_ep>; + }; + }; + + admaif2_port: port@2 { + reg = <0x2>; + + admaif2_ep: endpoint { + remote-endpoint = <&xbar_admaif2_ep>; + }; + }; + + admaif3_port: port@3 { + reg = <0x3>; + + admaif3_ep: endpoint { + remote-endpoint = <&xbar_admaif3_ep>; + }; + }; + + admaif4_port: port@4 { + reg = <0x4>; + + admaif4_ep: endpoint { + remote-endpoint = <&xbar_admaif4_ep>; + }; + }; + + admaif5_port: port@5 { + reg = <0x5>; + + admaif5_ep: endpoint { + remote-endpoint = <&xbar_admaif5_ep>; + }; + }; + + admaif6_port: port@6 { + reg = <0x6>; + + admaif6_ep: endpoint { + remote-endpoint = <&xbar_admaif6_ep>; + }; + }; + + admaif7_port: port@7 { + reg = <0x7>; + + admaif7_ep: endpoint { + remote-endpoint = <&xbar_admaif7_ep>; + }; + }; + + admaif8_port: port@8 { + reg = <0x8>; + + admaif8_ep: endpoint { + remote-endpoint = <&xbar_admaif8_ep>; + }; + }; + + admaif9_port: port@9 { + reg = <0x9>; + + admaif9_ep: endpoint { + remote-endpoint = <&xbar_admaif9_ep>; + }; + }; + + admaif10_port: port@a { + reg = <0xa>; + + admaif10_ep: endpoint { + remote-endpoint = <&xbar_admaif10_ep>; + }; + }; + + admaif11_port: port@b { + reg = <0xb>; + + admaif11_ep: endpoint { + remote-endpoint = <&xbar_admaif11_ep>; + }; + }; + + admaif12_port: port@c { + reg = <0xc>; + + admaif12_ep: endpoint { + remote-endpoint = <&xbar_admaif12_ep>; + }; + }; + + admaif13_port: port@d { + reg = <0xd>; + + admaif13_ep: endpoint { + remote-endpoint = <&xbar_admaif13_ep>; + }; + }; + + admaif14_port: port@e { + reg = <0xe>; + + admaif14_ep: endpoint { + remote-endpoint = <&xbar_admaif14_ep>; + }; + }; + + admaif15_port: port@f { + reg = <0xf>; + + admaif15_ep: endpoint { + remote-endpoint = <&xbar_admaif15_ep>; + }; + }; + + admaif16_port: port@10 { + reg = <0x10>; + + admaif16_ep: endpoint { + remote-endpoint = <&xbar_admaif16_ep>; + }; + }; + + admaif17_port: port@11 { + reg = <0x11>; + + admaif17_ep: endpoint { + remote-endpoint = <&xbar_admaif17_ep>; + }; + }; + + admaif18_port: port@12 { + reg = <0x12>; + + admaif18_ep: endpoint { + remote-endpoint = <&xbar_admaif18_ep>; + }; + }; + + admaif19_port: port@13 { + reg = <0x13>; + + admaif19_ep: endpoint { + remote-endpoint = <&xbar_admaif19_ep>; + }; + }; + }; + }; + + i2s@2901200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s3_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s3_ep>; + }; + }; + + i2s3_port: port@1 { + reg = <1>; + + i2s3_dap_ep: endpoint { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + i2s@2901400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s5_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s5_ep>; + }; + }; + + i2s5_port: port@1 { + reg = <1>; + + i2s5_dap_ep: endpoint@0 { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + dmic@2904000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic1_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic1_ep>; + }; + }; + + dmic1_port: port@1 { + reg = <1>; + + dmic1_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dmic@2904100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic2_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic2_ep>; + }; + }; + + dmic2_port: port@1 { + reg = <1>; + + dmic2_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dmic@2904300 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic4_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic4_ep>; + }; + }; + + dmic4_port: port@1 { + reg = <1>; + + dmic4_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dspk@2905000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk1_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk1_ep>; + }; + }; + + dspk1_port: port@1 { + reg = <1>; + + dspk1_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dspk@2905100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk2_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk2_ep>; + }; + }; + + dspk2_port: port@1 { + reg = <1>; + + dspk2_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + }; }; ddc: i2c@3190000 { @@ -36,7 +607,7 @@ }; hda@3510000 { - nvidia,model = "jetson-xavier-nx-hda"; + nvidia,model = "NVIDIA Jetson Xavier NX HDA"; status = "okay"; }; @@ -265,6 +836,28 @@ regulator-boot-on; }; + sound { + compatible = "nvidia,tegra186-audio-graph-card"; + status = "okay"; + + dais = /* ADMAIF (FE) Ports */ + <&admaif0_port>, <&admaif1_port>, <&admaif2_port>, <&admaif3_port>, + <&admaif4_port>, <&admaif5_port>, <&admaif6_port>, <&admaif7_port>, + <&admaif8_port>, <&admaif9_port>, <&admaif10_port>, <&admaif11_port>, + <&admaif12_port>, <&admaif13_port>, <&admaif14_port>, <&admaif15_port>, + <&admaif16_port>, <&admaif17_port>, <&admaif18_port>, <&admaif19_port>, + /* XBAR Ports */ + <&xbar_i2s3_port>, <&xbar_i2s5_port>, + <&xbar_dmic1_port>, <&xbar_dmic2_port>, <&xbar_dmic4_port>, + <&xbar_dspk1_port>, <&xbar_dspk2_port>, + /* BE I/O Ports */ + <&i2s3_port>, <&i2s5_port>, + <&dmic1_port>, <&dmic2_port>, <&dmic4_port>, + <&dspk1_port>, <&dspk2_port>; + + label = "NVIDIA Jetson Xavier NX APE"; + }; + thermal-zones { cpu { polling-delay = <0>; diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi index 9449156fae39..b7d532841390 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi @@ -62,6 +62,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_EQOSR &emc>, <&mc TEGRA194_MEMORY_CLIENT_EQOSW &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_EQOS>; status = "disabled"; snps,write-requests = <1>; @@ -733,6 +734,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRA &emc>, <&mc TEGRA194_MEMORY_CLIENT_SDMMCWA &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_SDMMC1>; nvidia,pad-autocal-pull-up-offset-3v3-timeout = <0x07>; nvidia,pad-autocal-pull-down-offset-3v3-timeout = @@ -759,6 +761,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCR &emc>, <&mc TEGRA194_MEMORY_CLIENT_SDMMCW &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_SDMMC3>; nvidia,pad-autocal-pull-up-offset-1v8 = <0x00>; nvidia,pad-autocal-pull-down-offset-1v8 = <0x7a>; nvidia,pad-autocal-pull-up-offset-3v3-timeout = <0x07>; @@ -790,6 +793,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRAB &emc>, <&mc TEGRA194_MEMORY_CLIENT_SDMMCWAB &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_SDMMC4>; nvidia,pad-autocal-pull-up-offset-hs400 = <0x00>; nvidia,pad-autocal-pull-down-offset-hs400 = <0x00>; nvidia,pad-autocal-pull-up-offset-1v8-timeout = <0x0a>; @@ -821,6 +825,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_HDAR &emc>, <&mc TEGRA194_MEMORY_CLIENT_HDAW &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_HDA>; status = "disabled"; }; @@ -1300,6 +1305,84 @@ interrupt-controller; }; + smmu: iommu@12000000 { + compatible = "nvidia,tegra194-smmu", "nvidia,smmu-500"; + reg = <0x12000000 0x800000>, + <0x11000000 0x800000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + stream-match-mask = <0x7f80>; + #global-interrupts = <2>; + #iommu-cells = <1>; + + nvidia,memory-controller = <&mc>; + status = "okay"; + }; + host1x@13e00000 { compatible = "nvidia,tegra194-host1x"; reg = <0x13e00000 0x10000>, @@ -1319,6 +1402,7 @@ ranges = <0x15000000 0x15000000 0x01000000>; interconnects = <&mc TEGRA194_MEMORY_CLIENT_HOST1XDMAR &emc>; interconnect-names = "dma-mem"; + iommus = <&smmu TEGRA194_SID_HOST1X>; display-hub@15200000 { compatible = "nvidia,tegra194-display"; @@ -1430,6 +1514,7 @@ interconnects = <&mc TEGRA194_MEMORY_CLIENT_VICSRD &emc>, <&mc TEGRA194_MEMORY_CLIENT_VICSWR &emc>; interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA194_SID_VIC>; }; dpaux0: dpaux@155c0000 { @@ -2136,6 +2221,7 @@ <&mc TEGRA194_MEMORY_CLIENT_BPMPDMAR &emc>, <&mc TEGRA194_MEMORY_CLIENT_BPMPDMAW &emc>; interconnect-names = "read", "write", "dma-mem", "dma-write"; + iommus = <&smmu TEGRA194_SID_BPMP>; bpmp_i2c: i2c { compatible = "nvidia,tegra186-bpmp-i2c"; @@ -2345,6 +2431,20 @@ }; }; + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = , + , + , + , + , + , + , + ; + interrupt-affinity = <&cpu0_0 &cpu0_1 &cpu1_0 &cpu1_1 + &cpu2_0 &cpu2_1 &cpu3_0 &cpu3_1>; + }; + psci { compatible = "arm,psci-1.0"; status = "okay"; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts index 497635af7fab..7d3e3634743e 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts @@ -424,6 +424,6 @@ <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>, <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>; - label = "jetson-tx1-ape"; + label = "NVIDIA Jetson TX1 APE"; }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi index a9caaf7c0d67..d8409c1b4380 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi @@ -1345,7 +1345,7 @@ }; hda@70030000 { - nvidia,model = "jetson-tx1-hda"; + nvidia,model = "NVIDIA Jetson TX1 HDA"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts index 14c128a5e248..7dbb13f20de7 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts @@ -441,7 +441,7 @@ }; hda@70030000 { - nvidia,model = "jetson-nano-hda"; + nvidia,model = "NVIDIA Jetson Nano HDA"; status = "okay"; }; @@ -1043,6 +1043,6 @@ <&i2s3_port>, <&i2s4_port>, <&dmic1_port>, <&dmic2_port>; - label = "jetson-nano-ape"; + label = "NVIDIA Jetson Nano APE"; }; }; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 456502aeee49..4f0597091976 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -5,8 +5,11 @@ dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-ifc6640.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq6018-cp01-c1.dtb dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk01.dtb +dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk10-c1.dtb +dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk10-c2.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-alcatel-idol347.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-asus-z00l.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8916-huawei-g7.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-longcheer-l8150.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-longcheer-l8910.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb @@ -32,11 +35,12 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-oneplus-dumpling.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5.dtb +dtb-$(CONFIG_ARCH_QCOM) += sa8155p-adp.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r1-lte.dtb -dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r2.dtb -dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r2-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r3.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-coachz-r3-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r0.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-lazor-r1-kb.dtb @@ -51,6 +55,8 @@ dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r1-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r2.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r2-lte.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r3.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-pompom-r3-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7180-trogdor-r1-lte.dtb dtb-$(CONFIG_ARCH_QCOM) += sc7280-idp.dtb @@ -70,8 +76,13 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm845-oneplus-fajita.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-xiaomi-beryllium.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm850-lenovo-yoga-c630.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-hdk.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8150-microsoft-surface-duo.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8150-sony-xperia-kumano-bahamut.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8150-sony-xperia-kumano-griffin.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx203.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx206.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-mtp.dtb diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi index defcbd15edf9..068692350e00 100644 --- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi @@ -41,14 +41,14 @@ / { aliases { - serial0 = &blsp2_uart1; - serial1 = &blsp2_uart2; - serial2 = &blsp1_uart1; - i2c0 = &blsp1_i2c2; + serial0 = &blsp2_uart2; + serial1 = &blsp2_uart3; + serial2 = &blsp1_uart2; + i2c0 = &blsp1_i2c3; i2c1 = &blsp2_i2c1; - i2c2 = &blsp2_i2c0; - spi0 = &blsp1_spi0; - spi1 = &blsp2_spi5; + i2c2 = &blsp2_i2c1; + spi0 = &blsp1_spi1; + spi1 = &blsp2_spi6; }; chosen { @@ -133,24 +133,24 @@ }; }; -&blsp1_i2c2 { +&blsp1_i2c3 { /* On Low speed expansion */ label = "LS-I2C0"; status = "okay"; }; -&blsp1_spi0 { +&blsp1_spi1 { /* On Low speed expansion */ label = "LS-SPI0"; status = "okay"; }; -&blsp1_uart1 { +&blsp1_uart2 { label = "BT-UART"; status = "okay"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp1_uart1_default>; - pinctrl-1 = <&blsp1_uart1_sleep>; + pinctrl-0 = <&blsp1_uart2_default>; + pinctrl-1 = <&blsp1_uart2_sleep>; bluetooth { compatible = "qcom,qca6174-bt"; @@ -162,7 +162,11 @@ }; }; -&blsp2_i2c0 { +&adsp_pil { + status = "okay"; +}; + +&blsp2_i2c1 { /* On High speed expansion */ label = "HS-I2C2"; status = "okay"; @@ -174,32 +178,36 @@ status = "okay"; }; -&blsp2_spi5 { +&blsp2_spi6 { /* On High speed expansion */ label = "HS-SPI1"; status = "okay"; }; -&blsp2_uart1 { +&blsp2_uart2 { label = "LS-UART1"; status = "okay"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_uart1_2pins_default>; - pinctrl-1 = <&blsp2_uart1_2pins_sleep>; + pinctrl-0 = <&blsp2_uart2_2pins_default>; + pinctrl-1 = <&blsp2_uart2_2pins_sleep>; }; -&blsp2_uart2 { +&blsp2_uart3 { label = "LS-UART0"; status = "disabled"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_uart2_4pins_default>; - pinctrl-1 = <&blsp2_uart2_4pins_sleep>; + pinctrl-0 = <&blsp2_uart3_4pins_default>; + pinctrl-1 = <&blsp2_uart3_4pins_sleep>; }; &camss { vdda-supply = <&vreg_l2a_1p25>; }; +&gpu { + status = "okay"; +}; + &hdmi { status = "okay"; @@ -245,7 +253,12 @@ vdd-gfx-supply = <&vdd_gfx>; }; -&msmgpio { +&pm8994_resin { + status = "okay"; + linux,code = ; +}; + +&tlmm { gpio-line-names = "[SPI0_DOUT]", /* GPIO_0, BLSP1_SPI_MOSI, LSEC pin 14 */ "[SPI0_DIN]", /* GPIO_1, BLSP1_SPI_MISO, LSEC pin 10 */ @@ -424,7 +437,7 @@ }; }; - blsp1_uart1_default: blsp1_uart1_default { + blsp1_uart2_default: blsp1_uart2_default { mux { pins = "gpio41", "gpio42", "gpio43", "gpio44"; function = "blsp_uart2"; @@ -437,7 +450,7 @@ }; }; - blsp1_uart1_sleep: blsp1_uart1_sleep { + blsp1_uart2_sleep: blsp1_uart2_sleep { mux { pins = "gpio41", "gpio42", "gpio43", "gpio44"; function = "gpio"; @@ -505,20 +518,20 @@ &pcie0 { status = "okay"; - perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>; + perst-gpio = <&tlmm 35 GPIO_ACTIVE_LOW>; vddpe-3v3-supply = <&wlan_en>; vdda-supply = <&vreg_l28a_0p925>; }; &pcie1 { status = "okay"; - perst-gpio = <&msmgpio 130 GPIO_ACTIVE_LOW>; + perst-gpio = <&tlmm 130 GPIO_ACTIVE_LOW>; vdda-supply = <&vreg_l28a_0p925>; }; &pcie2 { status = "okay"; - perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>; + perst-gpio = <&tlmm 114 GPIO_ACTIVE_LOW>; vdda-supply = <&vreg_l28a_0p925>; }; @@ -929,9 +942,9 @@ &sdhc2 { /* External SD card */ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; - pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; - cd-gpios = <&msmgpio 38 0x1>; + pinctrl-0 = <&sdc2_state_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_state_off &sdc2_cd_off>; + cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; vmmc-supply = <&vreg_l21a_2p95>; vqmmc-supply = <&vreg_l13a_2p95>; status = "okay"; @@ -1026,20 +1039,6 @@ }; }; -&spmi_bus { - pmic@0 { - pon@800 { - resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; - }; - }; -}; - &ufsphy { status = "okay"; @@ -1064,7 +1063,7 @@ status = "okay"; extcon = <&usb2_id>; - dwc3@7600000 { + usb@7600000 { extcon = <&usb2_id>; dr_mode = "otg"; maximum-speed = "high-speed"; @@ -1075,7 +1074,7 @@ status = "okay"; extcon = <&usb3_id>; - dwc3@6a00000 { + usb@6a00000 { extcon = <&usb3_id>; dr_mode = "otg"; }; @@ -1089,6 +1088,10 @@ }; +&venus { + status = "okay"; +}; + &wcd9335 { clock-names = "mclk", "slimbus"; clocks = <&div1_mclk>, diff --git a/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts b/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts index f6ddf17ada81..8c7a27e972b7 100644 --- a/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts +++ b/arch/arm64/boot/dts/qcom/apq8096-ifc6640.dts @@ -17,7 +17,7 @@ qcom,board-id = <0x00010018 0>; aliases { - serial0 = &blsp2_uart1; + serial0 = &blsp2_uart2; }; chosen { @@ -81,14 +81,22 @@ }; }; -&blsp2_uart1 { +&blsp2_uart2 { status = "okay"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_uart1_2pins_default>; - pinctrl-1 = <&blsp2_uart1_2pins_sleep>; + pinctrl-0 = <&blsp2_uart2_2pins_default>; + pinctrl-1 = <&blsp2_uart2_2pins_sleep>; }; -&msmgpio { +&gpu { + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&tlmm { sdc2_pins_default: sdc2-pins-default { clk { pins = "sdc2_clk"; @@ -352,7 +360,7 @@ bus-width = <4>; - cd-gpios = <&msmgpio 38 0x1>; + cd-gpios = <&tlmm 38 0x1>; vmmc-supply = <&vreg_l21a_2p95>; vqmmc-supply = <&vreg_l13a_2p95>; @@ -383,3 +391,7 @@ vdda-phy-max-microamp = <18380>; vdda-pll-max-microamp = <9440>; }; + +&venus { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts new file mode 100644 index 000000000000..2bfcf42aeabc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c1.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ +/dts-v1/; + +#include "ipq8074-hk10.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IPQ8074/AP-HK10-C1"; + compatible = "qcom,ipq8074-hk10-c1", "qcom,ipq8074"; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts new file mode 100644 index 000000000000..7da39f1d979b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10-c2.dts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ +#include "ipq8074-hk10.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IPQ8074/AP-HK10-C2"; + compatible = "qcom,ipq8074-hk10-c2", "qcom,ipq8074"; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi b/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi new file mode 100644 index 000000000000..07e670829676 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +/dts-v1/; + +#include "ipq8074.dtsi" + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + interrupt-parent = <&intc>; + + aliases { + serial0 = &blsp1_uart5; + }; + + chosen { + stdout-path = "serial0"; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x40000000 0x0 0x20000000>; + }; +}; + +&blsp1_spi1 { + status = "ok"; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + }; +}; + +&blsp1_uart5 { + status = "ok"; +}; + +&pcie0 { + status = "ok"; + perst-gpio = <&tlmm 58 0x1>; +}; + +&pcie1 { + status = "ok"; + perst-gpio = <&tlmm 61 0x1>; +}; + +&pcie_phy0 { + status = "ok"; +}; + +&pcie_phy1 { + status = "ok"; +}; + +&qpic_bam { + status = "ok"; +}; + +&qpic_nand { + status = "ok"; + + nand@0 { + reg = <0>; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + nand-bus-width = <8>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index a32e5e79ab0b..95d6cb8cd4c0 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -165,6 +165,7 @@ clock-names = "cfg_ahb", "ref"; resets = <&gcc GCC_QUSB2_0_PHY_BCR>; + status = "disabled"; }; pcie_phy0: phy@86000 { @@ -372,6 +373,21 @@ status = "disabled"; }; + blsp1_i2c6: i2c@78ba000 { + compatible = "qcom,i2c-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x078ba000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_AHB_CLK>, + <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>; + clock-names = "iface", "core"; + clock-frequency = <100000>; + dmas = <&blsp_dma 23>, <&blsp_dma 22>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + qpic_bam: dma-controller@7984000 { compatible = "qcom,bam-v1.7.0"; reg = <0x07984000 0x1a000>; @@ -427,7 +443,7 @@ resets = <&gcc GCC_USB0_BCR>; status = "disabled"; - dwc_0: dwc3@8a00000 { + dwc_0: usb@8a00000 { compatible = "snps,dwc3"; reg = <0x8a00000 0xcd00>; interrupts = ; @@ -468,7 +484,7 @@ resets = <&gcc GCC_USB1_BCR>; status = "disabled"; - dwc_1: dwc3@8c00000 { + dwc_1: usb@8c00000 { compatible = "snps,dwc3"; reg = <0x8c00000 0xcd00>; interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts index 540b1fa4b260..670bd1bebd73 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts @@ -45,6 +45,24 @@ status = "okay"; }; +&blsp_i2c4 { + status = "okay"; + + touchscreen@26 { + compatible = "mstar,msg2638"; + reg = <0x26>; + interrupt-parent = <&msmgpio>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&msmgpio 100 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_reset_default>; + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l5>; + touchscreen-size-x = <2048>; + touchscreen-size-y = <2048>; + }; +}; + &blsp_i2c5 { status = "okay"; @@ -281,6 +299,14 @@ bias-pull-up; }; + ts_int_reset_default: ts-int-reset-default { + pins = "gpio13", "gpio100"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + usb_id_default: usb-id-default { pins = "gpio69"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts new file mode 100644 index 000000000000..e0075b574190 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2021 Stephan Gerhold + +/dts-v1/; + +#include "msm8916-pm8916.dtsi" +#include +#include +#include +#include + +/* + * Note: The original firmware from Huawei can only boot 32-bit kernels. + * To boot arm64 kernels it is necessary to flash 64-bit TZ/HYP firmware + * with EDL, e.g. taken from the DragonBoard 410c. This works because Huawei + * forgot to set up (firmware) secure boot for some reason. + * + * Also note that Huawei no longer provides bootloader unlock codes. + * This can be bypassed by patching the bootloader from a custom HYP firmware, + * making it think the bootloader is unlocked. + * + * See: https://wiki.postmarketos.org/wiki/Huawei_Ascend_G7_(huawei-g7) + */ + +/ { + model = "Huawei Ascend G7"; + compatible = "huawei,g7", "qcom,msm8916"; + + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&gpio_keys_default>; + + label = "GPIO Buttons"; + + volume-up { + label = "Volume Up"; + gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-names = "default"; + pinctrl-0 = <&gpio_leds_default>; + + led-0 { + gpios = <&msmgpio 8 GPIO_ACTIVE_HIGH>; + color = ; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + }; + + led-1 { + gpios = <&msmgpio 9 GPIO_ACTIVE_HIGH>; + color = ; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + }; + + led-2 { + gpios = <&msmgpio 10 GPIO_ACTIVE_HIGH>; + color = ; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&msmgpio 117 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_default>; + }; +}; + +&blsp_i2c2 { + status = "okay"; + + magnetometer@c { + compatible = "asahi-kasei,ak09911"; + reg = <0x0c>; + + vdd-supply = <&pm8916_l17>; + vid-supply = <&pm8916_l6>; + + reset-gpios = <&msmgpio 36 GPIO_ACTIVE_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&mag_reset_default>; + }; + + accelerometer@1e { + compatible = "kionix,kx023-1025"; + reg = <0x1e>; + + interrupt-parent = <&msmgpio>; + interrupts = <115 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + + pinctrl-names = "default"; + pinctrl-0 = <&accel_irq_default>; + + mount-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "1"; + }; + + proximity@39 { + compatible = "avago,apds9930"; + reg = <0x39>; + + interrupt-parent = <&msmgpio>; + interrupts = <113 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + + led-max-microamp = <100000>; + amstaos,proximity-diodes = <1>; + + pinctrl-names = "default"; + pinctrl-0 = <&prox_irq_default>; + }; + + regulator@3e { + compatible = "ti,tps65132"; + reg = <0x3e>; + + pinctrl-names = "default"; + pinctrl-0 = <®_lcd_en_default>; + + reg_lcd_pos: outp { + regulator-name = "outp"; + regulator-min-microvolt = <5400000>; + regulator-max-microvolt = <5400000>; + enable-gpios = <&msmgpio 97 GPIO_ACTIVE_HIGH>; + regulator-active-discharge = <1>; + }; + + reg_lcd_neg: outn { + regulator-name = "outn"; + regulator-min-microvolt = <5400000>; + regulator-max-microvolt = <5400000>; + enable-gpios = <&msmgpio 32 GPIO_ACTIVE_HIGH>; + regulator-active-discharge = <1>; + }; + }; +}; + +&blsp_i2c5 { + status = "okay"; + + rmi4@70 { + compatible = "syna,rmi4-i2c"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&msmgpio>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l16>; + + pinctrl-names = "default"; + pinctrl-0 = <&ts_irq_default>; + + syna,startup-delay-ms = <100>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; /* Allow sleeping */ + }; + + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; /* Touchscreen */ + }; + }; +}; + +&blsp_i2c6 { + status = "okay"; + + nfc@28 { + compatible = "nxp,pn547", "nxp,nxp-nci-i2c"; + reg = <0x28>; + + interrupt-parent = <&msmgpio>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + + enable-gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&msmgpio 2 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_default>; + }; +}; + +&blsp1_uart2 { + status = "okay"; +}; + +&pm8916_resin { + status = "okay"; + linux,code = ; +}; + +&pm8916_vib { + status = "okay"; +}; + +&pronto { + status = "okay"; +}; + +&sdhc_1 { + status = "okay"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; +}; + +&sdhc_2 { + status = "okay"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdhc2_cd_default>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdhc2_cd_default>; + + /* + * The Huawei device tree sets cd-gpios = <&msmgpio 38 GPIO_ACTIVE_HIGH>. + * However, gpio38 does not change its state when inserting/removing the + * SD card, it's just low all the time. The Huawei kernel seems to use + * polling for SD card detection instead. + * + * However, looking closer at the GPIO debug output it turns out that + * gpio56 switches its state when inserting/removing the SD card. + * It behaves just like gpio38 normally does. Usually GPIO56 is used as + * "UIM2_PRESENT", i.e. to check if a second SIM card is inserted. + * Maybe Huawei decided to replace the second SIM card slot with the + * SD card slot and forgot to re-route to gpio38. + */ + cd-gpios = <&msmgpio 56 GPIO_ACTIVE_LOW>; +}; + +&usb { + status = "okay"; + extcon = <&usb_id>, <&usb_id>; +}; + +&usb_hs_phy { + extcon = <&usb_id>; +}; + +&smd_rpm_regulators { + vdd_l1_l2_l3-supply = <&pm8916_s3>; + vdd_l4_l5_l6-supply = <&pm8916_s4>; + vdd_l7-supply = <&pm8916_s4>; + + s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + }; + + s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + }; + + l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + l4 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l8 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + l9 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + l10 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + }; + + l11 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + regulator-system-load = <200000>; + }; + + l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + l13 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + l18 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; +}; + +&msmgpio { + accel_irq_default: accel-irq-default { + pins = "gpio115"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + gpio_keys_default: gpio-keys-default { + pins = "gpio107"; + function = "gpio"; + + drive-strength = <2>; + bias-pull-up; + }; + + gpio_leds_default: gpio-leds-default { + pins = "gpio8", "gpio9", "gpio10"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + nfc_default: nfc-default { + pins = "gpio2", "gpio20", "gpio21"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + mag_reset_default: mag-reset-default { + pins = "gpio36"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + prox_irq_default: prox-irq-default { + pins = "gpio113"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + reg_lcd_en_default: reg-lcd-en-default { + pins = "gpio32", "gpio97"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + sdhc2_cd_default: sdhc2-cd-default { + pins = "gpio56"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + ts_irq_default: ts-irq-default { + pins = "gpio13"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + usb_id_default: usb-id-default { + pins = "gpio117"; + function = "gpio"; + + drive-strength = <8>; + bias-pull-up; + }; +}; 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 230ba3ce3277..9b4b7de7cec2 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi @@ -4,6 +4,7 @@ #include #include #include +#include / { aliases { @@ -95,6 +96,63 @@ pinctrl-0 = <&muic_int_default>; }; }; + + i2c-tkey { + compatible = "i2c-gpio"; + sda-gpios = <&msmgpio 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&msmgpio 17 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_i2c_default>; + + #address-cells = <1>; + #size-cells = <0>; + + touchkey: touchkey@20 { + /* Note: Actually an ABOV MCU that implements same interface */ + compatible = "coreriver,tc360-touchkey"; + reg = <0x20>; + + interrupt-parent = <&msmgpio>; + interrupts = <98 IRQ_TYPE_EDGE_FALLING>; + + /* vcc/vdd-supply are board-specific */ + vddio-supply = <&pm8916_l6>; + + linux,keycodes = ; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_default>; + }; + }; + + i2c-nfc { + compatible = "i2c-gpio"; + sda-gpios = <&msmgpio 0 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&msmgpio 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_i2c_default>; + + #address-cells = <1>; + #size-cells = <0>; + + nfc@27 { + compatible = "samsung,s3fwrn5-i2c"; + reg = <0x27>; + + interrupt-parent = <&msmgpio>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + + en-gpios = <&msmgpio 20 GPIO_ACTIVE_HIGH>; + wake-gpios = <&msmgpio 49 GPIO_ACTIVE_HIGH>; + + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + + pinctrl-names = "default"; + pinctrl-0 = <&nfc_default &nfc_clk_req>; + }; + }; }; &blsp_i2c2 { @@ -122,6 +180,20 @@ }; }; +&blsp_i2c4 { + status = "okay"; + + battery@35 { + compatible = "richtek,rt5033-battery"; + reg = <0x35>; + interrupt-parent = <&msmgpio>; + interrupts = <121 IRQ_TYPE_EDGE_BOTH>; + + pinctrl-names = "default"; + pinctrl-0 = <&fg_alert_default>; + }; +}; + &blsp1_uart2 { status = "okay"; }; @@ -284,6 +356,14 @@ bias-disable; }; + fg_alert_default: fg-alert-default { + pins = "gpio121"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + gpio_keys_default: gpio-keys-default { pins = "gpio107", "gpio109"; function = "gpio"; @@ -333,6 +413,46 @@ bias-disable; }; + nfc_default: nfc-default { + pins = "gpio20", "gpio49"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + + irq { + pins = "gpio21"; + function = "gpio"; + + drive-strength = <2>; + bias-pull-down; + }; + }; + + nfc_i2c_default: nfc-i2c-default { + pins = "gpio0", "gpio1"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + tkey_default: tkey-default { + pins = "gpio98"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + tkey_i2c_default: tkey-i2c-default { + pins = "gpio16", "gpio17"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + tsp_en_default: tsp-en-default { pins = "gpio73"; function = "gpio"; @@ -341,3 +461,14 @@ bias-disable; }; }; + +&pm8916_gpios { + nfc_clk_req: nfc-clk-req { + pins = "gpio2"; + function = "func1"; + + input-enable; + bias-disable; + power-source = ; + }; +}; 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 661f41ad978b..6cc2eaeb1d33 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts @@ -20,6 +20,37 @@ pinctrl-names = "default"; pinctrl-0 = <&panel_vdd3_default>; }; + + reg_touch_key: regulator-touch-key { + compatible = "regulator-fixed"; + regulator-name = "touch_key"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + + gpio = <&msmgpio 86 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_en_default>; + }; + + reg_key_led: regulator-key-led { + compatible = "regulator-fixed"; + regulator-name = "key_led"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&msmgpio 60 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_led_en_default>; + }; +}; + +&touchkey { + vcc-supply = <®_touch_key>; + vdd-supply = <®_key_led>; }; &accelerometer { @@ -81,6 +112,22 @@ bias-disable; }; + tkey_en_default: tkey-en-default { + pins = "gpio86"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + tkey_led_en_default: tkey-led-en-default { + pins = "gpio60"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + ts_int_default: ts-int-default { pins = "gpio13"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts index dd35c3344358..c2eff5aebf85 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts @@ -7,6 +7,19 @@ / { model = "Samsung Galaxy A5U (EUR)"; compatible = "samsung,a5u-eur", "qcom,msm8916"; + + reg_touch_key: regulator-touch-key { + compatible = "regulator-fixed"; + regulator-name = "touch_key"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&msmgpio 97 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&tkey_en_default>; + }; }; &accelerometer { @@ -42,7 +55,20 @@ }; }; +&touchkey { + vcc-supply = <®_touch_key>; + vdd-supply = <®_touch_key>; +}; + &msmgpio { + tkey_en_default: tkey-en-default { + pins = "gpio97"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + ts_int_default: ts-int-default { pins = "gpio13"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts index baa55643b40f..ffe1a9bd8f70 100644 --- a/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts +++ b/arch/arm64/boot/dts/qcom/msm8994-angler-rev-101.dts @@ -32,3 +32,7 @@ }; }; }; + +&tlmm { + gpio-reserved-ranges = <85 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8996-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8996-mtp.dtsi index 5f46a1427f1f..1e1514e9158c 100644 --- a/arch/arm64/boot/dts/qcom/msm8996-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996-mtp.dtsi @@ -7,7 +7,7 @@ / { aliases { - serial0 = &blsp2_uart1; + serial0 = &blsp2_uart2; }; chosen { diff --git a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi deleted file mode 100644 index ac1ede579361..000000000000 --- a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi +++ /dev/null @@ -1,653 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. - */ - -&msmgpio { - - wcd9xxx_intr { - wcd_intr_default: wcd_intr_default{ - mux { - pins = "gpio54"; - function = "gpio"; - }; - - config { - pins = "gpio54"; - drive-strength = <2>; /* 2 mA */ - bias-pull-down; /* pull down */ - input-enable; - }; - }; - }; - - cdc_reset_ctrl { - cdc_reset_sleep: cdc_reset_sleep { - mux { - pins = "gpio64"; - function = "gpio"; - }; - config { - pins = "gpio64"; - drive-strength = <16>; - bias-disable; - output-low; - }; - }; - cdc_reset_active:cdc_reset_active { - mux { - pins = "gpio64"; - function = "gpio"; - }; - config { - pins = "gpio64"; - drive-strength = <16>; - bias-pull-down; - output-high; - }; - }; - }; - - blsp1_spi0_default: blsp1_spi0_default { - pinmux { - function = "blsp_spi1"; - pins = "gpio0", "gpio1", "gpio3"; - }; - pinmux_cs { - function = "gpio"; - pins = "gpio2"; - }; - pinconf { - pins = "gpio0", "gpio1", "gpio3"; - drive-strength = <12>; - bias-disable; - }; - pinconf_cs { - pins = "gpio2"; - drive-strength = <16>; - bias-disable; - output-high; - }; - }; - - blsp1_spi0_sleep: blsp1_spi0_sleep { - pinmux { - function = "gpio"; - pins = "gpio0", "gpio1", "gpio2", "gpio3"; - }; - pinconf { - pins = "gpio0", "gpio1", "gpio2", "gpio3"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - blsp1_i2c2_default: blsp1_i2c2_default { - pinmux { - function = "blsp_i2c3"; - pins = "gpio47", "gpio48"; - }; - pinconf { - pins = "gpio47", "gpio48"; - drive-strength = <16>; - bias-disable = <0>; - }; - }; - - blsp1_i2c2_sleep: blsp1_i2c2_sleep { - pinmux { - function = "gpio"; - pins = "gpio47", "gpio48"; - }; - pinconf { - pins = "gpio47", "gpio48"; - drive-strength = <2>; - bias-disable = <0>; - }; - }; - - blsp2_i2c0_default: blsp2_i2c0 { - pinmux { - function = "blsp_i2c7"; - pins = "gpio55", "gpio56"; - }; - pinconf { - pins = "gpio55", "gpio56"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_i2c0_sleep: blsp2_i2c0_sleep { - pinmux { - function = "gpio"; - pins = "gpio55", "gpio56"; - }; - pinconf { - pins = "gpio55", "gpio56"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_uart1_2pins_default: blsp2_uart1_2pins { - pinmux { - function = "blsp_uart8"; - pins = "gpio4", "gpio5"; - }; - pinconf { - pins = "gpio4", "gpio5"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_uart1_2pins_sleep: blsp2_uart1_2pins_sleep { - pinmux { - function = "gpio"; - pins = "gpio4", "gpio5"; - }; - pinconf { - pins = "gpio4", "gpio5"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_uart1_4pins_default: blsp2_uart1_4pins { - pinmux { - function = "blsp_uart8"; - pins = "gpio4", "gpio5", "gpio6", "gpio7"; - }; - - pinconf { - pins = "gpio4", "gpio5", "gpio6", "gpio7"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_uart1_4pins_sleep: blsp2_uart1_4pins_sleep { - pinmux { - function = "gpio"; - pins = "gpio4", "gpio5", "gpio6", "gpio7"; - }; - - pinconf { - pins = "gpio4", "gpio5", "gpio6", "gpio7"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_i2c1_default: blsp2_i2c1 { - pinmux { - function = "blsp_i2c8"; - pins = "gpio6", "gpio7"; - }; - pinconf { - pins = "gpio6", "gpio7"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_i2c1_sleep: blsp2_i2c1_sleep { - pinmux { - function = "gpio"; - pins = "gpio6", "gpio7"; - }; - pinconf { - pins = "gpio6", "gpio7"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_uart2_2pins_default: blsp2_uart2_2pins { - pinmux { - function = "blsp_uart9"; - pins = "gpio49", "gpio50"; - }; - pinconf { - pins = "gpio49", "gpio50"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_uart2_2pins_sleep: blsp2_uart2_2pins_sleep { - pinmux { - function = "gpio"; - pins = "gpio49", "gpio50"; - }; - pinconf { - pins = "gpio49", "gpio50"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_uart2_4pins_default: blsp2_uart2_4pins { - pinmux { - function = "blsp_uart9"; - pins = "gpio49", "gpio50", "gpio51", "gpio52"; - }; - - pinconf { - pins = "gpio49", "gpio50", "gpio51", "gpio52"; - drive-strength = <16>; - bias-disable; - }; - }; - - blsp2_uart2_4pins_sleep: blsp2_uart2_4pins_sleep { - pinmux { - function = "gpio"; - pins = "gpio49", "gpio50", "gpio51", "gpio52"; - }; - - pinconf { - pins = "gpio49", "gpio50", "gpio51", "gpio52"; - drive-strength = <2>; - bias-disable; - }; - }; - - blsp2_spi5_default: blsp2_spi5_default { - pinmux { - function = "blsp_spi12"; - pins = "gpio85", "gpio86", "gpio88"; - }; - pinmux_cs { - function = "gpio"; - pins = "gpio87"; - }; - pinconf { - pins = "gpio85", "gpio86", "gpio88"; - drive-strength = <12>; - bias-disable; - }; - pinconf_cs { - pins = "gpio87"; - drive-strength = <16>; - bias-disable; - output-high; - }; - }; - - blsp2_spi5_sleep: blsp2_spi5_sleep { - pinmux { - function = "gpio"; - pins = "gpio85", "gpio86", "gpio87", "gpio88"; - }; - pinconf { - pins = "gpio85", "gpio86", "gpio87", "gpio88"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - sdc2_clk_on: sdc2_clk_on { - config { - pins = "sdc2_clk"; - bias-disable; /* NO pull */ - drive-strength = <16>; /* 16 MA */ - }; - }; - - sdc2_clk_off: sdc2_clk_off { - config { - pins = "sdc2_clk"; - bias-disable; /* NO pull */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - sdc2_cmd_on: sdc2_cmd_on { - config { - pins = "sdc2_cmd"; - bias-pull-up; /* pull up */ - drive-strength = <10>; /* 10 MA */ - }; - }; - - sdc2_cmd_off: sdc2_cmd_off { - config { - pins = "sdc2_cmd"; - bias-pull-up; /* pull up */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - sdc2_data_on: sdc2_data_on { - config { - pins = "sdc2_data"; - bias-pull-up; /* pull up */ - drive-strength = <10>; /* 10 MA */ - }; - }; - - sdc2_data_off: sdc2_data_off { - config { - pins = "sdc2_data"; - bias-pull-up; /* pull up */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - pcie0_clkreq_default: pcie0_clkreq_default { - mux { - pins = "gpio36"; - function = "pci_e0"; - }; - - config { - pins = "gpio36"; - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie0_perst_default: pcie0_perst_default { - mux { - pins = "gpio35"; - function = "gpio"; - }; - - config { - pins = "gpio35"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - pcie0_wake_default: pcie0_wake_default { - mux { - pins = "gpio37"; - function = "gpio"; - }; - - config { - pins = "gpio37"; - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie0_clkreq_sleep: pcie0_clkreq_sleep { - mux { - pins = "gpio36"; - function = "gpio"; - }; - - config { - pins = "gpio36"; - drive-strength = <2>; - bias-disable; - }; - }; - - pcie0_wake_sleep: pcie0_wake_sleep { - mux { - pins = "gpio37"; - function = "gpio"; - }; - - config { - pins = "gpio37"; - drive-strength = <2>; - bias-disable; - }; - }; - - pcie1_clkreq_default: pcie1_clkreq_default { - mux { - pins = "gpio131"; - function = "pci_e1"; - }; - - config { - pins = "gpio131"; - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie1_perst_default: pcie1_perst_default { - mux { - pins = "gpio130"; - function = "gpio"; - }; - - config { - pins = "gpio130"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - pcie1_wake_default: pcie1_wake_default { - mux { - pins = "gpio132"; - function = "gpio"; - }; - - config { - pins = "gpio132"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - pcie1_clkreq_sleep: pcie1_clkreq_sleep { - mux { - pins = "gpio131"; - function = "gpio"; - }; - - config { - pins = "gpio131"; - drive-strength = <2>; - bias-disable; - }; - }; - - pcie1_wake_sleep: pcie1_wake_sleep { - mux { - pins = "gpio132"; - function = "gpio"; - }; - - config { - pins = "gpio132"; - drive-strength = <2>; - bias-disable; - }; - }; - - pcie2_clkreq_default: pcie2_clkreq_default { - mux { - pins = "gpio115"; - function = "pci_e2"; - }; - - config { - pins = "gpio115"; - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie2_perst_default: pcie2_perst_default { - mux { - pins = "gpio114"; - function = "gpio"; - }; - - config { - pins = "gpio114"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - pcie2_wake_default: pcie2_wake_default { - mux { - pins = "gpio116"; - function = "gpio"; - }; - - config { - pins = "gpio116"; - drive-strength = <2>; - bias-pull-down; - }; - }; - - pcie2_clkreq_sleep: pcie2_clkreq_sleep { - mux { - pins = "gpio115"; - function = "gpio"; - }; - - config { - pins = "gpio115"; - drive-strength = <2>; - bias-disable; - }; - }; - - pcie2_wake_sleep: pcie2_wake_sleep { - mux { - pins = "gpio116"; - function = "gpio"; - }; - - config { - pins = "gpio116"; - drive-strength = <2>; - bias-disable; - }; - }; - - cci0_default: cci0_default { - pinmux { - function = "cci_i2c"; - pins = "gpio17", "gpio18"; - }; - pinconf { - pins = "gpio17", "gpio18"; - drive-strength = <16>; - bias-disable; - }; - }; - - cci1_default: cci1_default { - pinmux { - function = "cci_i2c"; - pins = "gpio19", "gpio20"; - }; - pinconf { - pins = "gpio19", "gpio20"; - drive-strength = <16>; - bias-disable; - }; - }; - - camera_board_default: camera_board_default { - mux_pwdn { - function = "gpio"; - pins = "gpio98"; - }; - config_pwdn { - pins = "gpio98"; - drive-strength = <16>; - bias-disable; - }; - - mux_rst { - function = "gpio"; - pins = "gpio104"; - }; - config_rst { - pins = "gpio104"; - drive-strength = <16>; - bias-disable; - }; - - mux_mclk1 { - function = "cam_mclk"; - pins = "gpio14"; - }; - config_mclk1 { - pins = "gpio14"; - drive-strength = <16>; - bias-disable; - }; - }; - - camera_front_default: camera_front_default { - mux_pwdn { - function = "gpio"; - pins = "gpio133"; - }; - config_pwdn { - pins = "gpio133"; - drive-strength = <16>; - bias-disable; - }; - - mux_rst { - function = "gpio"; - pins = "gpio23"; - }; - config_rst { - pins = "gpio23"; - drive-strength = <16>; - bias-disable; - }; - - mux_mclk2 { - function = "cam_mclk"; - pins = "gpio15"; - }; - config_mclk2 { - pins = "gpio15"; - drive-strength = <16>; - bias-disable; - }; - }; - - camera_rear_default: camera_rear_default { - mux_pwdn { - function = "gpio"; - pins = "gpio26"; - }; - config_pwdn { - pins = "gpio26"; - drive-strength = <16>; - bias-disable; - }; - - mux_rst { - function = "gpio"; - pins = "gpio25"; - }; - config_rst { - pins = "gpio25"; - drive-strength = <16>; - bias-disable; - }; - - mux_mclk0 { - function = "cam_mclk"; - pins = "gpio13"; - }; - config_mclk0 { - pins = "gpio13"; - drive-strength = <16>; - bias-disable; - }; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 5d06216c5c1c..0e1bc4669d7e 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include / { interrupt-parent = <&intc>; @@ -43,6 +45,9 @@ enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; capacity-dmips-mhz = <1024>; + clocks = <&kryocc 0>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; next-level-cache = <&L2_0>; L2_0: l2-cache { compatible = "cache"; @@ -57,6 +62,9 @@ enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; capacity-dmips-mhz = <1024>; + clocks = <&kryocc 0>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; next-level-cache = <&L2_0>; }; @@ -67,6 +75,9 @@ enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; capacity-dmips-mhz = <1024>; + clocks = <&kryocc 1>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; next-level-cache = <&L2_1>; L2_1: l2-cache { compatible = "cache"; @@ -81,6 +92,9 @@ enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0>; capacity-dmips-mhz = <1024>; + clocks = <&kryocc 1>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; next-level-cache = <&L2_1>; }; @@ -120,6 +134,227 @@ }; }; + cluster0_opp: opp_table0 { + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&speedbin_efuse>; + opp-shared; + + /* Nominal fmax for now */ + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-422400000 { + opp-hz = /bits/ 64 <422400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-556800000 { + opp-hz = /bits/ 64 <556800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-729600000 { + opp-hz = /bits/ 64 <729600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-844800000 { + opp-hz = /bits/ 64 <844800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-960000000 { + opp-hz = /bits/ 64 <960000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1036800000 { + opp-hz = /bits/ 64 <1036800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1228800000 { + opp-hz = /bits/ 64 <1228800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1324800000 { + opp-hz = /bits/ 64 <1324800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1478400000 { + opp-hz = /bits/ 64 <1478400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1593600000 { + opp-hz = /bits/ 64 <1593600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + }; + + cluster1_opp: opp_table1 { + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&speedbin_efuse>; + opp-shared; + + /* Nominal fmax for now */ + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-403200000 { + opp-hz = /bits/ 64 <403200000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-556800000 { + opp-hz = /bits/ 64 <556800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-729600000 { + opp-hz = /bits/ 64 <729600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-806400000 { + opp-hz = /bits/ 64 <806400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-883200000 { + opp-hz = /bits/ 64 <883200000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-940800000 { + opp-hz = /bits/ 64 <940800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1036800000 { + opp-hz = /bits/ 64 <1036800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1248000000 { + opp-hz = /bits/ 64 <1248000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1324800000 { + opp-hz = /bits/ 64 <1324800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1478400000 { + opp-hz = /bits/ 64 <1478400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1555200000 { + opp-hz = /bits/ 64 <1555200000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1632000000 { + opp-hz = /bits/ 64 <1632000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1708800000 { + opp-hz = /bits/ 64 <1708800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1785600000 { + opp-hz = /bits/ 64 <1785600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1824000000 { + opp-hz = /bits/ 64 <1824000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1920000000 { + opp-hz = /bits/ 64 <1920000000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-1996800000 { + opp-hz = /bits/ 64 <1996800000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-2073600000 { + opp-hz = /bits/ 64 <2073600000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-2150400000 { + opp-hz = /bits/ 64 <2150400000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + }; + firmware { scm { compatible = "qcom,scm-msm8996"; @@ -424,7 +659,7 @@ bits = <1 4>; }; - gpu_speed_bin: gpu_speed_bin@133 { + speedbin_efuse: speedbin@133 { reg = <0x133 0x1>; bits = <5 3>; }; @@ -472,7 +707,7 @@ tcsr_mutex_regs: syscon@740000 { compatible = "syscon"; - reg = <0x00740000 0x20000>; + reg = <0x00740000 0x40000>; }; tcsr: syscon@7a0000 { @@ -521,6 +756,8 @@ #size-cells = <1>; ranges; + status = "disabled"; + mdp: mdp@901000 { compatible = "qcom,mdp5"; reg = <0x00901000 0x90000>; @@ -542,6 +779,11 @@ iommus = <&mdp_smmu 0>; + assigned-clocks = <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_VSYNC_CLK>; + assigned-clock-rates = <300000000>, + <19200000>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -552,9 +794,82 @@ remote-endpoint = <&hdmi_in>; }; }; + + port@1 { + reg = <1>; + mdp5_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; }; }; + dsi0: dsi@994000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x00994000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MMSS_MISC_AHB_CLK>, + <&mmcc MDSS_PCLK0_CLK>, + <&mmcc MDSS_ESC0_CLK>; + clock-names = "mdp_core", + "byte", + "iface", + "bus", + "core_mmss", + "pixel", + "core"; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + status = "disabled"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp5_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + }; + + dsi0_phy: dsi-phy@994400 { + compatible = "qcom,dsi-phy-14nm"; + reg = <0x00994400 0x100>, + <0x00994500 0x300>, + <0x00994800 0x188>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&mmcc MDSS_AHB_CLK>, <&xo_board>; + clock-names = "iface", "ref"; + status = "disabled"; + }; + hdmi: hdmi-tx@9a0000 { compatible = "qcom,hdmi-tx-8996"; reg = <0x009a0000 0x50c>, @@ -618,7 +933,8 @@ "ref"; }; }; - gpu@b00000 { + + gpu: gpu@b00000 { compatible = "qcom,adreno-530.2", "qcom,adreno"; #stream-id-cells = <16>; @@ -642,7 +958,7 @@ power-domains = <&mmcc GPU_GX_GDSC>; iommus = <&adreno_smmu 0>; - nvmem-cells = <&gpu_speed_bin>; + nvmem-cells = <&speedbin_efuse>; nvmem-cell-names = "speed_bin"; qcom,gpu-quirk-two-pass-use-wfi; @@ -650,6 +966,8 @@ operating-points-v2 = <&gpu_opp_table>; + status = "disabled"; + gpu_opp_table: opp-table { compatible ="operating-points-v2"; @@ -693,15 +1011,482 @@ }; }; - msmgpio: pinctrl@1010000 { + tlmm: pinctrl@1010000 { compatible = "qcom,msm8996-pinctrl"; reg = <0x01010000 0x300000>; interrupts = ; gpio-controller; - gpio-ranges = <&msmgpio 0 0 150>; + gpio-ranges = <&tlmm 0 0 150>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + + blsp1_spi1_default: blsp1-spi1-default { + spi { + pins = "gpio0", "gpio1", "gpio3"; + function = "blsp_spi1"; + drive-strength = <12>; + bias-disable; + }; + + cs { + pins = "gpio2"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-high; + }; + }; + + blsp1_spi1_sleep: blsp1-spi1-sleep { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + blsp2_uart2_2pins_default: blsp2-uart1-2pins { + pins = "gpio4", "gpio5"; + function = "blsp_uart8"; + drive-strength = <16>; + bias-disable; + }; + + blsp2_uart2_2pins_sleep: blsp2-uart1-2pins-sleep { + pins = "gpio4", "gpio5"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + blsp2_i2c2_default: blsp2-i2c2 { + pins = "gpio6", "gpio7"; + function = "blsp_i2c8"; + drive-strength = <16>; + bias-disable; + }; + + blsp2_i2c2_sleep: blsp2-i2c2-sleep { + pins = "gpio6", "gpio7"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + cci0_default: cci0-default { + pins = "gpio17", "gpio18"; + function = "cci_i2c"; + drive-strength = <16>; + bias-disable; + }; + + camera0_state_on: + camera_rear_default: camera-rear-default { + mclk0 { + pins = "gpio13"; + function = "cam_mclk"; + drive-strength = <16>; + bias-disable; + }; + + rst { + pins = "gpio25"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + pwdn { + pins = "gpio26"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + cci1_default: cci1-default { + pins = "gpio19", "gpio20"; + function = "cci_i2c"; + drive-strength = <16>; + bias-disable; + }; + + camera1_state_on: + camera_board_default: camera-board-default { + mclk1 { + pins = "gpio14"; + function = "cam_mclk"; + drive-strength = <16>; + bias-disable; + }; + + pwdn { + pins = "gpio98"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + rst { + pins = "gpio104"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + camera2_state_on: + camera_front_default: camera-front-default { + mclk2 { + pins = "gpio15"; + function = "cam_mclk"; + drive-strength = <16>; + bias-disable; + }; + + rst { + pins = "gpio23"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + pwdn { + pins = "gpio133"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + pcie0_state_on: pcie0-state-on { + perst { + pins = "gpio35"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio36"; + function = "pci_e0"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio37"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_state_off: pcie0-state-off { + perst { + pins = "gpio35"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio36"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake { + pins = "gpio37"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_i2c3_default: blsp1-i2c2-default { + pins = "gpio47", "gpio48"; + function = "blsp_i2c3"; + drive-strength = <16>; + bias-disable = <0>; + }; + + blsp1_i2c3_sleep: blsp1-i2c2-sleep { + pins = "gpio47", "gpio48"; + function = "gpio"; + drive-strength = <2>; + bias-disable = <0>; + }; + + blsp2_uart3_4pins_default: blsp2-uart2-4pins { + pins = "gpio49", "gpio50", "gpio51", "gpio52"; + function = "blsp_uart9"; + drive-strength = <16>; + bias-disable; + }; + + blsp2_uart3_4pins_sleep: blsp2-uart2-4pins-sleep { + pins = "gpio49", "gpio50", "gpio51", "gpio52"; + function = "blsp_uart9"; + drive-strength = <2>; + bias-disable; + }; + + wcd_intr_default: wcd-intr-default{ + pins = "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + blsp2_i2c1_default: blsp2-i2c1 { + pins = "gpio55", "gpio56"; + function = "blsp_i2c7"; + drive-strength = <16>; + bias-disable; + }; + + blsp2_i2c1_sleep: blsp2-i2c0-sleep { + pins = "gpio55", "gpio56"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + blsp2_i2c5_default: blsp2-i2c5 { + pins = "gpio60", "gpio61"; + function = "blsp_i2c11"; + drive-strength = <2>; + bias-disable; + }; + + /* Sleep state for BLSP2_I2C5 is missing.. */ + + cdc_reset_active: cdc-reset-active { + pins = "gpio64"; + function = "gpio"; + drive-strength = <16>; + bias-pull-down; + output-high; + }; + + cdc_reset_sleep: cdc-reset-sleep { + pins = "gpio64"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-low; + }; + + blsp2_spi6_default: blsp2-spi5-default { + spi { + pins = "gpio85", "gpio86", "gpio88"; + function = "blsp_spi12"; + drive-strength = <12>; + bias-disable; + }; + + cs { + pins = "gpio87"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-high; + }; + }; + + blsp2_spi6_sleep: blsp2-spi5-sleep { + pins = "gpio85", "gpio86", "gpio87", "gpio88"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + blsp2_i2c6_default: blsp2-i2c6 { + pins = "gpio87", "gpio88"; + function = "blsp_i2c12"; + drive-strength = <16>; + bias-disable; + }; + + blsp2_i2c6_sleep: blsp2-i2c6-sleep { + pins = "gpio87", "gpio88"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + pcie1_state_on: pcie1-state-on { + perst { + pins = "gpio130"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio131"; + function = "pci_e1"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio132"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie1_state_off: pcie1-state-off { + /* Perst is missing? */ + clkreq { + pins = "gpio131"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake { + pins = "gpio132"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + }; + + pcie2_state_on: pcie2-state-on { + perst { + pins = "gpio114"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio115"; + function = "pci_e2"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio116"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie2_state_off: pcie2-state-off { + /* Perst is missing? */ + clkreq { + pins = "gpio115"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake { + pins = "gpio116"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + }; + + sdc1_state_on: sdc1-state-on { + clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <16>; + }; + + cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <10>; + }; + + rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc1_state_off: sdc1-state-off { + clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <2>; + }; + + cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <2>; + }; + + rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc2_state_on: sdc2-clk-on { + clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <16>; + }; + + cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <10>; + }; + }; + + sdc2_state_off: sdc2-clk-off { + clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <2>; + }; + + cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <2>; + }; + }; }; spmi_bus: qcom,spmi@400f000 { @@ -762,8 +1547,8 @@ <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&pcie0_clkreq_default &pcie0_perst_default &pcie0_wake_default>; - pinctrl-1 = <&pcie0_clkreq_sleep &pcie0_perst_default &pcie0_wake_sleep>; + pinctrl-0 = <&pcie0_state_on>; + pinctrl-1 = <&pcie0_state_off>; linux,pci-domain = <0>; @@ -816,8 +1601,8 @@ <0 0 0 4 &intc 0 275 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&pcie1_clkreq_default &pcie1_perst_default &pcie1_wake_default>; - pinctrl-1 = <&pcie1_clkreq_sleep &pcie1_perst_default &pcie1_wake_sleep>; + pinctrl-0 = <&pcie1_state_on>; + pinctrl-1 = <&pcie1_state_off>; linux,pci-domain = <1>; @@ -867,8 +1652,8 @@ <0 0 0 4 &intc 0 145 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&pcie2_clkreq_default &pcie2_perst_default &pcie2_wake_default>; - pinctrl-1 = <&pcie2_clkreq_sleep &pcie2_perst_default &pcie2_wake_sleep >; + pinctrl-0 = <&pcie2_state_on>; + pinctrl-1 = <&pcie2_state_off>; linux,pci-domain = <2>; clocks = <&gcc GCC_PCIE_2_PIPE_CLK>, @@ -1152,7 +1937,7 @@ power-domains = <&mmcc GPU_GDSC>; }; - video-codec@c00000 { + venus: video-codec@c00000 { compatible = "qcom,msm8996-venus"; reg = <0x00c00000 0xff000>; interrupts = ; @@ -1183,7 +1968,7 @@ <&venus_smmu 0x2d>, <&venus_smmu 0x31>; memory-region = <&venus_region>; - status = "okay"; + status = "disabled"; video-decoder { compatible = "venus-decoder"; @@ -1745,9 +2530,14 @@ }; }; }; + kryocc: clock-controller@6400000 { - compatible = "qcom,apcc-msm8996"; + compatible = "qcom,msm8996-apcc"; reg = <0x06400000 0x90000>; + + clock-names = "xo"; + clocks = <&xo_board>; + #clock-cells = <1>; }; @@ -1758,6 +2548,10 @@ #size-cells = <1>; ranges; + interrupts = , + ; + interrupt-names = "hs_phy_irq", "ss_phy_irq"; + clocks = <&gcc GCC_SYS_NOC_USB3_AXI_CLK>, <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, @@ -1772,7 +2566,7 @@ power-domains = <&gcc USB30_GDSC>; status = "disabled"; - dwc3@6a00000 { + usb@6a00000 { compatible = "snps,dwc3"; reg = <0x06a00000 0xcc00>; interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>; @@ -1841,34 +2635,75 @@ status = "disabled"; }; + sdhc1: sdhci@7464900 { + compatible = "qcom,sdhci-msm-v4"; + reg = <0x07464900 0x11c>, <0x07464000 0x800>; + reg-names = "hc_mem", "core_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + clock-names = "iface", "core", "xo"; + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&xo_board>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc1_state_on>; + pinctrl-1 = <&sdc1_state_off>; + + bus-width = <8>; + non-removable; + status = "disabled"; + }; + sdhc2: sdhci@74a4900 { - status = "disabled"; - compatible = "qcom,sdhci-msm-v4"; - reg = <0x074a4900 0x314>, <0x074a4000 0x800>; - reg-names = "hc_mem", "core_mem"; + compatible = "qcom,sdhci-msm-v4"; + reg = <0x074a4900 0x314>, <0x074a4000 0x800>; + reg-names = "hc_mem", "core_mem"; - interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>, - <0 221 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "hc_irq", "pwr_irq"; + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; - clock-names = "iface", "core", "xo"; - clocks = <&gcc GCC_SDCC2_AHB_CLK>, - <&gcc GCC_SDCC2_APPS_CLK>, - <&xo_board>; - bus-width = <4>; + clock-names = "iface", "core", "xo"; + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, + <&xo_board>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_state_on>; + pinctrl-1 = <&sdc2_state_off>; + + bus-width = <4>; + status = "disabled"; }; - blsp1_uart1: serial@7570000 { + blsp1_dma: dma@7544000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x07544000 0x2b000>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "bam_clk"; + qcom,controlled-remotely; + #dma-cells = <1>; + qcom,ee = <0>; + }; + + blsp1_uart2: serial@7570000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x07570000 0x1000>; interrupts = ; clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>; clock-names = "core", "iface"; + dmas = <&blsp1_dma 2>, <&blsp1_dma 3>; + dma-names = "tx", "rx"; status = "disabled"; }; - blsp1_spi0: spi@7575000 { + blsp1_spi1: spi@7575000 { compatible = "qcom,spi-qup-v2.2.1"; reg = <0x07575000 0x600>; interrupts = ; @@ -1876,14 +2711,16 @@ <&gcc GCC_BLSP1_AHB_CLK>; clock-names = "core", "iface"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp1_spi0_default>; - pinctrl-1 = <&blsp1_spi0_sleep>; + pinctrl-0 = <&blsp1_spi1_default>; + pinctrl-1 = <&blsp1_spi1_sleep>; + dmas = <&blsp1_dma 12>, <&blsp1_dma 13>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; - blsp1_i2c2: i2c@7577000 { + blsp1_i2c3: i2c@7577000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x07577000 0x1000>; interrupts = ; @@ -1891,14 +2728,27 @@ <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; clock-names = "iface", "core"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp1_i2c2_default>; - pinctrl-1 = <&blsp1_i2c2_sleep>; + pinctrl-0 = <&blsp1_i2c3_default>; + pinctrl-1 = <&blsp1_i2c3_sleep>; + dmas = <&blsp1_dma 16>, <&blsp1_dma 17>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; - blsp2_uart1: serial@75b0000 { + blsp2_dma: dma@7584000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x07584000 0x2b000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + qcom,controlled-remotely; + #dma-cells = <1>; + qcom,ee = <0>; + }; + + blsp2_uart2: serial@75b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x075b0000 0x1000>; interrupts = ; @@ -1908,7 +2758,7 @@ status = "disabled"; }; - blsp2_uart2: serial@75b1000 { + blsp2_uart3: serial@75b1000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x075b1000 0x1000>; interrupts = ; @@ -1918,7 +2768,7 @@ status = "disabled"; }; - blsp2_i2c0: i2c@75b5000 { + blsp2_i2c1: i2c@75b5000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x075b5000 0x1000>; interrupts = ; @@ -1926,14 +2776,16 @@ <&gcc GCC_BLSP2_QUP1_I2C_APPS_CLK>; clock-names = "iface", "core"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_i2c0_default>; - pinctrl-1 = <&blsp2_i2c0_sleep>; + pinctrl-0 = <&blsp2_i2c1_default>; + pinctrl-1 = <&blsp2_i2c1_sleep>; + dmas = <&blsp2_dma 12>, <&blsp2_dma 13>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; - blsp2_i2c1: i2c@75b6000 { + blsp2_i2c2: i2c@75b6000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x075b6000 0x1000>; interrupts = ; @@ -1941,14 +2793,49 @@ <&gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>; clock-names = "iface", "core"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_i2c1_default>; - pinctrl-1 = <&blsp2_i2c1_sleep>; + pinctrl-0 = <&blsp2_i2c2_default>; + pinctrl-1 = <&blsp2_i2c2_sleep>; + dmas = <&blsp2_dma 14>, <&blsp2_dma 15>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; - blsp2_spi5: spi@75ba000{ + blsp2_i2c5: i2c@75b9000 { + compatible = "qcom,i2c-qup-v2.2.1"; + reg = <0x75b9000 0x1000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>, + <&gcc GCC_BLSP2_QUP5_I2C_APPS_CLK>; + clock-names = "iface", "core"; + pinctrl-names = "default"; + pinctrl-0 = <&blsp2_i2c5_default>; + dmas = <&blsp2_dma 20>, <&blsp2_dma 21>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + blsp2_i2c6: i2c@75ba000 { + compatible = "qcom,i2c-qup-v2.2.1"; + reg = <0x75ba000 0x1000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>, + <&gcc GCC_BLSP2_QUP6_I2C_APPS_CLK>; + clock-names = "iface", "core"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&blsp2_i2c6_default>; + pinctrl-1 = <&blsp2_i2c6_sleep>; + dmas = <&blsp2_dma 22>, <&blsp2_dma 23>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + blsp2_spi6: spi@75ba000{ compatible = "qcom,spi-qup-v2.2.1"; reg = <0x075ba000 0x600>; interrupts = ; @@ -1956,8 +2843,10 @@ <&gcc GCC_BLSP2_AHB_CLK>; clock-names = "core", "iface"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&blsp2_spi5_default>; - pinctrl-1 = <&blsp2_spi5_sleep>; + pinctrl-0 = <&blsp2_spi6_default>; + pinctrl-1 = <&blsp2_spi6_sleep>; + dmas = <&blsp2_dma 22>, <&blsp2_dma 23>; + dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1981,14 +2870,16 @@ assigned-clock-rates = <19200000>, <60000000>; power-domains = <&gcc USB30_GDSC>; + qcom,select-utmi-as-pipe-clk; status = "disabled"; - dwc3@7600000 { + usb@7600000 { compatible = "snps,dwc3"; reg = <0x07600000 0xcc00>; interrupts = <0 138 IRQ_TYPE_LEVEL_HIGH>; phys = <&hsusb_phy2>; phy-names = "usb2-phy"; + maximum-speed = "high-speed"; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; }; @@ -2032,13 +2923,13 @@ compatible = "slim217,1a0"; reg = <1 0>; - interrupt-parent = <&msmgpio>; + interrupt-parent = <&tlmm>; interrupts = <54 IRQ_TYPE_LEVEL_HIGH>, <53 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "intr1", "intr2"; interrupt-controller; #interrupt-cells = <1>; - reset-gpios = <&msmgpio 64 0>; + reset-gpios = <&tlmm 64 0>; slim-ifc-dev = <&tasha_ifd>; @@ -2067,6 +2958,11 @@ qcom,smem-states = <&smp2p_adsp_out 0>; qcom,smem-state-names = "stop"; + power-domains = <&rpmpd MSM8996_VDDCX>; + power-domain-names = "cx"; + + status = "disabled"; + smd-edge { interrupts = ; @@ -2458,4 +3354,3 @@ ; }; }; -#include "msm8996-pins.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index e9d3ce29937c..6f294f9c0cdf 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -1964,7 +1964,7 @@ resets = <&gcc GCC_USB_30_BCR>; - usb3_dwc3: dwc3@a800000 { + usb3_dwc3: usb@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 8ab4f1f78bbf..8a4972e6a24c 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -7,6 +7,30 @@ #include #include +/ { + thermal-zones { + pm6150_thermal: pm6150-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm6150_temp>; + + trips { + pm6150_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6150_crit: crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; +}; + &spmi_bus { pm6150_lsid0: pmic@0 { compatible = "qcom,pm6150", "qcom,spmi-pmic"; diff --git a/arch/arm64/boot/dts/qcom/pm7325.dtsi b/arch/arm64/boot/dts/qcom/pm7325.dtsi new file mode 100644 index 000000000000..e7f64a9ddc9c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm7325.dtsi @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021, The Linux Foundation. All rights reserved. + +#include +#include + +&spmi_bus { + pm7325: pmic@1 { + compatible = "qcom,pm7325", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm7325_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pm7325_gpios: gpios@8800 { + compatible = "qcom,pm7325-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pm7325_gpios 0 0 10>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + +&thermal_zones { + pm7325_thermal: pm7325-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm7325_temp_alarm>; + + trips { + pm7325_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm7325_crit: pm7325-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8150.dtsi b/arch/arm64/boot/dts/qcom/pm8150.dtsi index fa4ea7ded0ab..c566a64b1373 100644 --- a/arch/arm64/boot/dts/qcom/pm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150.dtsi @@ -50,7 +50,8 @@ pon: power-on@800 { compatible = "qcom,pm8916-pon"; reg = <0x0800>; - pwrkey { + + pon_pwrkey: pwrkey { compatible = "qcom,pm8941-pwrkey"; interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>; debounce = <15625>; @@ -59,6 +60,15 @@ status = "disabled"; }; + + pon_resin: resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + + status = "disabled"; + }; }; pm8150_temp: temp-alarm@2400 { diff --git a/arch/arm64/boot/dts/qcom/pm8350c.dtsi b/arch/arm64/boot/dts/qcom/pm8350c.dtsi index 2b9b75ecec60..e1b75ae0a823 100644 --- a/arch/arm64/boot/dts/qcom/pm8350c.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8350c.dtsi @@ -13,13 +13,43 @@ #address-cells = <1>; #size-cells = <0>; + pm8350c_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x2 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + pm8350c_gpios: gpio@8800 { - compatible = "qcom,pm8350c-gpio"; + compatible = "qcom,pm8350c-gpio", "qcom,spmi-gpio"; reg = <0x8800>; gpio-controller; + gpio-ranges = <&pm8350c_gpios 0 0 9>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; }; }; }; + +&thermal_zones { + pm8350c_thermal: pm8350c-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8350c_temp_alarm>; + + trips { + pm8350c_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm8350c_crit: pm8350c-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8994.dtsi b/arch/arm64/boot/dts/qcom/pm8994.dtsi index c3876c82c874..ad19016df047 100644 --- a/arch/arm64/boot/dts/qcom/pm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8994.dtsi @@ -45,7 +45,6 @@ pm8994_pon: pon@800 { compatible = "qcom,pm8916-pon"; - reg = <0x800>; mode-bootloader = <0x2>; mode-recovery = <0x1>; @@ -58,6 +57,13 @@ linux,code = ; }; + pm8994_resin: resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + status = "disabled"; + }; }; pm8994_temp: temp-alarm@2400 { diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi index e5ed28ab9b2d..b4ac900ab115 100644 --- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi @@ -32,5 +32,18 @@ #address-cells = <1>; #size-cells = <1>; }; + + pmi8994_wled: wled@d800 { + compatible = "qcom,pmi8994-wled"; + reg = <0xd800 0xd900>; + interrupts = <3 0xd8 0x02 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "short"; + qcom,num-strings = <3>; + /* Yes, all four strings *have to* be defined or things won't work. */ + qcom,enabled-strings = <0 1 2 3>; + qcom,cabc; + qcom,eternal-pfet; + status = "disabled"; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi index 1530b8ff270f..04fc2632a0b2 100644 --- a/arch/arm64/boot/dts/qcom/pmk8350.dtsi +++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi @@ -3,6 +3,8 @@ * Copyright (c) 2021, Linaro Limited */ +#include +#include #include #include @@ -13,10 +15,57 @@ #address-cells = <1>; #size-cells = <0>; + pmk8350_pon: pon@1300 { + compatible = "qcom,pm8998-pon"; + reg = <0x1300>; + + pwrkey { + compatible = "qcom,pmk8350-pwrkey"; + interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_BOTH>; + linux,code = ; + }; + + resin { + compatible = "qcom,pmk8350-resin"; + interrupts = <0x0 0x13 0x6 IRQ_TYPE_EDGE_BOTH>; + linux,code = ; + }; + }; + + pmk8350_vadc: adc@3100 { + compatible = "qcom,spmi-adc7"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + #io-channel-cells = <1>; + io-channel-ranges; + }; + + pmk8350_adc_tm: adc-tm@3400 { + compatible = "qcom,adc-tm7"; + reg = <0x3400>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "threshold"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; + + pmk8350_rtc: rtc@6100 { + compatible = "qcom,pmk8350-rtc"; + reg = <0x6100>, <0x6200>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x62 0x1 IRQ_TYPE_EDGE_RISING>; + }; + pmk8350_gpios: gpio@b000 { - compatible = "qcom,pmk8350-gpio"; + compatible = "qcom,pmk8350-gpio", "qcom,spmi-gpio"; reg = <0xb000>; gpio-controller; + gpio-ranges = <&pmk8350_gpios 0 0 4>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm64/boot/dts/qcom/pmm8155au_1.dtsi b/arch/arm64/boot/dts/qcom/pmm8155au_1.dtsi new file mode 100644 index 000000000000..7072e5a2e73f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmm8155au_1.dtsi @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include +#include +#include +#include + +/ { + thermal-zones { + pmm8155au-1-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + + thermal-sensors = <&pmm8155au_1_temp>; + + trips { + trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "hot"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; +}; + +&spmi_bus { + pmic@0 { + compatible = "qcom,pmm8155au", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon: power-on@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + + status = "disabled"; + }; + }; + + pmm8155au_1_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pmm8155au_1_adc ADC5_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pmm8155au_1_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + ref-gnd@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + vref-1p25@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + die-temp@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + }; + + pmm8155au_1_adc_tm: adc-tm@3500 { + compatible = "qcom,spmi-adc-tm5"; + reg = <0x3500>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + pmm8155au_1_rtc: rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + + status = "disabled"; + }; + + pmm8155au_1_gpios: gpio@c000 { + compatible = "qcom,pmm8155au-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pmm8155au_1_gpios 0 0 10>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmic@1 { + compatible = "qcom,pmm8155au", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmm8155au_2.dtsi b/arch/arm64/boot/dts/qcom/pmm8155au_2.dtsi new file mode 100644 index 000000000000..72075964fbb9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmm8155au_2.dtsi @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include +#include +#include + +/ { + thermal-zones { + pmm8155au-2-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + + thermal-sensors = <&pmm8155au_2_temp>; + + trips { + trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "hot"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; +}; + +&spmi_bus { + pmic@4 { + compatible = "qcom,pmm8155au", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + power-on@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + + status = "disabled"; + }; + + pmm8155au_2_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pmm8155au_2_adc ADC5_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pmm8155au_2_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x4 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + ref-gnd@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + vref-1p25@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + die-temp@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + }; + + pmm8155au_2_gpios: gpio@c000 { + compatible = "qcom,pmm8155au-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pmm8155au_2_gpios 0 0 10>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmic@5 { + compatible = "qcom,pmm8155au", "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmr735a.dtsi b/arch/arm64/boot/dts/qcom/pmr735a.dtsi index 1c675af13cbf..b4b6ba24f845 100644 --- a/arch/arm64/boot/dts/qcom/pmr735a.dtsi +++ b/arch/arm64/boot/dts/qcom/pmr735a.dtsi @@ -13,13 +13,43 @@ #address-cells = <1>; #size-cells = <0>; + pmr735a_temp_alarm: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x4 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + pmr735a_gpios: gpio@8800 { - compatible = "qcom,pmr735a-gpio"; + compatible = "qcom,pmr735a-gpio", "qcom,spmi-gpio"; reg = <0x8800>; gpio-controller; + gpio-ranges = <&pmr735a_gpios 0 0 4>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; }; }; }; + +&thermal_zones { + pmr735a_thermal: pmr735a-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pmr735a_temp_alarm>; + + trips { + pmr735a_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pmr735a_crit: pmr735a-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi index a80c578484ba..f8a55307b855 100644 --- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi @@ -337,7 +337,7 @@ &usb3 { status = "okay"; - dwc3@7580000 { + usb@7580000 { dr_mode = "host"; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index 339790ba585d..9c4be020d568 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -544,7 +544,7 @@ assigned-clock-rates = <19200000>, <200000000>; status = "disabled"; - dwc3@7580000 { + usb@7580000 { compatible = "snps,dwc3"; reg = <0x07580000 0xcd00>; interrupts = ; @@ -573,7 +573,7 @@ assigned-clock-rates = <19200000>, <133333333>; status = "disabled"; - dwc3@78c0000 { + usb@78c0000 { compatible = "snps,dwc3"; reg = <0x078c0000 0xcc00>; interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 5f41de20aa22..8ac96f8e79d4 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -5,7 +5,6 @@ /dts-v1/; -#include #include #include #include @@ -552,7 +551,13 @@ vdds-supply = <&vreg_l5a_0p88>; }; +&gmu { + status = "okay"; +}; + &gpu { + status = "okay"; + zap-shader { memory-region = <&gpu_mem>; firmware-name = "qcom/sm8250/a650_zap.mbn"; @@ -664,10 +669,6 @@ &pcie0 { status = "okay"; - perst-gpio = <&tlmm 79 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 81 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pcie0_default_state>; }; &pcie0_phy { @@ -678,10 +679,6 @@ &pcie1 { status = "okay"; - perst-gpio = <&tlmm 82 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 84 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pcie1_default_state>; }; &pcie1_phy { @@ -692,10 +689,6 @@ &pcie2 { status = "okay"; - perst-gpio = <&tlmm 85 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 87 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pcie2_default_state>; }; &pcie2_phy { @@ -1173,81 +1166,6 @@ bias-disable; }; - pcie0_default_state: pcie0-default { - clkreq { - pins = "gpio80"; - function = "pci_e0"; - bias-pull-up; - }; - - reset-n { - pins = "gpio79"; - function = "gpio"; - - drive-strength = <2>; - output-low; - bias-pull-down; - }; - - wake-n { - pins = "gpio81"; - function = "gpio"; - - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie1_default_state: pcie1-default { - clkreq { - pins = "gpio83"; - function = "pci_e1"; - bias-pull-up; - }; - - reset-n { - pins = "gpio82"; - function = "gpio"; - - drive-strength = <2>; - output-low; - bias-pull-down; - }; - - wake-n { - pins = "gpio84"; - function = "gpio"; - - drive-strength = <2>; - bias-pull-up; - }; - }; - - pcie2_default_state: pcie2-default { - clkreq { - pins = "gpio86"; - function = "pci_e2"; - bias-pull-up; - }; - - reset-n { - pins = "gpio85"; - function = "gpio"; - - drive-strength = <2>; - output-low; - bias-pull-down; - }; - - wake-n { - pins = "gpio87"; - function = "gpio"; - - drive-strength = <2>; - bias-pull-up; - }; - }; - sdc2_default_state: sdc2-default { clk { pins = "sdc2_clk"; @@ -1352,6 +1270,10 @@ qcom,dmic-sample-rate = <600000>; }; +&venus { + status = "okay"; +}; + /* PINCTRL - additions to nodes defined in sm8250.dtsi */ &qup_spi0_cs_gpio { drive-strength = <6>; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts new file mode 100644 index 000000000000..0da7a3b8d1bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Linaro Limited + */ + +/dts-v1/; + +#include +#include +#include "sm8150.dtsi" +#include "pmm8155au_1.dtsi" +#include "pmm8155au_2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P ADP"; + compatible = "qcom,sa8155p-adp", "qcom,sa8155p"; + + aliases { + serial0 = &uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vreg_3p3: vreg_3p3_regulator { + compatible = "regulator-fixed"; + regulator-name = "vreg_3p3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + /* + * S4A is always on and not controllable through RPMh. + * So model it as a fixed regulator. + */ + vreg_s4a_1p8: smps4 { + compatible = "regulator-fixed"; + regulator-name = "vreg_s4a_1p8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-always-on; + regulator-boot-on; + regulator-allow-set-load; + + vin-supply = <&vreg_3p3>; + }; +}; + +&apps_rsc { + pmm8155au-1-rpmh-regulators { + compatible = "qcom,pmm8155au-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-s1-supply = <&vreg_3p3>; + vdd-s2-supply = <&vreg_3p3>; + vdd-s3-supply = <&vreg_3p3>; + vdd-s4-supply = <&vreg_3p3>; + vdd-s5-supply = <&vreg_3p3>; + vdd-s6-supply = <&vreg_3p3>; + vdd-s7-supply = <&vreg_3p3>; + vdd-s8-supply = <&vreg_3p3>; + vdd-s9-supply = <&vreg_3p3>; + vdd-s10-supply = <&vreg_3p3>; + + vdd-l1-l8-l11-supply = <&vreg_s6a_0p92>; + vdd-l2-l10-supply = <&vreg_3p3>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p92>; + vdd-l6-l9-supply = <&vreg_s6a_0p92>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p04>; + vdd-l13-l16-l17-supply = <&vreg_3p3>; + + vreg_s5a_2p04: smps5 { + regulator-name = "vreg_s5a_2p04"; + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_s6a_0p92: smps6 { + regulator-name = "vreg_s6a_0p92"; + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <1128000>; + }; + + vreg_l1a_0p752: ldo1 { + regulator-name = "vreg_l1a_0p752"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + regulator-initial-mode = ; + }; + + vdda_usb_hs_3p1: + vreg_l2a_3p072: ldo2 { + regulator-name = "vreg_l2a_3p072"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p8: ldo3 { + regulator-name = "vreg_l3a_0p8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vdd_usb_hs_core: + vdda_usb_ss_dp_core_1: + vreg_l5a_0p88: ldo5 { + regulator-name = "vreg_l5a_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l7a_1p8: ldo7 { + regulator-name = "vreg_l7a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l10a_2p96: ldo10 { + regulator-name = "vreg_l10a_2p96"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l11a_0p8: ldo11 { + regulator-name = "vreg_l11a_0p8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vdda_usb_hs_1p8: + vreg_l12a_1p8: ldo12 { + regulator-name = "vreg_l12a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l13a_2p7: ldo13 { + regulator-name = "vreg_l13a_2p7"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p7: ldo15 { + regulator-name = "vreg_l15a_1p7"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-name = "vreg_l16a_2p7"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l17a_2p96: ldo17 { + regulator-name = "vreg_l17a_2p96"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + }; + + pmm8155au-2-rpmh-regulators { + compatible = "qcom,pmm8155au-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vreg_3p3>; + vdd-s2-supply = <&vreg_3p3>; + vdd-s3-supply = <&vreg_3p3>; + vdd-s4-supply = <&vreg_3p3>; + vdd-s5-supply = <&vreg_3p3>; + vdd-s6-supply = <&vreg_3p3>; + vdd-s7-supply = <&vreg_3p3>; + vdd-s8-supply = <&vreg_3p3>; + vdd-s9-supply = <&vreg_3p3>; + vdd-s10-supply = <&vreg_3p3>; + + vdd-l1-l8-l11-supply = <&vreg_s4c_1p352>; + vdd-l2-l10-supply = <&vreg_3p3>; + vdd-l3-l4-l5-l18-supply = <&vreg_s4c_1p352>; + vdd-l6-l9-supply = <&vreg_s6c_1p128>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5c_2p04>; + vdd-l13-l16-l17-supply = <&vreg_3p3>; + + vreg_s4c_1p352: smps4 { + regulator-name = "vreg_s4c_1p352"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + }; + + vreg_s5c_2p04: smps5 { + regulator-name = "vreg_s5c_2p04"; + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_s6c_1p128: smps6 { + regulator-name = "vreg_s6c_1p128"; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + }; + + vreg_l1c_1p304: ldo1 { + regulator-name = "vreg_l1c_1p304"; + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p808: ldo2 { + regulator-name = "vreg_l2c_1p808"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p2: ldo5 { + regulator-name = "vreg_l5c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l7c_1p8: ldo7 { + regulator-name = "vreg_l7c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p2: ldo8 { + regulator-name = "vreg_l8c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l10c_3p3: ldo10 { + regulator-name = "vreg_l10c_3p3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_0p8: ldo11 { + regulator-name = "vreg_l11c_0p8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vreg_l12c_1p808: ldo12 { + regulator-name = "vreg_l12c_1p808"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vreg_l13c_2p96: ldo13 { + regulator-name = "vreg_l13c_2p96"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l15c_1p9: ldo15 { + regulator-name = "vreg_l15c_1p9"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vreg_l16c_3p008: ldo16 { + regulator-name = "vreg_l16c_3p008"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l18c_0p88: ldo18 { + regulator-name = "vreg_l18c_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + }; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>; +}; + +&uart2 { + status = "okay"; +}; + +&ufs_mem_hc { + status = "okay"; + + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l10a_2p96>; + vcc-max-microamp = <750000>; + vccq-supply = <&vreg_l5c_1p2>; + vccq-max-microamp = <700000>; + vccq2-supply = <&vreg_s4a_1p8>; + vccq2-max-microamp = <750000>; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l8c_1p2>; + vdda-max-microamp = <87100>; + vdda-pll-supply = <&vreg_l5a_0p88>; + vdda-pll-max-microamp = <18300>; +}; + + +&usb_1_hsphy { + status = "okay"; + vdda-pll-supply = <&vdd_usb_hs_core>; + vdda33-supply = <&vdda_usb_hs_3p1>; + vdda18-supply = <&vdda_usb_hs_1p8>; +}; + +&usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l8c_1p2>; + vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-idp.dts b/arch/arm64/boot/dts/qcom/sc7180-idp.dts index e77a7926034a..acdb36f4479f 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-idp.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-idp.dts @@ -9,6 +9,7 @@ #include #include +#include #include "sc7180.dtsi" #include "pm6150.dtsi" #include "pm6150l.dtsi" @@ -45,7 +46,7 @@ /* Increase the size from 2MB to 8MB */ &rmtfs_mem { - reg = <0x0 0x84400000 0x0 0x800000>; + reg = <0x0 0x94600000 0x0 0x800000>; }; / { @@ -288,6 +289,57 @@ }; }; +&dsi0 { + status = "okay"; + + vdda-supply = <&vreg_l3c_1p2>; + + panel@0 { + compatible = "visionox,rm69299-1080p-display"; + reg = <0>; + + vdda-supply = <&vreg_l8c_1p8>; + vdd3p3-supply = <&vreg_l18a_2p8>; + + pinctrl-names = "default"; + pinctrl-0 = <&disp_pins>; + + reset-gpios = <&pm6150l_gpio 3 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + panel0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + + ports { + port@1 { + endpoint { + remote-endpoint = <&panel0_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +&dsi_phy { + status = "okay"; +}; + +&mdp { + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + &qfprom { vcc-supply = <&vreg_l11a_1p8>; }; @@ -414,6 +466,19 @@ /* PINCTRL - additions to nodes defined in sc7180.dtsi */ +&pm6150l_gpio { + disp_pins: disp-pins { + pinconf { + pins = "gpio3"; + function = PMIC_GPIO_FUNC_FUNC1; + qcom,drive-strength = ; + power-source = <0>; + bias-disable; + output-low; + }; + }; +}; + &qspi_clk { pinconf { pins = "gpio63"; @@ -598,4 +663,106 @@ bias-pull-up; }; }; + + sdc1_on: sdc1-on { + pinconf-clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <16>; + }; + + pinconf-cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc1_off: sdc1-off { + pinconf-clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <2>; + }; + + pinconf-cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc2_on: sdc2-on { + pinconf-clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <16>; + }; + + pinconf-cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-sd-cd { + pins = "gpio69"; + bias-pull-up; + drive-strength = <2>; + }; + }; + + sdc2_off: sdc2-off { + pinconf-clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <2>; + }; + + pinconf-cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-sd-cd { + pins = "gpio69"; + bias-pull-up; + drive-strength = <2>; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts index 533c048903ea..82dc00cc7fb9 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1-lte.dts @@ -9,8 +9,8 @@ #include "sc7180-trogdor-lte-sku.dtsi" / { - model = "Google CoachZ (rev1) with LTE"; - compatible = "google,coachz-rev1-sku0", "qcom,sc7180"; + model = "Google CoachZ (rev1 - 2) with LTE"; + compatible = "google,coachz-rev1-sku0", "google,coachz-rev2-sku0", "qcom,sc7180"; }; &cros_ec_proximity { diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts index 1b1dbdb2a82f..21b516e0694a 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r1.dts @@ -10,8 +10,26 @@ #include "sc7180-trogdor-coachz.dtsi" / { - model = "Google CoachZ (rev1)"; - compatible = "google,coachz-rev1", "qcom,sc7180"; + model = "Google CoachZ (rev1 - 2)"; + compatible = "google,coachz-rev1", "google,coachz-rev2", "qcom,sc7180"; +}; + +/* + * CoachZ rev1 is stuffed with a 47k NTC as charger thermistor which currently + * is not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; + +/* + * CoachZ rev1 is stuffed with a 47k NTC as thermistor for skin temperature, + * which currently is not supported by the PM6150 ADC driver. Disable the + * skin temperature thermal zone to avoid using bogus temperature values. + */ +&skin_temp_thermal { + status = "disabled"; }; &tlmm { diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3-lte.dts similarity index 69% rename from arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts rename to arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3-lte.dts index 6e7745801fae..d23409034e8c 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2-lte.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3-lte.dts @@ -2,14 +2,14 @@ /* * Google CoachZ board device tree source * - * Copyright 2020 Google LLC. + * Copyright 2021 Google LLC. */ -#include "sc7180-trogdor-coachz-r2.dts" +#include "sc7180-trogdor-coachz-r3.dts" #include "sc7180-trogdor-lte-sku.dtsi" / { - model = "Google CoachZ (rev2+) with LTE"; + model = "Google CoachZ (rev3+) with LTE"; compatible = "google,coachz-sku0", "qcom,sc7180"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3.dts similarity index 75% rename from arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts rename to arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3.dts index 4f69b6ba299f..a02d2d57c78c 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r2.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz-r3.dts @@ -2,7 +2,7 @@ /* * Google CoachZ board device tree source * - * Copyright 2020 Google LLC. + * Copyright 2021 Google LLC. */ /dts-v1/; @@ -10,6 +10,6 @@ #include "sc7180-trogdor-coachz.dtsi" / { - model = "Google CoachZ (rev2+)"; + model = "Google CoachZ (rev3+)"; compatible = "google,coachz", "qcom,sc7180"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi index 4c6e433c8226..6f9c07147551 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi @@ -23,8 +23,53 @@ ap_h1_spi: &spi0 {}; adau7002: audio-codec-1 { compatible = "adi,adau7002"; IOVDD-supply = <&pp1800_l15a>; + wakeup-delay-ms = <15>; #sound-dai-cells = <0>; }; + + thermal-zones { + skin_temp_thermal: skin-temp-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&pm6150_adc_tm 1>; + sustainable-power = <814>; + + trips { + skin_temp_alert0: trip-point0 { + temperature = <42000>; + hysteresis = <1000>; + type = "passive"; + }; + + skin_temp_alert1: trip-point1 { + temperature = <45000>; + hysteresis = <1000>; + type = "passive"; + }; + + skin-temp-crit { + temperature = <60000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&skin_temp_alert0>; + cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + + map1 { + trip = <&skin_temp_alert1>; + cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; }; &ap_spi_fp { @@ -77,6 +122,25 @@ ap_ts_pen_1v8: &i2c4 { compatible = "boe,nv110wtm-n61"; }; +&pm6150_adc { + skin-temp-thermistor@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm6150_adc_tm { + status = "okay"; + + skin-temp-thermistor@1 { + reg = <1>; + io-channels = <&pm6150_adc ADC5_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + &pp3300_dx_edp { gpio = <&tlmm 67 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts index 5c997cd90069..30e3e769d2b4 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r0.dts @@ -14,15 +14,6 @@ compatible = "google,lazor-rev0", "qcom,sc7180"; }; -/* - * Lazor is stuffed with a 47k NTC as charger thermistor which currently is - * not supported by the PM6150 ADC driver. Disable the charger thermal zone - * to avoid using bogus temperature values. - */ -&charger_thermal { - status = "disabled"; -}; - &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts index d9fbcc7bc5bd..c2ef06367baf 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r1.dts @@ -14,15 +14,6 @@ compatible = "google,lazor-rev1", "google,lazor-rev2", "qcom,sc7180"; }; -/* - * Lazor is stuffed with a 47k NTC as charger thermistor which currently is - * not supported by the PM6150 ADC driver. Disable the charger thermal zone - * to avoid using bogus temperature values. - */ -&charger_thermal { - status = "disabled"; -}; - &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts index ea8c2ee09741..b474df47cd70 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor-r3.dts @@ -14,12 +14,3 @@ model = "Google Lazor (rev3+)"; compatible = "google,lazor", "qcom,sc7180"; }; - -/* - * Lazor is stuffed with a 47k NTC as charger thermistor which currently is - * not supported by the PM6150 ADC driver. Disable the charger thermal zone - * to avoid using bogus temperature values. - */ -&charger_thermal { - status = "disabled"; -}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi index 6b10b96173e8..00535aaa43c9 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi @@ -21,6 +21,15 @@ ap_h1_spi: &spi0 {}; semtech,avg-pos-strength = <64>; }; +/* + * Lazor is stuffed with a 47k NTC as charger thermistor which currently is + * not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; + ap_ts_pen_1v8: &i2c4 { status = "okay"; clock-frequency = <400000>; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts index e720e7bd0d70..e122a6b481ff 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r1.dts @@ -9,11 +9,23 @@ #include "sc7180-trogdor-pompom.dtsi" +/delete-node/ &keyboard_controller; +#include + / { model = "Google Pompom (rev1)"; compatible = "google,pompom-rev1", "qcom,sc7180"; }; +/* + * Pompom rev1 is stuffed with a 47k NTC as charger thermistor which currently + * is not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; +}; + &pp3300_hub { /* pp3300_l7c is used to power the USB hub */ /delete-property/regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts index 791d496ad046..00e187c08eb9 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2-lte.dts @@ -9,6 +9,6 @@ #include "sc7180-trogdor-lte-sku.dtsi" / { - model = "Google Pompom (rev2+) with LTE"; - compatible = "google,pompom-sku0", "qcom,sc7180"; + model = "Google Pompom (rev2) with LTE"; + compatible = "google,pompom-rev2-sku0", "qcom,sc7180"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts index 984d7337da78..4f32e6733f4c 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r2.dts @@ -10,35 +10,15 @@ #include "sc7180-trogdor-pompom.dtsi" / { - model = "Google Pompom (rev2+)"; - compatible = "google,pompom", "qcom,sc7180"; + model = "Google Pompom (rev2)"; + compatible = "google,pompom-rev2", "qcom,sc7180"; }; -&keyboard_controller { - function-row-physmap = < - MATRIX_KEY(0x00, 0x02, 0) /* T1 */ - MATRIX_KEY(0x03, 0x02, 0) /* T2 */ - MATRIX_KEY(0x02, 0x02, 0) /* T3 */ - MATRIX_KEY(0x01, 0x02, 0) /* T4 */ - MATRIX_KEY(0x03, 0x04, 0) /* T5 */ - MATRIX_KEY(0x02, 0x04, 0) /* T6 */ - MATRIX_KEY(0x01, 0x04, 0) /* T7 */ - MATRIX_KEY(0x02, 0x09, 0) /* T8 */ - MATRIX_KEY(0x01, 0x09, 0) /* T9 */ - MATRIX_KEY(0x00, 0x04, 0) /* T10 */ - >; - linux,keymap = < - MATRIX_KEY(0x00, 0x02, KEY_BACK) - MATRIX_KEY(0x03, 0x02, KEY_REFRESH) - MATRIX_KEY(0x02, 0x02, KEY_ZOOM) - MATRIX_KEY(0x01, 0x02, KEY_SCALE) - MATRIX_KEY(0x03, 0x04, KEY_SYSRQ) - MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN) - MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP) - MATRIX_KEY(0x02, 0x09, KEY_MUTE) - MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN) - MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP) - - CROS_STD_MAIN_KEYMAP - >; +/* + * Pompom rev2 is stuffed with a 47k NTC as charger thermistor which currently + * is not supported by the PM6150 ADC driver. Disable the charger thermal zone + * to avoid using bogus temperature values. + */ +&charger_thermal { + status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3-lte.dts new file mode 100644 index 000000000000..e90b73c353bb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3-lte.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2021 Google LLC. + */ + +#include "sc7180-trogdor-pompom-r3.dts" +#include "sc7180-trogdor-lte-sku.dtsi" + +/ { + model = "Google Pompom (rev3+) with LTE"; + compatible = "google,pompom-sku0", "qcom,sc7180"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3.dts new file mode 100644 index 000000000000..f8aac63a53ef --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom-r3.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Google Pompom board device tree source + * + * Copyright 2021 Google LLC. + */ + +/dts-v1/; + +#include "sc7180-trogdor-pompom.dtsi" + +/ { + model = "Google Pompom (rev3+)"; + compatible = "google,pompom", "qcom,sc7180"; +}; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi index 622b5f1b88a2..a246dbd74cc1 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi @@ -107,6 +107,35 @@ ap_ts_pen_1v8: &i2c4 { }; }; +&keyboard_controller { + function-row-physmap = < + MATRIX_KEY(0x00, 0x02, 0) /* T1 */ + MATRIX_KEY(0x03, 0x02, 0) /* T2 */ + MATRIX_KEY(0x02, 0x02, 0) /* T3 */ + MATRIX_KEY(0x01, 0x02, 0) /* T4 */ + MATRIX_KEY(0x03, 0x04, 0) /* T5 */ + MATRIX_KEY(0x02, 0x04, 0) /* T6 */ + MATRIX_KEY(0x01, 0x04, 0) /* T7 */ + MATRIX_KEY(0x02, 0x09, 0) /* T8 */ + MATRIX_KEY(0x01, 0x09, 0) /* T9 */ + MATRIX_KEY(0x00, 0x04, 0) /* T10 */ + >; + linux,keymap = < + MATRIX_KEY(0x00, 0x02, KEY_BACK) + MATRIX_KEY(0x03, 0x02, KEY_REFRESH) + MATRIX_KEY(0x02, 0x02, KEY_ZOOM) + MATRIX_KEY(0x01, 0x02, KEY_SCALE) + MATRIX_KEY(0x03, 0x04, KEY_SYSRQ) + MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN) + MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP) + MATRIX_KEY(0x02, 0x09, KEY_MUTE) + MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN) + MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP) + + CROS_STD_MAIN_KEYMAP + >; +}; + &panel { compatible = "kingdisplay,kd116n21-30nv-a010"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi index 24d293ef56d7..77ae7561d436 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi @@ -64,11 +64,6 @@ no-map; }; - camera_mem: memory@8ec00000 { - reg = <0x0 0x8ec00000 0x0 0x500000>; - no-map; - }; - venus_mem: memory@8f600000 { reg = <0 0x8f600000 0 0x500000>; no-map; @@ -335,8 +330,7 @@ compatible = "jedec,spi-nor"; reg = <0>; - /* TODO: Increase frequency after testing */ - spi-max-frequency = <25000000>; + spi-max-frequency = <37500000>; spi-tx-bus-width = <2>; spi-rx-bus-width = <2>; }; @@ -564,10 +558,6 @@ #size-cells = <0>; }; - pdupdate { - compatible = "google,cros-ec-pd-update"; - }; - typec { compatible = "google,cros-ec-typec"; #address-cells = <1>; @@ -655,6 +645,8 @@ edp_brij_i2c: &i2c2 { clocks = <&rpmhcc RPMH_LN_BB_CLK3>; clock-names = "refclk"; + no-hpd; + ports { #address-cells = <1>; #size-cells = <0>; @@ -772,7 +764,7 @@ hp_i2c: &i2c9 { qcom,capture-sd-lines = <0>; }; - mi2s@1 { + secondary_mi2s: mi2s@1 { reg = ; qcom,playback-sd-lines = <0>; }; @@ -805,7 +797,7 @@ hp_i2c: &i2c9 { }; }; -&pm6150_pwrkey { +&pm6150_pon { status = "disabled"; }; @@ -981,6 +973,7 @@ ap_spi_fp: &spi10 { &qspi_clk { pinconf { pins = "gpio63"; + drive-strength = <8>; bias-disable; }; }; @@ -1494,4 +1487,106 @@ ap_spi_fp: &spi10 { drive-strength = <2>; }; }; + + sdc1_on: sdc1-on { + pinconf-clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <16>; + }; + + pinconf-cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc1_off: sdc1-off { + pinconf-clk { + pins = "sdc1_clk"; + bias-disable; + drive-strength = <2>; + }; + + pinconf-cmd { + pins = "sdc1_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-data { + pins = "sdc1_data"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-rclk { + pins = "sdc1_rclk"; + bias-pull-down; + }; + }; + + sdc2_on: sdc2-on { + pinconf-clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <16>; + }; + + pinconf-cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <10>; + }; + + pinconf-sd-cd { + pins = "gpio69"; + bias-pull-up; + drive-strength = <2>; + }; + }; + + sdc2_off: sdc2-off { + pinconf-clk { + pins = "sdc2_clk"; + bias-disable; + drive-strength = <2>; + }; + + pinconf-cmd { + pins = "sdc2_cmd"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-data { + pins = "sdc2_data"; + bias-pull-up; + drive-strength = <2>; + }; + + pinconf-sd-cd { + pins = "gpio69"; + bias-pull-up; + drive-strength = <2>; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 6228ba2d8513..a5d58eb92896 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -701,8 +701,9 @@ interrupt-names = "hc_irq", "pwr_irq"; clocks = <&gcc GCC_SDCC1_APPS_CLK>, - <&gcc GCC_SDCC1_AHB_CLK>; - clock-names = "core", "iface"; + <&gcc GCC_SDCC1_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "core", "iface", "xo"; interconnects = <&aggre1_noc MASTER_EMMC 0 &mc_virt SLAVE_EBI1 0>, <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_EMMC_CFG 0>; interconnect-names = "sdhc-ddr","cpu-sdhc"; @@ -726,15 +727,15 @@ opp-100000000 { opp-hz = /bits/ 64 <100000000>; required-opps = <&rpmhpd_opp_low_svs>; - opp-peak-kBps = <100000 100000>; - opp-avg-kBps = <100000 50000>; + opp-peak-kBps = <1800000 600000>; + opp-avg-kBps = <100000 0>; }; opp-384000000 { opp-hz = /bits/ 64 <384000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - opp-peak-kBps = <600000 900000>; - opp-avg-kBps = <261438 300000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <5400000 1600000>; + opp-avg-kBps = <390000 0>; }; }; }; @@ -768,8 +769,6 @@ #size-cells = <2>; ranges; iommus = <&apps_smmu 0x43 0x0>; - interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>; - interconnect-names = "qup-core"; status = "disabled"; i2c0: i2c@880000 { @@ -1059,8 +1058,6 @@ #size-cells = <2>; ranges; iommus = <&apps_smmu 0x4c3 0x0>; - interconnects = <&qup_virt MASTER_QUP_CORE_1 0 &qup_virt SLAVE_QUP_CORE_1 0>; - interconnect-names = "qup-core"; status = "disabled"; i2c6: i2c@a80000 { @@ -1871,108 +1868,6 @@ function = "lpass_ext"; }; }; - - sdc1_on: sdc1-on { - pinconf-clk { - pins = "sdc1_clk"; - bias-disable; - drive-strength = <16>; - }; - - pinconf-cmd { - pins = "sdc1_cmd"; - bias-pull-up; - drive-strength = <10>; - }; - - pinconf-data { - pins = "sdc1_data"; - bias-pull-up; - drive-strength = <10>; - }; - - pinconf-rclk { - pins = "sdc1_rclk"; - bias-pull-down; - }; - }; - - sdc1_off: sdc1-off { - pinconf-clk { - pins = "sdc1_clk"; - bias-disable; - drive-strength = <2>; - }; - - pinconf-cmd { - pins = "sdc1_cmd"; - bias-pull-up; - drive-strength = <2>; - }; - - pinconf-data { - pins = "sdc1_data"; - bias-pull-up; - drive-strength = <2>; - }; - - pinconf-rclk { - pins = "sdc1_rclk"; - bias-pull-down; - }; - }; - - sdc2_on: sdc2-on { - pinconf-clk { - pins = "sdc2_clk"; - bias-disable; - drive-strength = <16>; - }; - - pinconf-cmd { - pins = "sdc2_cmd"; - bias-pull-up; - drive-strength = <10>; - }; - - pinconf-data { - pins = "sdc2_data"; - bias-pull-up; - drive-strength = <10>; - }; - - pinconf-sd-cd { - pins = "gpio69"; - bias-pull-up; - drive-strength = <2>; - }; - }; - - sdc2_off: sdc2-off { - pinconf-clk { - pins = "sdc2_clk"; - bias-disable; - drive-strength = <2>; - }; - - pinconf-cmd { - pins = "sdc2_cmd"; - bias-pull-up; - drive-strength = <2>; - }; - - pinconf-data { - pins = "sdc2_data"; - bias-pull-up; - drive-strength = <2>; - }; - - pinconf-sd-cd { - pins = "gpio69"; - bias-disable; - drive-strength = <2>; - }; - }; }; remoteproc_mpss: remoteproc@4080000 { @@ -2670,8 +2565,9 @@ interrupt-names = "hc_irq", "pwr_irq"; clocks = <&gcc GCC_SDCC2_APPS_CLK>, - <&gcc GCC_SDCC2_AHB_CLK>; - clock-names = "core", "iface"; + <&gcc GCC_SDCC2_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "core", "iface", "xo"; interconnects = <&aggre1_noc MASTER_SDCC_2 0 &mc_virt SLAVE_EBI1 0>, <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_SDCC_2 0>; @@ -2689,15 +2585,15 @@ opp-100000000 { opp-hz = /bits/ 64 <100000000>; required-opps = <&rpmhpd_opp_low_svs>; - opp-peak-kBps = <160000 100000>; - opp-avg-kBps = <80000 50000>; + opp-peak-kBps = <1800000 600000>; + opp-avg-kBps = <100000 0>; }; opp-202000000 { opp-hz = /bits/ 64 <202000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - opp-peak-kBps = <200000 120000>; - opp-avg-kBps = <100000 60000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <5400000 1600000>; + opp-avg-kBps = <200000 0>; }; }; }; @@ -2754,8 +2650,8 @@ usb_1_qmpphy: phy-wrapper@88e9000 { compatible = "qcom,sc7180-qmp-usb3-dp-phy"; reg = <0 0x088e9000 0 0x18c>, - <0 0x088e8000 0 0x38>, - <0 0x088ea000 0 0x40>; + <0 0x088e8000 0 0x3c>, + <0 0x088ea000 0 0x18c>; status = "disabled"; #address-cells = <2>; #size-cells = <2>; @@ -2860,7 +2756,7 @@ <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xe000>; interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dts b/arch/arm64/boot/dts/qcom/sc7280-idp.dts index 54d2cb365b71..3900cfc09562 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-idp.dts +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dts @@ -7,11 +7,19 @@ /dts-v1/; +#include +#include +#include +#include #include "sc7280.dtsi" +#include "pm7325.dtsi" +#include "pmr735a.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" / { model = "Qualcomm Technologies, Inc. sc7280 IDP platform"; - compatible = "qcom,sc7280-idp", "qcom,sc7280"; + compatible = "qcom,sc7280-idp", "google,senor", "qcom,sc7280"; aliases { serial0 = &uart5; @@ -234,6 +242,32 @@ }; }; +&pmk8350_vadc { + pm8350_die_temp { + reg = ; + label = "pm8350_die_temp"; + qcom,pre-scaling = <1 1>; + }; + + pmk8350_die_temp { + reg = ; + label = "pmk8350_die_temp"; + qcom,pre-scaling = <1 1>; + }; + + pmr735a_die_temp { + reg = ; + label = "pmr735a_die_temp"; + qcom,pre-scaling = <1 1>; + }; + + pmr735b_die_temp { + reg = ; + label = "pmr735b_die_temp"; + qcom,pre-scaling = <1 1>; + }; +}; + &qupv3_id_0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 2cc478553935..a8c274ad74c4 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -11,7 +11,10 @@ #include #include #include +#include +#include #include +#include / { interrupt-parent = <&intc>; @@ -51,6 +54,11 @@ no-map; }; + smem_mem: memory@80900000 { + reg = <0x0 0x80900000 0x0 0x200000>; + no-map; + }; + cpucp_mem: memory@80b00000 { no-map; reg = <0x0 0x80b00000 0x0 0x100000>; @@ -70,6 +78,8 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_0: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -88,6 +98,8 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_100>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_100: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -103,6 +115,8 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_200>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_200: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -118,6 +132,8 @@ &LITTLE_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_300>; + qcom,freq-domain = <&cpufreq_hw 0>; + #cooling-cells = <2>; L2_300: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -133,6 +149,8 @@ &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_400>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_400: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -148,6 +166,8 @@ &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_500>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_500: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -163,6 +183,8 @@ &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_600>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_600: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -178,6 +200,8 @@ &BIG_CPU_SLEEP_1 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_700>; + qcom,freq-domain = <&cpufreq_hw 1>; + #cooling-cells = <2>; L2_700: l2-cache { compatible = "cache"; next-level-cache = <&L3_0>; @@ -251,6 +275,125 @@ }; }; + clk_virt: interconnect { + compatible = "qcom,sc7280-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-mpss { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_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>; + }; + }; + + smp2p-wpss { + compatible = "qcom,smp2p"; + qcom,smem = <617>, <616>; + interrupts-extended = <&ipcc IPCC_CLIENT_WPSS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_WPSS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,local-pid = <0>; + qcom,remote-pid = <13>; + + wpss_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + wpss_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = ; @@ -316,6 +459,93 @@ }; }; + cnoc2: interconnect@1500000 { + reg = <0 0x01500000 0 0x1000>; + compatible = "qcom,sc7280-cnoc2"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + cnoc3: interconnect@1502000 { + reg = <0 0x01502000 0 0x1000>; + compatible = "qcom,sc7280-cnoc3"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect@1580000 { + reg = <0 0x01580000 0 0x4>; + compatible = "qcom,sc7280-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + system_noc: interconnect@1680000 { + reg = <0 0x01680000 0 0x15480>; + compatible = "qcom,sc7280-system-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sc7280-aggre1-noc"; + reg = <0 0x016e0000 0 0x1c080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre2_noc: interconnect@1700000 { + reg = <0 0x01700000 0 0x2b080>; + compatible = "qcom,sc7280-aggre2-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mmss_noc: interconnect@1740000 { + reg = <0 0x01740000 0 0x1e080>; + compatible = "qcom,sc7280-mmss-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex", "syscon"; + reg = <0 0x01f40000 0 0x40000>; + #hwlock-cells = <1>; + }; + + lpasscc: lpasscc@3000000 { + compatible = "qcom,sc7280-lpasscc"; + reg = <0 0x03000000 0 0x40>, + <0 0x03c04000 0 0x4>, + <0 0x03389000 0 0x24>; + reg-names = "qdsp6ss", "top_cc", "cc"; + clocks = <&gcc GCC_CFG_NOC_LPASS_CLK>; + clock-names = "iface"; + #clock-cells = <1>; + }; + + lpass_ag_noc: interconnect@3c40000 { + reg = <0 0x03c40000 0 0xf080>; + compatible = "qcom,sc7280-lpass-ag-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + gpucc: clock-controller@3d90000 { + compatible = "qcom,sc7280-gpucc"; + reg = <0 0x03d90000 0 0x9000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_GPU_GPLL0_CLK_SRC>, + <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>; + clock-names = "bi_tcxo", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + stm@6002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0 0x06002000 0 0x1000>, @@ -805,6 +1035,20 @@ }; }; + dc_noc: interconnect@90e0000 { + reg = <0 0x090e0000 0 0x5080>; + compatible = "qcom,sc7280-dc-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + gem_noc: interconnect@9100000 { + reg = <0 0x9100000 0 0xe2200>; + compatible = "qcom,sc7280-gem-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + system-cache-controller@9200000 { compatible = "qcom,sc7280-llcc"; reg = <0 0x09200000 0 0xd0000>, <0 0x09600000 0 0x50000>; @@ -812,6 +1056,42 @@ interrupts = ; }; + nsp_noc: interconnect@a0c0000 { + reg = <0 0x0a0c0000 0 0x10000>; + compatible = "qcom,sc7280-nsp-noc"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + videocc: clock-controller@aaf0000 { + compatible = "qcom,sc7280-videocc"; + reg = <0 0xaaf0000 0 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>; + clock-names = "bi_tcxo", "bi_tcxo_ao"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + dispcc: clock-controller@af00000 { + compatible = "qcom,sc7280-dispcc"; + reg = <0 0xaf00000 0 0x20000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <0>, <0>, <0>, <0>, <0>, <0>; + clock-names = "bi_tcxo", "gcc_disp_gpll0_clk", + "dsi0_phy_pll_out_byteclk", + "dsi0_phy_pll_out_dsiclk", + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk", + "edp_phy_pll_link_clk", + "edp_phy_pll_vco_div_clk"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + pdc: interrupt-controller@b220000 { compatible = "qcom,sc7280-pdc", "qcom,pdc"; reg = <0 0x0b220000 0 0x30000>; @@ -825,6 +1105,40 @@ interrupt-controller; }; + pdc_reset: reset-controller@b5e0000 { + compatible = "qcom,sc7280-pdc-global"; + reg = <0 0x0b5e0000 0 0x20000>; + #reset-cells = <1>; + }; + + tsens0: thermal-sensor@c263000 { + compatible = "qcom,sc7280-tsens","qcom,tsens-v2"; + reg = <0 0x0c263000 0 0x1ff>, /* TM */ + <0 0x0c222000 0 0x1ff>; /* SROT */ + #qcom,sensors = <15>; + interrupts = , + ; + interrupt-names = "uplow","critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c265000 { + compatible = "qcom,sc7280-tsens","qcom,tsens-v2"; + reg = <0 0x0c265000 0 0x1ff>, /* TM */ + <0 0x0c223000 0 0x1ff>; /* SROT */ + #qcom,sensors = <12>; + interrupts = , + ; + interrupt-names = "uplow","critical"; + #thermal-sensor-cells = <1>; + }; + + aoss_reset: reset-controller@c2a0000 { + compatible = "qcom,sc7280-aoss-cc", "qcom,sdm845-aoss-cc"; + reg = <0 0x0c2a0000 0 0x31000>; + #reset-cells = <1>; + }; + aoss_qmp: power-controller@c300000 { compatible = "qcom,sc7280-aoss-qmp"; reg = <0 0x0c300000 0 0x100000>; @@ -1063,6 +1377,10 @@ , ; + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + rpmhpd: power-controller { compatible = "qcom,sc7280-rpmhpd"; #power-domain-cells = <1>; @@ -1116,6 +1434,859 @@ #clock-cells = <1>; }; }; + + cpufreq_hw: cpufreq@18591000 { + compatible = "qcom,cpufreq-epss"; + reg = <0 0x18591000 0 0x1000>, + <0 0x18592000 0 0x1000>, + <0 0x18593000 0 0x1000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + #freq-domain-cells = <1>; + }; + }; + + thermal_zones: thermal-zones { + cpu0-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 1>; + + trips { + cpu0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu0_alert0>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu0_alert1>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu1-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 2>; + + trips { + cpu1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu1_alert0>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu1_alert1>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu2-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 3>; + + trips { + cpu2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu2_alert0>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu2_alert1>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu3-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 4>; + + trips { + cpu3_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu3_alert0>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu3_alert1>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu4-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 7>; + + trips { + cpu4_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu4_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu4_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu5-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 8>; + + trips { + cpu5_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu5_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu5_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu6-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 9>; + + trips { + cpu6_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu6_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu6_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu7-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 10>; + + trips { + cpu7_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu7_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu7_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu8-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 11>; + + trips { + cpu8_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu8_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu8_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu8_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu8_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu9-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 12>; + + trips { + cpu9_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu9_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu9_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu9_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu9_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu10-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 13>; + + trips { + cpu10_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu10_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu10_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu10_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu10_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu11-thermal { + polling-delay-passive = <250>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 14>; + + trips { + cpu11_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu11_alert1: trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu11_crit: cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu11_alert0>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + map1 { + trip = <&cpu11_alert1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + aoss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 0>; + + trips { + aoss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss0_crit: aoss0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + aoss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 0>; + + trips { + aoss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss1_crit: aoss1-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 5>; + + trips { + cpuss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + cpuss0_crit: cluster0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 6>; + + trips { + cpuss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + cpuss1_crit: cluster0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 1>; + + trips { + gpuss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss0_crit: gpuss0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 2>; + + trips { + gpuss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss1_crit: gpuss1-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nspss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 3>; + + trips { + nspss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nspss0_crit: nspss0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nspss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 4>; + + trips { + nspss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nspss1_crit: nspss1-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 5>; + + trips { + video_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + video_crit: video-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + ddr-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 6>; + + trips { + ddr_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + ddr_crit: ddr-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + mdmss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 7>; + + trips { + mdmss0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + mdmss0_crit: mdmss0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + mdmss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 8>; + + trips { + mdmss1_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + mdmss1_crit: mdmss1-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + mdmss2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 9>; + + trips { + mdmss2_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + mdmss2_crit: mdmss2-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + mdmss3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 10>; + + trips { + mdmss3_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + mdmss3_crit: mdmss3-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + camera0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 11>; + + trips { + camera0_alert0: trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + camera0_crit: camera0-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; }; timer { diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi index 216a74f0057c..dfd1b42c07fd 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi @@ -714,10 +714,6 @@ ap_ts_i2c: &i2c14 { #address-cells = <1>; #size-cells = <0>; }; - - pdupdate { - compatible = "google,cros-ec-pd-update"; - }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index 1372fe8601f5..91ede9296aff 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -448,6 +448,11 @@ clock-frequency = <400000>; }; +&ipa { + status = "okay"; + memory-region = <&ipa_fw_mem>; +}; + &mdss { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi index 8f617f7b6d34..4d052e39b348 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi @@ -46,6 +46,14 @@ }; reserved-memory { + /* The rmtfs_mem needs to be guarded due to "XPU limitations" + * it is otherwise possible for an allocation adjacent to the + * rmtfs_mem region to trigger an XPU violation, causing a crash. + */ + rmtfs_lower_guard: memory@f5b00000 { + no-map; + reg = <0 0xf5b00000 0 0x1000>; + }; /* * The rmtfs memory region in downstream is 'dynamically allocated' * but given the same address every time. Hard code it as this address is @@ -59,6 +67,10 @@ qcom,client-id = <1>; qcom,vmid = <15>; }; + rmtfs_upper_guard: memory@f5d01000 { + no-map; + reg = <0 0xf5d01000 0 0x2000>; + }; /* * It seems like reserving the old rmtfs_mem region is also needed to prevent @@ -387,6 +399,12 @@ }; }; +&ipa { + status = "okay"; + + memory-region = <&ipa_fw_mem>; +}; + &mdss { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts index 7d029425336e..c60c8c640e17 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "sdm845.dtsi" #include "pm8998.dtsi" #include "pmi8998.dtsi" @@ -311,6 +313,28 @@ }; }; +/* QUAT I2S Uses 1 I2S SD Line for audio on TAS2559/60 amplifiers */ +&q6afedai { + qi2s@22 { + reg = <22>; + qcom,sd-lines = <0>; + }; +}; + +&q6asmdai { + dai@0 { + reg = <0>; + }; + + dai@1 { + reg = <1>; + }; + + dai@2 { + reg = <2>; + }; +}; + &qupv3_id_0 { status = "okay"; }; @@ -328,6 +352,70 @@ cd-gpios = <&tlmm 126 GPIO_ACTIVE_HIGH>; }; +&sound { + compatible = "qcom,db845c-sndcard"; + pinctrl-0 = <&quat_mi2s_active + &quat_mi2s_sd0_active>; + pinctrl-names = "default"; + model = "Xiaomi Poco F1"; + audio-routing = + "RX_BIAS", "MCLK", + "AMIC1", "MIC BIAS1", + "AMIC2", "MIC BIAS2", + "AMIC3", "MIC BIAS3"; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + mm2-dai-link { + link-name = "MultiMedia2"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>; + }; + }; + + mm3-dai-link { + link-name = "MultiMedia3"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>; + }; + }; + + slim-dai-link { + link-name = "SLIM Playback"; + cpu { + sound-dai = <&q6afedai SLIMBUS_0_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&wcd9340 0>; + }; + }; + + slimcap-dai-link { + link-name = "SLIM Capture"; + cpu { + sound-dai = <&q6afedai SLIMBUS_0_TX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&wcd9340 1>; + }; + }; +}; + &tlmm { gpio-reserved-ranges = <0 4>, <81 4>; @@ -356,6 +444,15 @@ function = "gpio"; bias-pull-up; }; + + wcd_intr_default: wcd_intr_default { + pins = <54>; + function = "gpio"; + + input-enable; + bias-pull-down; + drive-strength = <2>; + }; }; &uart6 { @@ -416,6 +513,23 @@ vdda-pll-supply = <&vreg_l1a_0p875>; }; +&wcd9340{ + pinctrl-0 = <&wcd_intr_default>; + pinctrl-names = "default"; + clock-names = "extclk"; + clocks = <&rpmhcc RPMH_LN_BB_CLK2>; + reset-gpios = <&tlmm 64 0>; + vdd-buck-supply = <&vreg_s4a_1p8>; + vdd-buck-sido-supply = <&vreg_s4a_1p8>; + vdd-tx-supply = <&vreg_s4a_1p8>; + vdd-rx-supply = <&vreg_s4a_1p8>; + vdd-io-supply = <&vreg_s4a_1p8>; + qcom,micbias1-microvolt = <2700000>; + qcom,micbias2-microvolt = <1800000>; + qcom,micbias3-microvolt = <2700000>; + qcom,micbias4-microvolt = <2700000>; +}; + &wifi { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0a86fe71a66d..1796ae8372be 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3781,7 +3781,7 @@ <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xcd00>; interrupts = ; @@ -3829,7 +3829,7 @@ <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_1 0>; interconnect-names = "usb-ddr", "apps-usb"; - usb_2_dwc3: dwc3@a800000 { + usb_2_dwc3: usb@a800000 { compatible = "snps,dwc3"; reg = <0 0x0a800000 0 0xcd00>; interrupts = ; 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 140db2d5ba31..c2a709a384e9 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -376,6 +376,8 @@ clocks = <&sn65dsi86_refclk>; clock-names = "refclk"; + no-hpd; + ports { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts index fb2cf3d987a1..335aa0753fc0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts @@ -354,22 +354,26 @@ }; }; -&qupv3_id_1 { +&gmu { status = "okay"; }; -&pon { - pwrkey { - status = "okay"; - }; +&gpu { + status = "okay"; +}; - resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + + linux,code = ; +}; + +&qupv3_id_1 { + status = "okay"; }; &remoteproc_adsp { diff --git a/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts b/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts new file mode 100644 index 000000000000..736da9af44e0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2021, Microsoft Corporation + */ + +/dts-v1/; + +#include +#include +#include "sm8150.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" + +/ { + model = "Microsoft Surface Duo"; + compatible = "microsoft,surface-duo", "qcom,sm8150"; + + aliases { + serial0 = &uart2; + }; + + 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>; + }; + + /* + * Apparently RPMh does not provide support for PM8150 S4 because it + * is always-on; model it as a fixed regulator. + */ + vreg_s4a_1p8: pm8150-s4 { + compatible = "regulator-fixed"; + regulator-name = "vreg_s4a_1p8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; + + gpio_keys { + compatible = "gpio-keys"; + + vol_up { + label = "Volume Up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&apps_rsc { + pm8150-rpmh-regulators { + 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_s6a_0p9>; + vdd-l2-l10-supply = <&vreg_bob>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p9>; + vdd-l6-l9-supply = <&vreg_s8c_1p3>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p0>; + vdd-l13-l16-l17-supply = <&vreg_bob>; + + vreg_s5a_2p0: smps5 { + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2000000>; + }; + + vreg_s6a_0p9: smps6 { + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <1128000>; + }; + + vdda_wcss_pll: + vreg_l1a_0p75: ldo1 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + regulator-initial-mode = ; + }; + + vdd_pdphy: + vdda_usb_hs_3p1: + vreg_l2a_3p1: ldo2 { + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p8: ldo3 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <932000>; + regulator-initial-mode = ; + }; + + vdd_usb_hs_core: + vdda_csi_0_0p9: + vdda_csi_1_0p9: + vdda_csi_2_0p9: + vdda_csi_3_0p9: + vdda_dsi_0_0p9: + vdda_dsi_1_0p9: + vdda_dsi_0_pll_0p9: + vdda_dsi_1_pll_0p9: + vdda_pcie_1ln_core: + vdda_pcie_2ln_core: + vdda_pll_hv_cc_ebi01: + vdda_pll_hv_cc_ebi23: + vdda_qrefs_0p875_5: + vdda_sp_sensor: + vdda_ufs_2ln_core_1: + vdda_ufs_2ln_core_2: + vdda_usb_ss_dp_core_1: + vdda_usb_ss_dp_core_2: + vdda_qlink_lv: + vdda_qlink_lv_ck: + vreg_l5a_0p875: ldo5 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l6a_1p2: ldo6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l7a_1p8: ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vddpx_10: + vreg_l9a_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l10a_2p5: ldo10 { + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l11a_0p8: ldo11 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vdd_qfprom: + vdd_qfprom_sp: + vdda_apc_cs_1p8: + vdda_gfx_cs_1p8: + vdda_usb_hs_1p8: + vdda_qrefs_vref_1p8: + vddpx_10_a: + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l13a_2p7: ldo13 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + regulator-initial-mode = ; + }; + + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p7: ldo15 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l17a_3p0: ldo17 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + }; + + pm8150l-rpmh-regulators { + 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_1p3>; + vdd-l4-l5-l6-supply = <&vreg_bob>; + vdd-l7-l11-supply = <&vreg_bob>; + vdd-l9-l10-supply = <&vreg_bob>; + + vdd-bob-supply = <&vph_pwr>; + vdd-flash-supply = <&vreg_bob>; + vdd-rgb-supply = <&vreg_bob>; + + vreg_bob: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <4000000>; + regulator-initial-mode = ; + regulator-allow-bypass; + }; + + vreg_s8c_1p3: smps8 { + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vdda_wcss_adcdac_1: + vdda_wcss_adcdac_22: + vreg_l2c_1p3: ldo2 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vdda_hv_ebi0: + vdda_hv_ebi1: + vdda_hv_ebi2: + vdda_hv_ebi3: + vdda_hv_refgen0: + vdda_qlink_hv_ck: + vreg_l3c_1p2: ldo3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vddpx_5: + vreg_l4c_1p8: ldo4 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vddpx_6: + vreg_l5c_1p8: ldo5 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vddpx_2: + vreg_l6c_2p9: ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p8: ldo8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p9: ldo9 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10c_3p3: ldo10 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p3: ldo11 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + }; + + pm8009-rpmh-regulators { + compatible = "qcom,pm8009-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vreg_bob>; + + vdd-l2-supply = <&vreg_s8c_1p3>; + vdd-l5-l6-supply = <&vreg_bob>; + + vreg_l2f_1p2: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l5f_2p85: ldo5 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6f_2p85: ldo6 { + regulator-initial-mode = ; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <2856000>; + }; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; + + bq27742@55 { + compatible = "ti,bq27742"; + reg = <0x55>; + }; + + da7280@4a { + compatible = "dlg,da7280"; + reg = <0x4a>; + interrupts-extended = <&tlmm 42 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "da7280_default"; + pinctrl-0 = <&da7280_intr_default>; + + dlg,actuator-type = "LRA"; + dlg,dlg,const-op-mode = <1>; + dlg,dlg,periodic-op-mode = <1>; + dlg,nom-microvolt = <2000000>; + dlg,abs-max-microvolt = <2000000>; + dlg,imax-microamp = <129000>; + dlg,resonant-freq-hz = <180>; + dlg,impd-micro-ohms = <14300000>; + dlg,freq-track-enable; + dlg,bemf-sens-enable; + dlg,mem-array = < + 0x06 0x08 0x10 0x11 0x12 0x13 0x14 0x15 0x1c 0x2a + 0x33 0x3c 0x42 0x4b 0x4c 0x4e 0x17 0x19 0x27 0x29 + 0x17 0x19 0x03 0x84 0x5e 0x04 0x08 0x84 0x5d 0x01 + 0x84 0x5e 0x02 0x00 0xa4 0x5d 0x03 0x84 0x5e 0x06 + 0x08 0x84 0x5d 0x05 0x84 0x5d 0x06 0x84 0x5e 0x08 + 0x84 0x5e 0x05 0x8c 0x5e 0x24 0x84 0x5f 0x10 0x84 + 0x5e 0x05 0x84 0x5e 0x08 0x84 0x5f 0x01 0x8c 0x5e + 0x04 0x84 0x5e 0x08 0x84 0x5f 0x11 0x19 0x88 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + >; + }; + + /* SMB1381 @ 0x44 */ + /* MAX34417 @ 0x1c */ +}; + +&i2c4 { + status = "okay"; + clock-frequency = <400000>; + + /* SMB1355 @ 0x0c */ + /* SMB1390 @ 0x10 */ +}; + +&i2c17 { + status = "okay"; + clock-frequency = <400000>; + + bq27742@55 { + compatible = "ti,bq27742"; + reg = <0x55>; + }; +}; + +&i2c19 { + status = "okay"; + clock-frequency = <400000>; + + /* MAX34417 @ 0x12 */ + /* MAX34417 @ 0x1a */ + /* MAX34417 @ 0x1e */ +}; + +&pon { + pwrkey { + status = "okay"; + }; + + resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&qupv3_id_2 { + status = "okay"; +}; + +&remoteproc_adsp { + status = "okay"; + firmware-name = "qcom/sm8150/microsoft/adsp.mdt"; +}; + +&remoteproc_cdsp { + status = "okay"; + firmware-name = "qcom/sm8150/microsoft/cdsp.mdt"; +}; + +&remoteproc_mpss { + status = "okay"; + firmware-name = "qcom/sm8150/microsoft/modem.mdt"; +}; + +&remoteproc_slpi { + status = "okay"; + firmware-name = "qcom/sm8150/microsoft/slpi.mdt"; +}; + +&tlmm { + gpio-reserved-ranges = <126 4>; + + da7280_intr_default: da7280-intr-default { + pins = "gpio42"; + function = "gpio"; + bias-pull-up; + input-enable; + }; +}; + +&uart2 { + status = "okay"; +}; + +&ufs_mem_hc { + status = "okay"; + + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l10a_2p5>; + vcc-max-microamp = <750000>; + vccq-supply = <&vreg_l9a_1p2>; + vccq-max-microamp = <700000>; + vccq2-supply = <&vreg_s4a_1p8>; + vccq2-max-microamp = <750000>; +}; + +&ufs_mem_phy { + status = "okay"; + + vdda-phy-supply = <&vdda_ufs_2ln_core_1>; + vdda-max-microamp = <90200>; + vdda-pll-supply = <&vreg_l3c_1p2>; + vdda-pll-max-microamp = <19000>; +}; + +&usb_1_hsphy { + status = "okay"; + vdda-pll-supply = <&vdd_usb_hs_core>; + vdda33-supply = <&vdda_usb_hs_3p1>; + vdda18-supply = <&vdda_usb_hs_1p8>; +}; + +&usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l3c_1p2>; + vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&wifi { + status = "okay"; + + vdd-0.8-cx-mx-supply = <&vdda_wcss_pll>; + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vdda_wcss_adcdac_1>; + vdd-3.3-ch0-supply = <&vreg_l11c_3p3>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts index 3774f8e63416..53edf7541169 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts @@ -349,22 +349,26 @@ }; }; -&qupv3_id_1 { +&gmu { status = "okay"; }; -&pon { - pwrkey { - status = "okay"; - }; +&gpu { + status = "okay"; +}; - resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + + linux,code = ; +}; + +&qupv3_id_1 { + status = "okay"; }; &remoteproc_adsp { diff --git a/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-bahamut.dts b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-bahamut.dts new file mode 100644 index 000000000000..3b55fdda767a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-bahamut.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +/dts-v1/; + +#include "sm8150-sony-xperia-kumano.dtsi" + +/ { + model = "Sony Xperia 5"; + compatible = "sony,bahamut-generic", "qcom,sm8150"; +}; + +&framebuffer { + width = <1080>; + height = <2520>; + stride = <(1080 * 4)>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-griffin.dts b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-griffin.dts new file mode 100644 index 000000000000..6f490ec284bd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano-griffin.dts @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +/dts-v1/; + +#include "sm8150-sony-xperia-kumano.dtsi" + +/ { + model = "Sony Xperia 1"; + compatible = "sony,griffin-generic", "qcom,sm8150"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi new file mode 100644 index 000000000000..014fe3a31548 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sony-xperia-kumano.dtsi @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +/dts-v1/; + +#include +#include +#include "sm8150.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" + +/delete-node/ &cdsp_mem; +/delete-node/ &gpu_mem; +/delete-node/ &ipa_fw_mem; +/delete-node/ &ipa_gsi_mem; +/delete-node/ &mpss_mem; +/delete-node/ &slpi_mem; +/delete-node/ &spss_mem; +/delete-node/ &venus_mem; + +/ { + qcom,msm-id = <339 0x20000>; /* SM8150 v2 */ + qcom,board-id = <8 0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer: framebuffer@9c000000 { + compatible = "simple-framebuffer"; + reg = <0 0x9c000000 0 0x2300000>; + width = <1644>; + height = <3840>; + stride = <(1644 * 4)>; + format = "a8r8g8b8"; + /* + * That's (going to be) a lot of clocks, but it's necessary due + * to unused clk cleanup & no panel driver yet (& no dispcc either).. + */ + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + /* + * Apparently RPMh does not provide support for PM8150 S4 because it + * is always-on; model it as a fixed regulator. + */ + vreg_s4a_1p8: pm8150-s4 { + compatible = "regulator-fixed"; + regulator-name = "vreg_s4a_1p8"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-always-on; + regulator-boot-on; + + vin-supply = <&vph_pwr>; + }; + + reserved-memory { + mpss_mem: memory@8dc00000 { + reg = <0x0 0x8dc00000 0x0 0x9600000>; + no-map; + }; + + venus_mem: memory@97200000 { + reg = <0x0 0x97200000 0x0 0x500000>; + no-map; + }; + + slpi_mem: memory@97700000 { + reg = <0x0 0x97700000 0x0 0x1400000>; + no-map; + }; + + ipa_fw_mem: memory@98b00000 { + reg = <0x0 0x98b00000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: memory@98b10000 { + reg = <0x0 0x98b10000 0x0 0x5000>; + no-map; + }; + + gpu_mem: memory@98b15000 { + reg = <0x0 0x98b15000 0x0 0x2000>; + no-map; + }; + + spss_mem: memory@98c00000 { + reg = <0x0 0x98c00000 0x0 0x100000>; + no-map; + }; + + cdsp_mem: memory@98d00000 { + reg = <0x0 0x98d00000 0x0 0x1400000>; + no-map; + }; + + cont_splash_mem: memory@9c000000 { + reg = <0x0 0x9c000000 0x0 0x2400000>; + no-map; + }; + + cdsp_sec_mem: memory@a4c00000 { + reg = <0x0 0xa4c00000 0x0 0x3c00000>; + no-map; + }; + + ramoops@ffc00000 { + compatible = "ramoops"; + reg = <0x0 0xffc00000 0x0 0x100000>; + record-size = <0x1000>; + console-size = <0x40000>; + msg-size = <0x20000 0x20000>; + ecc-size = <16>; + no-map; + }; + }; +}; + +&adsp_mem { + reg = <0x0 0x8be00000 0x0 0x1e00000>; +}; + +&apps_rsc { + pm8150-rpmh-regulators { + 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_s6a_0p9>; + vdd-l2-l10-supply = <&vreg_bob>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p9>; + vdd-l6-l9-supply = <&vreg_s8c_1p3>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_1p9>; + vdd-l13-l16-l17-supply = <&vreg_bob>; + + vreg_s2a_0p6: smps2 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <600000>; + regulator-initial-mode = ; + }; + + vreg_s5a_1p9: smps5 { + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s6a_0p9: smps6 { + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = ; + }; + + vreg_l1a_0p75: ldo1 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + regulator-initial-mode = ; + }; + + vreg_l2a_3p1: ldo2 { + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p8: ldo3 { + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <932000>; + regulator-initial-mode = ; + }; + + vreg_l5a_0p875: ldo5 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l6a_1p2: ldo6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l7a_1p8: ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9a_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l10a_2p5: ldo10 { + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l11a_0p8: ldo11 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-initial-mode = ; + }; + + vreg_l12a_1p8: ldo12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + /* L13 is unused. */ + + vreg_l14a_1p8: ldo14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l15a_1p7: ldo15 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + regulator-initial-mode = ; + }; + + vreg_l16a_2p7: ldo16 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l17a_3p0: ldo17 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l18a_0p8: ldo18 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + }; + }; + + pm8150l-rpmh-regulators { + 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_1p3>; + vdd-l4-l5-l6-supply = <&vreg_bob>; + vdd-l7-l11-supply = <&vreg_bob>; + vdd-l9-l10-supply = <&vreg_bob>; + + vdd-bob-supply = <&vph_pwr>; + vdd-flash-supply = <&vreg_bob>; + vdd-rgb-supply = <&vreg_bob>; + + vreg_bob: bob { + regulator-min-microvolt = <3350000>; + regulator-max-microvolt = <4000000>; + regulator-initial-mode = ; + regulator-allow-bypass; + }; + + vreg_s1c_1p1: smps1 { + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = ; + }; + + vreg_s8c_1p3: smps8 { + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p3: ldo2 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l3c_1p2: ldo3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l4c_1p8: ldo4 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p8: ldo5 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p9: ldo6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p8: ldo8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p9: ldo9 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + }; + + vreg_l10c_3p3: ldo10 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p3: ldo11 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + }; + + /* PM8009 is not present on these boards, even if downstream sources suggest so. */ +}; + +&i2c4 { + status = "okay"; + + /* Qcom SMB1355 @ c */ + /* Qcom SMB1390 @ 10 */ + /* NXP PN553 NFC @ 28 */ + /* Qcom FSA4480 USB-C audio switch @ 43 */ +}; + +&i2c7 { + status = "okay"; + + /* AMS TCS3490 RGB+IR color sensor @ 72 */ +}; + +&i2c10 { + status = "okay"; + + /* Samsung touchscreen @ 48 */ +}; + +&pon_pwrkey { + status = "okay"; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <126 4>; +}; + +&uart2 { + status = "okay"; +}; + +/* BIG WARNING! DO NOT TOUCH UFS, YOUR DEVICE WILL DIE! */ +&ufs_mem_hc { status = "disabled"; }; +&ufs_mem_phy { status = "disabled"; }; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + status = "okay"; + vdda-pll-supply = <&vreg_l5a_0p875>; + vdda33-supply = <&vreg_l2a_3p1>; + vdda18-supply = <&vreg_l12a_1p8>; +}; + +&usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l3c_1p2>; + vdda-pll-supply = <&vreg_l18a_0p8>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 51235a9521c2..612dda0fef43 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -4,6 +4,7 @@ * Copyright (c) 2019, Linaro Limited */ +#include #include #include #include @@ -577,6 +578,29 @@ <&sleep_clk>; }; + gpi_dma0: dma-controller@800000 { + compatible = "qcom,sm8150-gpi-dma"; + reg = <0 0x800000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <13>; + dma-channel-mask = <0xfa>; + iommus = <&apps_smmu 0x00d6 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_0: geniqup@8c0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x008c0000 0x0 0x6000>; @@ -695,6 +719,29 @@ }; + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,sm8150-gpi-dma"; + reg = <0 0xa00000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <13>; + dma-channel-mask = <0xfa>; + iommus = <&apps_smmu 0x0616 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_1: geniqup@ac0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x00ac0000 0x0 0x6000>; @@ -795,6 +842,29 @@ }; }; + gpi_dma2: dma-controller@c00000 { + compatible = "qcom,sm8150-gpi-dma"; + reg = <0 0xc00000 0 0x60000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <13>; + dma-channel-mask = <0xfa>; + iommus = <&apps_smmu 0x07b6 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_2: geniqup@cc0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x00cc0000 0x0 0x6000>; @@ -1082,6 +1152,8 @@ qcom,gmu = <&gmu>; + status = "disabled"; + zap-shader { memory-region = <&gpu_mem>; }; @@ -1149,6 +1221,8 @@ operating-points-v2 = <&gmu_opp_table>; + status = "disabled"; + gmu_opp_table: opp-table { compatible = "operating-points-v2"; @@ -1496,6 +1570,8 @@ qcom,smem-states = <&modem_smp2p_out 0>; qcom,smem-state-names = "stop"; + status = "disabled"; + glink-edge { interrupts = ; label = "modem"; @@ -2268,7 +2344,7 @@ resets = <&gcc GCC_USB30_PRIM_BCR>; - usb_1_dwc3: dwc3@a600000 { + usb_1_dwc3: usb@a600000 { compatible = "snps,dwc3"; reg = <0 0x0a600000 0 0xcd00>; interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/sm8250-hdk.dts b/arch/arm64/boot/dts/qcom/sm8250-hdk.dts index c3a2c5aa6fe9..47742816ac2f 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-hdk.dts @@ -6,7 +6,6 @@ /dts-v1/; #include -#include #include "sm8250.dtsi" #include "pm8150.dtsi" #include "pm8150b.dtsi" @@ -365,22 +364,26 @@ }; }; -&qupv3_id_1 { +&gmu { status = "okay"; }; -&pon { - pwrkey { - status = "okay"; - }; +&gpu { + status = "okay"; +}; - resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + + linux,code = ; +}; + +&qupv3_id_1 { + status = "okay"; }; &tlmm { @@ -452,3 +455,7 @@ &usb_2_dwc3 { dr_mode = "host"; }; + +&venus { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts index cfc4d1febe0f..062b944be91d 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8250-mtp.dts @@ -465,7 +465,13 @@ firmware-name = "qcom/sm8250/cdsp.mbn"; }; +&gmu { + status = "okay"; +}; + &gpu { + status = "okay"; + zap-shader { memory-region = <&gpu_mem>; firmware-name = "qcom/sm8250/a650_zap.mbn"; @@ -691,3 +697,7 @@ vdda-phy-supply = <&vreg_l9a_1p2>; vdda-pll-supply = <&vreg_l18a_0p9>; }; + +&venus { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts new file mode 100644 index 000000000000..79afeb07f4a2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx203.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +/dts-v1/; + +#include "sm8250-sony-xperia-edo.dtsi" + +/ { + model = "Sony Xperia 1 II"; + compatible = "sony,pdx203-generic", "qcom,sm8250"; +}; + +/delete-node/ &vreg_l7f_1p8; diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts new file mode 100644 index 000000000000..16c96e838534 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo-pdx206.dts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +/dts-v1/; + +#include "sm8250-sony-xperia-edo.dtsi" + +/ { + model = "Sony Xperia 5 II"; + compatible = "sony,pdx206-generic", "qcom,sm8250"; +}; + +&framebuffer { + width = <1080>; + height = <2520>; + stride = <(1080 * 4)>; +}; + +&gpio_keys { + g-assist-key { + label = "Google Assistant Key"; + linux,code = ; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + linux,can-disable; + gpio-key,wakeup; + }; +}; + +&vreg_l2f_1p3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi new file mode 100644 index 000000000000..d63f7a9bc4e9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, Konrad Dybcio + */ + +#include +#include "sm8250.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" +#include "pm8009.dtsi" + +/delete-node/ &adsp_mem; +/delete-node/ &spss_mem; +/delete-node/ &cdsp_secure_heap; + +/ { + qcom,msm-id = <356 0x20001>; /* SM8250 v2.1 */ + qcom,board-id = <0x10008 0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer: framebuffer@9c000000 { + compatible = "simple-framebuffer"; + reg = <0 0x9c000000 0 0x2300000>; + width = <1644>; + height = <3840>; + stride = <(1644 * 4)>; + format = "a8r8g8b8"; + /* + * That's a lot of clocks, but it's necessary due + * to unused clk cleanup & no panel driver yet.. + */ + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&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>; + power-domains = <&dispcc MDSS_GDSC>; + }; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + + /* + * Camera focus (light press) and camera snapshot (full press) + * seem not to work properly.. Adding the former one stalls the CPU + * and the latter kills the volume down key for whatever reason. In any + * case, they are both on &pm8150b_gpios: camera focus(2), camera snapshot(1). + */ + + vol-down { + label = "Volume Down"; + linux,code = ; + gpios = <&pm8150_gpios 1 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + linux,can-disable; + gpio-key,wakeup; + }; + }; + + 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 { + adsp_mem: memory@8a100000 { + reg = <0x0 0x8a100000 0x0 0x2500000>; + no-map; + }; + + spss_mem: memory@8c600000 { + reg = <0x0 0x8c600000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap: memory@8c700000 { + reg = <0x0 0x8c700000 0x0 0x4600000>; + no-map; + }; + + cont_splash_mem: memory@9c000000 { + reg = <0x0 0x9c000000 0x0 0x2300000>; + no-map; + }; + + ramoops@ffc00000 { + compatible = "ramoops"; + reg = <0x0 0xffc00000 0x0 0x100000>; + record-size = <0x1000>; + console-size = <0x40000>; + msg-size = <0x20000 0x20000>; + ecc-size = <16>; + no-map; + }; + }; +}; + +&adsp { + status = "okay"; +}; + +&apps_rsc { + pm8150-rpmh-regulators { + 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_0p6>; + vdd-l6-l9-supply = <&vreg_s8c_1p2>; + 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 = ; + }; + + vreg_s5a_1p9: smps5 { + regulator-name = "vreg_s5a_1p9"; + regulator-min-microvolt = <1824000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s6a_0p6: smps6 { + regulator-name = "vreg_s6a_0p6"; + 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 = ; + }; + + /* 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_1p8: ldo14 { + regulator-name = "vreg_l14a_1p8"; + regulator-min-microvolt = <1800000>; + 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 = ; + }; + + vreg_l18a_0p9: ldo18 { + regulator-name = "vreg_l18a_0p9"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + /* + * Remaining regulators that are not yet supported: + * OLEDB: 4925000-8100000 + * ab: 4600000-6100000 + * ibb: 800000-5400000 + */ + pm8150l-rpmh-regulators { + 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_1p2>; + 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_1p2: smps8 { + regulator-name = "vreg_s8c_1p2"; + 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; + }; + + 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; + }; + + vreg_l10c_3p3: ldo10 { + regulator-name = "vreg_l10c_3p3"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3296000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p0: ldo11 { + regulator-name = "vreg_l11c_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + }; + + pm8009-rpmh-regulators { + compatible = "qcom,pm8009-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vreg_bob>; + vdd-l2-supply = <&vreg_s8c_1p2>; + 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 = <1200000>; + 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 = <1304000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + /* L3 & L4 are unused. */ + + vreg_l5f_2p8: ldo5 { + regulator-name = "vreg_l5f_2p85"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6f_2p8: ldo6 { + regulator-name = "vreg_l6f_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l7f_1p8: ldo7 { + regulator-name = "vreg_l7f_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; +}; + +&cdsp { + status = "okay"; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&gpi_dma2 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <400000>; + + /* NXP PN553 NFC @ 28 */ +}; + +&i2c2 { + status = "okay"; + clock-frequency = <1000000>; + + /* Dual Cirrus Logic CS35L41 amps @ 40, 41 */ +}; + +&i2c5 { + status = "okay"; + clock-frequency = <400000>; + + /* Dialog SLG51000 CMIC @ 75 */ +}; + +&i2c9 { + status = "okay"; + clock-frequency = <400000>; + + /* AMS TCS3490 RGB+IR color sensor @ 72 */ +}; + +&i2c13 { + status = "okay"; + clock-frequency = <400000>; + + touchscreen@48 { + compatible = "samsung,s6sy761"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + /* It's "vddio" downstream but it works anyway! */ + vdd-supply = <&vreg_l1c_1p8>; + avdd-supply = <&vreg_l10c_3p3>; + + pinctrl-names = "default"; + pinctrl-0 = <&ts_int_default>; + }; +}; + +&i2c15 { + status = "okay"; + clock-frequency = <400000>; + + /* Qcom SMB1390 @ 10 */ + /* Silicon Labs SI4704 FM Radio Receiver @ 11 */ + /* Qcom SMB1390_slave @ 18 */ + /* HALO HL6111R Qi charger @ 25 */ + /* Richwave RTC6226 FM Radio Receiver @ 64 */ +}; + +&pcie0 { + status = "okay"; +}; + +&pcie0_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; +}; + +&pcie2 { + status = "okay"; + + pinctrl-0 = <&pcie2_default_state &mdm2ap_default &ap2mdm_default>; +}; + +&pcie2_phy { + status = "okay"; + + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + + linux,code = ; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&qupv3_id_2 { + status = "okay"; +}; + +&sdhc_2 { + status = "okay"; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdc2_default_state &sdc2_card_det_n>; + pinctrl-1 = <&sdc2_sleep_state &sdc2_card_det_n>; + vmmc-supply = <&vreg_l9c_2p9>; + vqmmc-supply = <&vreg_l6c_2p9>; + bus-width = <4>; + no-sdio; + no-emmc; +}; + +&slpi { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <40 4>, <52 4>; + + sdc2_default_state: sdc2-default { + clk { + pins = "sdc2_clk"; + drive-strength = <16>; + bias-disable; + }; + + cmd { + pins = "sdc2_cmd"; + drive-strength = <16>; + bias-pull-up; + }; + + data { + pins = "sdc2_data"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + mdm2ap_default: mdm2ap-default { + pins = "gpio1", "gpio3"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + ts_int_default: ts-int-default { + pins = "gpio39"; + function = "gpio"; + drive-strength = <2>; + bias-disabled; + input-enable; + }; + + ap2mdm_default: ap2mdm-default { + pins = "gpio56", "gpio57"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + sdc2_card_det_n: sd-card-det-n { + pins = "gpio77"; + function = "gpio"; + bias-pull-up; + drive-strength = <2>; + }; +}; + +&uart12 { + status = "okay"; +}; + +/* BIG WARNING! DO NOT TOUCH UFS, YOUR DEVICE WILL DIE! */ +&ufs_mem_hc { status = "disabled"; }; +&ufs_mem_phy { status = "disabled"; }; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + status = "okay"; + + vdda-pll-supply = <&vreg_l5a_0p88>; + vdda18-supply = <&vreg_l12a_1p8>; + vdda33-supply = <&vreg_l2a_3p1>; +}; + +&usb_1_qmpphy { + status = "okay"; + + vdda-phy-supply = <&vreg_l9a_1p2>; + vdda-pll-supply = <&vreg_l18a_0p9>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 4c0de12aaba6..4798368b02ef 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -519,6 +521,26 @@ }; }; + gpi_dma2: dma-controller@800000 { + compatible = "qcom,sm8250-gpi-dma"; + reg = <0 0x00800000 0 0x70000>; + interrupts = , + , + , + , + , + , + , + , + , + ; + dma-channels = <10>; + dma-channel-mask = <0x3f>; + iommus = <&apps_smmu 0x76 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_2: geniqup@8c0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x008c0000 0x0 0x6000>; @@ -714,6 +736,29 @@ }; }; + gpi_dma0: dma-controller@900000 { + compatible = "qcom,sm8250-gpi-dma"; + reg = <0 0x00900000 0 0x70000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <15>; + dma-channel-mask = <0x7ff>; + iommus = <&apps_smmu 0x5b6 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_0: geniqup@9c0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x009c0000 0x0 0x6000>; @@ -961,6 +1006,26 @@ }; }; + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,sm8250-gpi-dma"; + reg = <0 0x00a00000 0 0x70000>; + interrupts = , + , + , + , + , + , + , + , + , + ; + dma-channels = <10>; + dma-channel-mask = <0x3f>; + iommus = <&apps_smmu 0x56 0x0>; + #dma-cells = <3>; + status = "disabled"; + }; + qupv3_id_1: geniqup@ac0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x00ac0000 0x0 0x6000>; @@ -1249,6 +1314,12 @@ phys = <&pcie0_lane>; phy-names = "pciephy"; + perst-gpio = <&tlmm 79 GPIO_ACTIVE_LOW>; + enable-gpio = <&tlmm 81 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_default_state>; + status = "disabled"; }; @@ -1347,6 +1418,12 @@ phys = <&pcie1_lane>; phy-names = "pciephy"; + perst-gpio = <&tlmm 82 GPIO_ACTIVE_LOW>; + enable-gpio = <&tlmm 84 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_default_state>; + status = "disabled"; }; @@ -1447,6 +1524,12 @@ phys = <&pcie2_lane>; phy-names = "pciephy"; + perst-gpio = <&tlmm 85 GPIO_ACTIVE_LOW>; + enable-gpio = <&tlmm 87 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_default_state>; + status = "disabled"; }; @@ -1470,7 +1553,7 @@ status = "disabled"; - pcie2_lane: lanes@1c0e200 { + pcie2_lane: lanes@1c16200 { reg = <0 0x1c16200 0 0x170>, /* tx0 */ <0 0x1c16400 0 0x200>, /* rx0 */ <0 0x1c16a00 0 0x1f0>, /* pcs */ @@ -1746,6 +1829,8 @@ qcom,gmu = <&gmu>; + status = "disabled"; + zap-shader { memory-region = <&gpu_mem>; }; @@ -1819,6 +1904,8 @@ operating-points-v2 = <&gmu_opp_table>; + status = "disabled"; + gmu_opp_table: opp-table { compatible = "operating-points-v2"; @@ -2323,6 +2410,8 @@ <&videocc VIDEO_CC_MVS0C_CLK_ARES>; reset-names = "bus", "core"; + status = "disabled"; + video-decoder { compatible = "venus-decoder"; }; @@ -2370,7 +2459,7 @@ }; mdss: mdss@ae00000 { - compatible = "qcom,sdm845-mdss"; + compatible = "qcom,sm8250-mdss"; reg = <0 0x0ae00000 0 0x1000>; reg-names = "mdss"; @@ -2402,7 +2491,7 @@ ranges; mdss_mdp: mdp@ae01000 { - compatible = "qcom,sdm845-dpu"; + compatible = "qcom,sm8250-dpu"; reg = <0 0x0ae01000 0 0x8f000>, <0 0x0aeb0000 0 0x2008>; reg-names = "mdp", "vbif"; @@ -2424,8 +2513,6 @@ interrupt-parent = <&mdss>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - ports { #address-cells = <1>; #size-cells = <0>; @@ -2499,6 +2586,9 @@ status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -2566,6 +2656,9 @@ status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -3395,6 +3488,95 @@ output-high; }; }; + + sdc2_sleep_state: sdc2-sleep { + clk { + pins = "sdc2_clk"; + drive-strength = <2>; + bias-disable; + }; + + cmd { + pins = "sdc2_cmd"; + drive-strength = <2>; + bias-pull-up; + }; + + data { + pins = "sdc2_data"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_default_state: pcie0-default { + perst { + pins = "gpio79"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio80"; + function = "pci_e0"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio81"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_default_state: pcie1-default { + perst { + pins = "gpio82"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio83"; + function = "pci_e1"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio84"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie2_default_state: pcie2-default { + perst { + pins = "gpio85"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq { + pins = "gpio86"; + function = "pci_e2"; + drive-strength = <2>; + bias-pull-up; + }; + + wake { + pins = "gpio87"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; }; apps_smmu: iommu@15000000 { diff --git a/arch/arm64/boot/dts/qcom/sm8350-mtp.dts b/arch/arm64/boot/dts/qcom/sm8350-mtp.dts index 6ca638b4e321..93740444dd1e 100644 --- a/arch/arm64/boot/dts/qcom/sm8350-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8350-mtp.dts @@ -364,3 +364,9 @@ vdda-phy-supply = <&vreg_l6b_1p2>; vdda-pll-supply = <&vreg_l5b_0p88>; }; + +&ipa { + status = "okay"; + + memory-region = <&pil_ipa_fw_mem>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index ed0b51bc03ea..0d16392bb976 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include / { interrupt-parent = <&intc>; @@ -391,6 +393,17 @@ 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>; + }; }; smp2p-slpi { @@ -629,6 +642,45 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; + ipa: ipa@1e40000 { + compatible = "qcom,sm8350-ipa"; + + iommus = <&apps_smmu 0x5c0 0x0>, + <&apps_smmu 0x5c2 0x0>; + reg = <0 0x1e40000 0 0x8000>, + <0 0x1e50000 0 0x4b20>, + <0 0x1e04000 0 0x23000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 655 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 &gem_noc SLAVE_LLCC>, + <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_IPA_CFG>; + interconnect-names = "ipa_to_llcc", + "llcc_to_ebi1", + "appss_to_ipa"; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; @@ -656,7 +708,7 @@ <&rpmhpd 12>; power-domain-names = "load_state", "cx", "mss"; - interconnects = <&mc_virt 0 &mc_virt 1>; + interconnects = <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>; memory-region = <&pil_modem_mem>; @@ -689,7 +741,7 @@ interrupt-controller; }; - tsens0: thermal-sensor@c222000 { + tsens0: thermal-sensor@c263000 { compatible = "qcom,sm8350-tsens", "qcom,tsens-v2"; reg = <0 0x0c263000 0 0x1ff>, /* TM */ <0 0x0c222000 0 0x8>; /* SROT */ @@ -700,7 +752,7 @@ #thermal-sensor-cells = <1>; }; - tsens1: thermal-sensor@c223000 { + tsens1: thermal-sensor@c265000 { compatible = "qcom,sm8350-tsens", "qcom,tsens-v2"; reg = <0 0x0c265000 0 0x1ff>, /* TM */ <0 0x0c223000 0 0x8>; /* SROT */ @@ -1063,7 +1115,7 @@ <&rpmhpd 10>; power-domain-names = "load_state", "cx", "mxc"; - interconnects = <&compute_noc 1 &mc_virt 1>; + interconnects = <&compute_noc MASTER_CDSP_PROC &mc_virt SLAVE_EBI1>; memory-region = <&pil_cdsp_mem>; @@ -1176,7 +1228,7 @@ }; }; - dc_noc: interconnect@90e0000 { + dc_noc: interconnect@90c0000 { compatible = "qcom,sm8350-dc-noc"; reg = <0 0x090c0000 0 0x4200>; #interconnect-cells = <1>; @@ -1317,7 +1369,7 @@ }; }; - thermal-zones { + thermal_zones: thermal-zones { cpu0-thermal { polling-delay-passive = <250>; polling-delay = <1000>; diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile index f2de2fa0c8b8..68e30e26564b 100644 --- a/arch/arm64/boot/dts/renesas/Makefile +++ b/arch/arm64/boot/dts/renesas/Makefile @@ -62,3 +62,5 @@ dtb-$(CONFIG_ARCH_R8A77990) += r8a77990-ebisu.dtb dtb-$(CONFIG_ARCH_R8A77995) += r8a77995-draak.dtb dtb-$(CONFIG_ARCH_R8A779A0) += r8a779a0-falcon.dtb + +dtb-$(CONFIG_ARCH_R9A07G044) += r9a07g044l2-smarc.dtb diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi index d8046fedf9c1..e3c8b2fe143e 100644 --- a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi +++ b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi @@ -271,12 +271,12 @@ &ehci0 { dr_mode = "otg"; status = "okay"; - clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>; + clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, <&usb2_clksel>, <&versaclock5 3>; }; &ehci1 { status = "okay"; - clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>; + clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, <&usb2_clksel>, <&versaclock5 3>; }; &hdmi0 { diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi index 8d3a4d6ee885..090dc9c4f57b 100644 --- a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi +++ b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi @@ -53,6 +53,8 @@ phy-handle = <&phy0>; rx-internal-delay-ps = <1800>; tx-internal-delay-ps = <2000>; + clocks = <&cpg CPG_MOD 812>, <&versaclock5 4>; + clock-names = "fck", "refclk"; status = "okay"; phy0: ethernet-phy@0 { @@ -319,8 +321,10 @@ status = "okay"; }; -&usb_extal_clk { - clock-frequency = <50000000>; +&usb2_clksel { + clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>, + <&versaclock5 3>, <&usb3s0_clk>; + status = "okay"; }; &usb3s0_clk { diff --git a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi index 46f8dbf68904..78c121a89f11 100644 --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi @@ -76,6 +76,7 @@ opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <820000>; clock-latency-ns = <300000>; + opp-suspend; }; }; @@ -1127,6 +1128,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a774b1.dtsi b/arch/arm64/boot/dts/renesas/r8a774b1.dtsi index d16a4be5ef77..28c612ce49c0 100644 --- a/arch/arm64/boot/dts/renesas/r8a774b1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774b1.dtsi @@ -1001,6 +1001,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi index 1aef34447abd..a5d4dce8476d 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774c0.dtsi @@ -957,6 +957,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a774e1.dtsi b/arch/arm64/boot/dts/renesas/r8a774e1.dtsi index 1f51237ab0a6..379a1300272b 100644 --- a/arch/arm64/boot/dts/renesas/r8a774e1.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a774e1.dtsi @@ -1230,6 +1230,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77951.dtsi b/arch/arm64/boot/dts/renesas/r8a77951.dtsi index 85d66d15465a..2e4c18b8eee4 100644 --- a/arch/arm64/boot/dts/renesas/r8a77951.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77951.dtsi @@ -1312,6 +1312,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77960.dtsi b/arch/arm64/boot/dts/renesas/r8a77960.dtsi index 12476e354d74..2bd8169735d3 100644 --- a/arch/arm64/boot/dts/renesas/r8a77960.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77960.dtsi @@ -63,18 +63,19 @@ opp-500000000 { opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; }; opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; }; opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; + opp-suspend; }; opp-1600000000 { opp-hz = /bits/ 64 <1600000000>; @@ -1188,6 +1189,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77961.dtsi b/arch/arm64/boot/dts/renesas/r8a77961.dtsi index d9804768425a..91b501e0121e 100644 --- a/arch/arm64/boot/dts/renesas/r8a77961.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77961.dtsi @@ -52,18 +52,19 @@ opp-500000000 { opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; }; opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; }; opp-1500000000 { opp-hz = /bits/ 64 <1500000000>; - opp-microvolt = <820000>; + opp-microvolt = <830000>; clock-latency-ns = <300000>; + opp-suspend; }; opp-1600000000 { opp-hz = /bits/ 64 <1600000000>; @@ -559,10 +560,19 @@ }; intc_ex: interrupt-controller@e61c0000 { + compatible = "renesas,intc-ex-r8a77961", "renesas,irqc"; #interrupt-cells = <2>; interrupt-controller; reg = <0 0xe61c0000 0 0x200>; - /* placeholder */ + interrupts = , + , + , + , + , + ; + clocks = <&cpg CPG_MOD 407>; + power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; + resets = <&cpg 407>; }; tmu0: timer@e61e0000 { @@ -1144,6 +1154,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77961_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi index dcb9df861d74..ad69da362a72 100644 --- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi @@ -1050,6 +1050,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77965_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 874a7fc2730b..5c84681703ed 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -73,6 +73,12 @@ /* first 128MB is reserved for secure area. */ reg = <0x0 0x48000000 0x0 0x38000000>; }; + + x1_clk: x1-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <148500000>; + }; }; &avb { @@ -104,6 +110,8 @@ }; &du { + clocks = <&cpg CPG_MOD 724>, <&x1_clk>; + clock-names = "du.0", "dclkin.0"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts index 7417cf5fea0f..2426e533128c 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts @@ -59,7 +59,7 @@ memory@48000000 { device_type = "memory"; /* first 128MB is reserved for secure area. */ - reg = <0x0 0x48000000 0x0 0x38000000>; + reg = <0x0 0x48000000 0x0 0x78000000>; }; osc5_clk: osc5-clock { diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi index e8f6352c3665..517892cf6294 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi @@ -612,6 +612,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77970_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts index 04d47c0c9bb9..7bde0a549c09 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts +++ b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts @@ -210,7 +210,7 @@ &mmc0 { pinctrl-0 = <&mmc_pins>; - pinctrl-1 = <&mmc_pins_uhs>; + pinctrl-1 = <&mmc_pins>; pinctrl-names = "default", "state_uhs"; vmmc-supply = <&d3_3v>; @@ -253,12 +253,6 @@ }; mmc_pins: mmc { - groups = "mmc_data8", "mmc_ctrl", "mmc_ds"; - function = "mmc"; - power-source = <3300>; - }; - - mmc_pins_uhs: mmc_uhs { groups = "mmc_data8", "mmc_ctrl", "mmc_ds"; function = "mmc"; power-source = <1800>; diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi index 7b51d464de0e..6347d15e66b6 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi @@ -664,6 +664,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77980_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi index 0eaea58f4210..4d0304bc9745 100644 --- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi @@ -1000,6 +1000,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77990_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi index 2319271c881b..84dba3719381 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi @@ -760,6 +760,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 812>; + clock-names = "fck"; power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; resets = <&cpg 812>; phy-mode = "rgmii"; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi index 14d3db5d6c16..f791c76f1bcf 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-csi-dsi.dtsi @@ -6,6 +6,27 @@ */ &i2c0 { + pca9654_a: gpio@21 { + compatible = "onnn,pca9654"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9654_b: gpio@22 { + compatible = "onnn,pca9654"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9654_c: gpio@23 { + compatible = "onnn,pca9654"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + }; + eeprom@52 { compatible = "rohm,br24g01", "atmel,24c01"; label = "csi-dsi-sub-board-id"; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi index 70b3604e56cd..78ca75f619f6 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi @@ -618,6 +618,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 211>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 211>; phy-mode = "rgmii"; @@ -665,6 +666,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 212>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 212>; phy-mode = "rgmii"; @@ -712,6 +714,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 213>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 213>; phy-mode = "rgmii"; @@ -759,6 +762,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 214>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 214>; phy-mode = "rgmii"; @@ -806,6 +810,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 215>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 215>; phy-mode = "rgmii"; @@ -853,6 +858,7 @@ "ch20", "ch21", "ch22", "ch23", "ch24"; clocks = <&cpg CPG_MOD 216>; + clock-names = "fck"; power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; resets = <&cpg 216>; phy-mode = "rgmii"; @@ -1096,7 +1102,6 @@ <0x0 0xf1060000 0 0x110000>; interrupts = ; - power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; }; fcpvd0: fcp@fea10000 { diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi new file mode 100644 index 000000000000..734c8adeceba --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/G2L and RZ/G2LC common SoC parts + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include +#include + +/ { + compatible = "renesas,r9a07g044"; + #address-cells = <2>; + #size-cells = <2>; + + /* clock can be either from exclk or crystal oscillator (XIN/XOUT) */ + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a55"; + reg = <0>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + compatible = "arm,cortex-a55"; + reg = <0x100>; + device_type = "cpu"; + next-level-cache = <&L3_CA55>; + enable-method = "psci"; + }; + + L3_CA55: cache-controller-0 { + compatible = "cache"; + cache-unified; + cache-size = <0x40000>; + }; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + scif0: serial@1004b800 { + compatible = "renesas,scif-r9a07g044"; + reg = <0 0x1004b800 0 0x400>; + interrupts = , + , + , + , + , + ; + interrupt-names = "eri", "rxi", "txi", + "bri", "dri", "tei"; + clocks = <&cpg CPG_MOD R9A07G044_CLK_SCIF0>; + clock-names = "fck"; + power-domains = <&cpg>; + resets = <&cpg R9A07G044_CLK_SCIF0>; + status = "disabled"; + }; + + cpg: clock-controller@11010000 { + compatible = "renesas,r9a07g044-cpg"; + reg = <0 0x11010000 0 0x10000>; + clocks = <&extal_clk>; + clock-names = "extal"; + #clock-cells = <2>; + #reset-cells = <1>; + #power-domain-cells = <0>; + }; + + sysc: system-controller@11020000 { + compatible = "renesas,r9a07g044-sysc"; + reg = <0 0x11020000 0 0x10000>; + interrupts = , + , + , + ; + interrupt-names = "lpm_int", "ca55stbydone_int", + "cm33stbyr_int", "ca55_deny"; + status = "disabled"; + }; + + gic: interrupt-controller@11900000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x0 0x11900000 0 0x40000>, + <0x0 0x11940000 0 0x60000>; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r9a07g044l1.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044l1.dtsi new file mode 100644 index 000000000000..9d89d4590358 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a07g044l1.dtsi @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/G2L R9A07G044L1 SoC specific parts + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r9a07g044.dtsi" + +/ { + compatible = "renesas,r9a07g044l1", "renesas,r9a07g044"; + + cpus { + /delete-node/ cpu-map; + /delete-node/ cpu@100; + }; + + timer { + interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r9a07g044l2-smarc.dts b/arch/arm64/boot/dts/renesas/r9a07g044l2-smarc.dts new file mode 100644 index 000000000000..d3f72ec62f03 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a07g044l2-smarc.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/G2L SMARC EVK board + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r9a07g044l2.dtsi" +#include "rzg2l-smarc.dtsi" + +/ { + model = "Renesas SMARC EVK based on r9a07g044l2"; + compatible = "renesas,smarc-evk", "renesas,r9a07g044l2", "renesas,r9a07g044"; + + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ + reg = <0x0 0x48000000 0x0 0x78000000>; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r9a07g044l2.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044l2.dtsi new file mode 100644 index 000000000000..91dc10b2cdbb --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r9a07g044l2.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/G2L R9A07G044L2 SoC specific parts + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +/dts-v1/; +#include "r9a07g044.dtsi" + +/ { + compatible = "renesas,r9a07g044l2", "renesas,r9a07g044"; +}; diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi new file mode 100644 index 000000000000..adcd4f50519e --- /dev/null +++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Device Tree Source for the RZ/G2L SMARC EVK common parts + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include + +/ { + aliases { + serial0 = &scif0; + }; + + chosen { + bootargs = "ignore_loglevel"; + stdout-path = "serial0:115200n8"; + }; +}; + +&extal_clk { + clock-frequency = <24000000>; +}; + +&scif0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index c3e00c0e2db7..7fdb41de01ec 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -51,3 +51,4 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rockpro64.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-v10.dtb diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi index 09baa8a167ce..248ebb61aa79 100644 --- a/arch/arm64/boot/dts/rockchip/px30.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30.dtsi @@ -244,28 +244,31 @@ #size-cells = <0>; /* These power domains are grouped by VD_LOGIC */ - pd_usb@PX30_PD_USB { + power-domain@PX30_PD_USB { reg = ; clocks = <&cru HCLK_HOST>, <&cru HCLK_OTG>, <&cru SCLK_OTG_ADP>; pm_qos = <&qos_usb_host>, <&qos_usb_otg>; + #power-domain-cells = <0>; }; - pd_sdcard@PX30_PD_SDCARD { + power-domain@PX30_PD_SDCARD { reg = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; pm_qos = <&qos_sdmmc>; + #power-domain-cells = <0>; }; - pd_gmac@PX30_PD_GMAC { + power-domain@PX30_PD_GMAC { reg = ; clocks = <&cru ACLK_GMAC>, <&cru PCLK_GMAC>, <&cru SCLK_MAC_REF>, <&cru SCLK_GMAC_RX_TX>; pm_qos = <&qos_gmac>; + #power-domain-cells = <0>; }; - pd_mmc_nand@PX30_PD_MMC_NAND { + power-domain@PX30_PD_MMC_NAND { reg = ; clocks = <&cru HCLK_NANDC>, <&cru HCLK_EMMC>, @@ -277,15 +280,17 @@ <&cru SCLK_SFC>; pm_qos = <&qos_emmc>, <&qos_nand>, <&qos_sdio>, <&qos_sfc>; + #power-domain-cells = <0>; }; - pd_vpu@PX30_PD_VPU { + power-domain@PX30_PD_VPU { reg = ; clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>, <&cru SCLK_CORE_VPU>; pm_qos = <&qos_vpu>, <&qos_vpu_r128>; + #power-domain-cells = <0>; }; - pd_vo@PX30_PD_VO { + power-domain@PX30_PD_VO { reg = ; clocks = <&cru ACLK_RGA>, <&cru ACLK_VOPB>, @@ -300,8 +305,9 @@ <&cru SCLK_VOPB_PWM>; pm_qos = <&qos_rga_rd>, <&qos_rga_wr>, <&qos_vop_m0>, <&qos_vop_m1>; + #power-domain-cells = <0>; }; - pd_vi@PX30_PD_VI { + power-domain@PX30_PD_VI { reg = ; clocks = <&cru ACLK_CIF>, <&cru ACLK_ISP>, @@ -311,11 +317,13 @@ pm_qos = <&qos_isp_128>, <&qos_isp_rd>, <&qos_isp_wr>, <&qos_isp_m1>, <&qos_vip>; + #power-domain-cells = <0>; }; - pd_gpu@PX30_PD_GPU { + power-domain@PX30_PD_GPU { reg = ; clocks = <&cru SCLK_GPU>; pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; }; }; }; @@ -814,7 +822,7 @@ #address-cells = <1>; #size-cells = <1>; - u2phy: usb2-phy@100 { + u2phy: usb2phy@100 { compatible = "rockchip,px30-usb2phy"; reg = <0x100 0x20>; clocks = <&pmucru SCLK_USBPHY_REF>; @@ -1087,7 +1095,6 @@ compatible = "rockchip,iommu"; reg = <0x0 0xff460f00 0x0 0x100>; interrupts = ; - interrupt-names = "vopb_mmu"; clocks = <&cru ACLK_VOPB>, <&cru HCLK_VOPB>; clock-names = "aclk", "iface"; power-domains = <&power PX30_PD_VO>; @@ -1128,7 +1135,6 @@ compatible = "rockchip,iommu"; reg = <0x0 0xff470f00 0x0 0x100>; interrupts = ; - interrupt-names = "vopl_mmu"; clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>; clock-names = "aclk", "iface"; power-domains = <&power PX30_PD_VO>; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts index 3dddd4742c3a..665b2e69455d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts @@ -84,8 +84,8 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_HIGH>; - states = <1800000 0x0 - 3300000 0x1>; + states = <1800000 0x0>, + <3300000 0x1>; vin-supply = <&vcc5v0_sys>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index b815ce73e5c6..a185901aba9a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -164,7 +164,7 @@ grf: grf@ff000000 { compatible = "rockchip,rk3308-grf", "syscon", "simple-mfd"; - reg = <0x0 0xff000000 0x0 0x10000>; + reg = <0x0 0xff000000 0x0 0x08000>; reboot-mode { compatible = "syscon-reboot-mode"; @@ -177,6 +177,42 @@ }; }; + usb2phy_grf: syscon@ff008000 { + compatible = "rockchip,rk3308-usb2phy-grf", "syscon", "simple-mfd"; + reg = <0x0 0xff008000 0x0 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + + u2phy: usb2phy@100 { + compatible = "rockchip,rk3308-usb2phy"; + reg = <0x100 0x10>; + assigned-clocks = <&cru USB480M>; + assigned-clock-parents = <&u2phy>; + clocks = <&cru SCLK_USBPHY_REF>; + clock-names = "phyclk"; + clock-output-names = "usb480m_phy"; + #clock-cells = <0>; + status = "disabled"; + + u2phy_otg: otg-port { + interrupts = , + , + ; + interrupt-names = "otg-bvalid", "otg-id", + "linestate"; + #phy-cells = <0>; + status = "disabled"; + }; + + u2phy_host: host-port { + interrupts = ; + interrupt-names = "linestate"; + #phy-cells = <0>; + status = "disabled"; + }; + }; + }; + detect_grf: syscon@ff00b000 { compatible = "rockchip,rk3308-detect-grf", "syscon", "simple-mfd"; reg = <0x0 0xff00b000 0x0 0x1000>; @@ -579,6 +615,42 @@ status = "disabled"; }; + usb20_otg: usb@ff400000 { + compatible = "rockchip,rk3308-usb", "rockchip,rk3066-usb", + "snps,dwc2"; + reg = <0x0 0xff400000 0x0 0x40000>; + interrupts = ; + 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 = <&u2phy_otg>; + phy-names = "usb2-phy"; + status = "disabled"; + }; + + usb_host_ehci: usb@ff440000 { + compatible = "generic-ehci"; + reg = <0x0 0xff440000 0x0 0x10000>; + interrupts = ; + clocks = <&cru HCLK_HOST>, <&cru HCLK_HOST_ARB>, <&u2phy>; + phys = <&u2phy_host>; + phy-names = "usb"; + status = "disabled"; + }; + + usb_host_ohci: usb@ff450000 { + compatible = "generic-ohci"; + reg = <0x0 0xff450000 0x0 0x10000>; + interrupts = ; + clocks = <&cru HCLK_HOST>, <&cru HCLK_HOST_ARB>, <&u2phy>; + phys = <&u2phy_host>; + phy-names = "usb"; + status = "disabled"; + }; + sdmmc: mmc@ff480000 { compatible = "rockchip,rk3308-dw-mshc", "rockchip,rk3288-dw-mshc"; reg = <0x0 0xff480000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts index 49c97f76df77..7fc674a99a6c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts @@ -165,6 +165,31 @@ }; }; + rk817-sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "Analog"; + simple-audio-card,format = "i2s"; + simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,widgets = + "Microphone", "Mic Jack", + "Headphone", "Headphones", + "Speaker", "Speaker"; + simple-audio-card,routing = + "MICL", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR", + "Speaker", "SPKO"; + + simple-audio-card,codec { + sound-dai = <&rk817>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1_2ch>; + }; + }; + vccsys: vccsys { compatible = "regulator-fixed"; regulator-name = "vcc3v8_sys"; @@ -239,6 +264,7 @@ backlight = <&backlight>; iovcc-supply = <&vcc_lcd>; reset-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>; + rotation = <270>; vdd-supply = <&vcc_lcd>; port { @@ -269,11 +295,14 @@ reg = <0x20>; interrupt-parent = <&gpio0>; interrupts = ; + clock-output-names = "rk808-clkout1", "xin32k"; + clock-names = "mclk"; + clocks = <&cru SCLK_I2S1_OUT>; pinctrl-names = "default"; - pinctrl-0 = <&pmic_int>; + pinctrl-0 = <&pmic_int>, <&i2s1_2ch_mclk>; wakeup-source; #clock-cells = <1>; - clock-output-names = "rk808-clkout1", "xin32k"; + #sound-dai-cells = <0>; vcc1-supply = <&vccsys>; vcc2-supply = <&vccsys>; @@ -432,6 +461,10 @@ }; }; }; + + rk817_codec: codec { + rockchip,mic-in-differential; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts index f807bc066ccb..3857d487ab84 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts @@ -14,6 +14,7 @@ compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328"; aliases { + ethernet1 = &rtl8153; mmc0 = &sdmmc; }; @@ -76,8 +77,8 @@ regulator-settling-time-us = <5000>; regulator-type = "voltage"; startup-delay-us = <2000>; - states = <1800000 0x1 - 3300000 0x0>; + states = <1800000 0x1>, + <3300000 0x0>; vin-supply = <&vcc_io_33>; }; @@ -101,6 +102,18 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; }; + + vdd_5v_lan: vdd-5v-lan { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&lan_vdd_pin>; + pinctrl-names = "default"; + regulator-name = "vdd_5v_lan"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vdd_5v>; + }; }; &cpu0 { @@ -309,6 +322,12 @@ }; }; + lan { + lan_vdd_pin: lan-vdd-pin { + rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + pmic { pmic_int_l: pmic-int-l { rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; @@ -368,6 +387,19 @@ dr_mode = "host"; }; +&usbdrd3 { + dr_mode = "host"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + /* Second port is for USB 3.0 */ + rtl8153: device@2 { + compatible = "usbbda,8153"; + reg = <2>; + }; +}; + &usb_host0_ehci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts index a05732b59f38..aa22a0c22265 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts @@ -50,8 +50,8 @@ vcc_sdio: sdmmcio-regulator { compatible = "regulator-gpio"; gpios = <&grf_gpio 0 GPIO_ACTIVE_HIGH>; - states = <1800000 0x1 - 3300000 0x0>; + states = <1800000 0x1>, + <3300000 0x0>; regulator-name = "vcc_sdio"; regulator-type = "voltage"; regulator-min-microvolt = <1800000>; @@ -363,6 +363,11 @@ status = "okay"; }; +&usbdrd3 { + dr_mode = "host"; + status = "okay"; +}; + &usb_host0_ehci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts index c7e31efdd2e1..018a3a5075c7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts @@ -177,8 +177,6 @@ }; &gmac2phy { - pinctrl-names = "default"; - pinctrl-0 = <&fephyled_linkm1>, <&fephyled_rxm1>; status = "okay"; }; @@ -382,6 +380,11 @@ status = "okay"; }; +&usbdrd3 { + dr_mode = "host"; + status = "okay"; +}; + &usb_host0_ehci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index 3bef1f39bc6e..1b0f7e4551ea 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -381,6 +381,11 @@ status = "okay"; }; +&usbdrd3 { + dr_mode = "host"; + status = "okay"; +}; + &usb_host0_ehci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 3ed69ecbcf3c..8c821acb21ff 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -288,7 +288,7 @@ status = "disabled"; }; - grf_gpio: grf-gpio { + grf_gpio: gpio { compatible = "rockchip,rk3328-grf-gpio"; gpio-controller; #gpio-cells = <2>; @@ -300,15 +300,18 @@ #address-cells = <1>; #size-cells = <0>; - pd_hevc@RK3328_PD_HEVC { + power-domain@RK3328_PD_HEVC { reg = ; + #power-domain-cells = <0>; }; - pd_video@RK3328_PD_VIDEO { + power-domain@RK3328_PD_VIDEO { reg = ; + #power-domain-cells = <0>; }; - pd_vpu@RK3328_PD_VPU { + power-domain@RK3328_PD_VPU { reg = ; clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + #power-domain-cells = <0>; }; }; @@ -816,7 +819,7 @@ #address-cells = <1>; #size-cells = <1>; - u2phy: usb2-phy@100 { + u2phy: usb2phy@100 { compatible = "rockchip,rk3328-usb2phy"; reg = <0x100 0x10>; clocks = <&xin24m>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index dfc6376171d0..4c64fbefb483 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -664,6 +664,8 @@ compatible = "rockchip,rk3368-timer", "rockchip,rk3288-timer"; reg = <0x0 0xff810000 0x0 0x20>; interrupts = ; + clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER00>; + clock-names = "pclk", "timer"; }; spdif: spdif@ff880000 { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index 45254be1350d..c4dd2a6b4836 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -6,6 +6,7 @@ /dts-v1/; #include #include +#include #include "rk3399.dtsi" #include "rk3399-opp.dtsi" @@ -94,6 +95,13 @@ }; }; + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&ir_int>; + pinctrl-names = "default"; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -151,6 +159,23 @@ reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; }; + sound-dit { + compatible = "audio-graph-card"; + label = "SPDIF"; + dais = <&spdif_p0>; + }; + + spdif-dit { + compatible = "linux,spdif-dit"; + #sound-dai-cells = <0>; + + port { + dit_p0_0: endpoint { + remote-endpoint = <&spdif_p0_0>; + }; + }; + }; + /* switched by pmic_sleep */ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { compatible = "regulator-fixed"; @@ -196,6 +221,17 @@ vin-supply = <&vcc_sys>; }; + vcc5v0_typec: vcc5v0-typec-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_typec_en>; + regulator-name = "vcc5v0_typec"; + regulator-always-on; + vin-supply = <&vcc_sys>; + }; + vcc_sys: vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; @@ -521,6 +557,53 @@ i2c-scl-falling-time-ns = <20>; status = "okay"; + fusb0: typec-portc@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio1>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&fusb0_int>; + vbus-supply = <&vcc5v0_typec>; + status = "okay"; + + connector { + compatible = "usb-c-connector"; + data-role = "host"; + label = "USB-C"; + op-sink-microwatt = <1000000>; + power-role = "dual"; + sink-pdos = + ; + source-pdos = + ; + try-power-role = "sink"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usbc_hs: endpoint { + remote-endpoint = + <&u2phy0_typec_hs>; + }; + }; + + port@1 { + reg = <1>; + + usbc_ss: endpoint { + remote-endpoint = + <&tcphy0_typec_ss>; + }; + }; + }; + }; + }; + accelerometer@68 { compatible = "invensense,mpu6500"; reg = <0x68>; @@ -578,12 +661,34 @@ }; }; + fusb302x { + fusb0_int: fusb0-int { + rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + ir { + ir_int: ir-int { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + lcd-panel { lcd_panel_reset: lcd-panel-reset { rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>; }; }; + leds { + work_led_pin: work-led-pin { + rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + diy_led_pin: diy-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + pcie { pcie_pwr_en: pcie-pwr-en { rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; @@ -595,6 +700,10 @@ }; pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + vsel1_pin: vsel1-pin { rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; }; @@ -604,21 +713,21 @@ }; }; - sdio-pwrseq { - wifi_enable_h: wifi-enable-h { - rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - rt5640 { rt5640_hpcon: rt5640-hpcon { rockchip,pins = <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; }; }; - pmic { - pmic_int_l: pmic-int-l { - rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb-typec { + vcc5v0_typec_en: vcc5v0_typec_en { + rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; }; }; @@ -633,16 +742,6 @@ rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; }; }; - - leds { - work_led_pin: work-led-pin { - rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - diy_led_pin: diy-led-pin { - rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; }; &pwm0 { @@ -710,10 +809,29 @@ status = "okay"; }; +&spdif { + pinctrl-0 = <&spdif_bus_1>; + status = "okay"; + + spdif_p0: port { + spdif_p0_0: endpoint { + remote-endpoint = <&dit_p0_0>; + }; + }; +}; + &tcphy0 { status = "okay"; }; +&tcphy0_usb3 { + port { + tcphy0_typec_ss: endpoint { + remote-endpoint = <&usbc_ss>; + }; + }; +}; + &tcphy1 { status = "okay"; }; @@ -737,6 +855,12 @@ phy-supply = <&vcc5v0_host>; status = "okay"; }; + + port { + u2phy0_typec_hs: endpoint { + remote-endpoint = <&usbc_hs>; + }; + }; }; &u2phy1 { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi index beee5fbb3443..5d7a9d96d163 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi @@ -245,7 +245,7 @@ pp1800_pcie: &pp1800_s0 { }; &ppvar_sd_card_io { - states = <1800000 0x0 3300000 0x1>; + states = <1800000 0x0>, <3300000 0x1>; regulator-max-microvolt = <3300000>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi index 4002742fed4c..c1bcc8ca3769 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi @@ -252,8 +252,8 @@ enable-active-high; enable-gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>; gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; - states = <1800000 0x1 - 3000000 0x0>; + states = <1800000 0x1>, + <3000000 0x0>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index 19485b552bc4..738cfd21df3e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -23,6 +23,16 @@ mmc1 = &sdhci; }; + avdd_0v9_s0: avdd-0v9-s0 { + compatible = "regulator-fixed"; + regulator-name = "avdd_0v9_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + vin-supply = <&vcc1v8_sys_s3>; + }; + avdd_1v8_s0: avdd-1v8-s0 { compatible = "regulator-fixed"; regulator-name = "avdd_1v8_s0"; @@ -40,6 +50,20 @@ #clock-cells = <0>; }; + fan1 { + /* fan connected to P7 */ + compatible = "pwm-fan"; + pwms = <&pwm0 0 40000 0>; + cooling-levels = <0 80 170 255>; + }; + + fan2 { + /* fan connected to P6 */ + compatible = "pwm-fan"; + pwms = <&pwm1 0 40000 0>; + cooling-levels = <0 80 170 255>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -58,6 +82,18 @@ }; }; + pcie_power: pcie-power { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie_pwr>; + pinctrl-names = "default"; + regulator-boot-on; + regulator-name = "pcie_power"; + startup-delay-us = <10000>; + vin-supply = <&vcc5v0_perdev>; + }; + vcc1v8_sys_s0: vcc1v8-sys-s0 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_sys_s0"; @@ -95,6 +131,16 @@ }; }; + vcc5v0_perdev: vcc5v0-perdev { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_perdev"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin_bkup>; + }; + vcc5v0_sys: vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; @@ -109,6 +155,20 @@ }; }; + vcc5v0_usb: vcc5v0-usb { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_usb_en>; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_perdev>; + }; + vcc12v_dcin: vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; @@ -317,6 +377,20 @@ status = "okay"; }; +&pcie_phy { + status = "okay"; +}; + +&pcie0 { + num-lanes = <2>; + status = "okay"; + + vpcie12v-supply = <&vcc12v_dcin>; + vpcie3v3-supply = <&pcie_power>; + vpcie1v8-supply = <&avdd_1v8_s0>; + vpcie0v9-supply = <&avdd_0v9_s0>; +}; + &pinctrl { gmac { gphy_reset: gphy-reset { @@ -334,12 +408,25 @@ }; }; + pcie { + pcie_pwr: pcie-pwr { + rockchip,pins = + <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + pmic { pmic_int_l: pmic-int-l { rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; }; }; + power { + vcc5v0_usb_en: vcc5v0-usb-en { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + vcc3v0-sd { sdmmc0_pwr_h: sdmmc0-pwr-h { rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; @@ -352,6 +439,16 @@ status = "okay"; }; +&pwm0 { + /* pwm-fan on P7 */ + status = "okay"; +}; + +&pwm1 { + /* pwm-fan on P6 */ + status = "okay"; +}; + &sdhci { bus-width = <8>; mmc-hs200-1_8v; @@ -372,6 +469,30 @@ status = "okay"; }; +&tcphy1 { + /* phy for &usbdrd_dwc3_1 */ + status = "okay"; +}; + +&u2phy1 { + status = "okay"; + + otg-port { + /* phy for &usbdrd_dwc3_1 */ + phy-supply = <&vcc5v0_usb>; + status = "okay"; + }; +}; + &uart2 { status = "okay"; }; + +&usbdrd3_1 { + status = "okay"; + + usb@fe900000 { + dr_mode = "host"; + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts index fa5809887643..cef4d18b599d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts @@ -33,7 +33,7 @@ sys_led: led-sys { gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; - label = "red:sys"; + label = "red:power"; default-state = "on"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi index 16fd58c4a80f..8c0ff6c96e03 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi @@ -510,7 +510,6 @@ }; &pcie0 { - max-link-speed = <2>; num-lanes = <2>; vpcie0v9-supply = <&vcca0v9_s3>; vpcie1v8-supply = <&vcca1v8_s3>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi index c172f5a803e7..d1aaf8e83391 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi @@ -63,6 +63,13 @@ }; }; + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_int>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -389,6 +396,7 @@ vcc_sdio: LDO_REG4 { regulator-name = "vcc_sdio"; + regulator-always-on; regulator-boot-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3000000>; @@ -493,6 +501,8 @@ regulator-min-microvolt = <712500>; regulator-max-microvolt = <1500000>; regulator-ramp-delay = <1000>; + regulator-always-on; + regulator-boot-on; vin-supply = <&vcc3v3_sys>; regulator-state-mem { @@ -601,6 +611,12 @@ }; }; + ir { + ir_int: ir-int { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + lcd-panel { lcd_panel_reset: lcd-panel-reset { rockchip,pins = <4 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi index 7d0a7c697703..b28888ea9262 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi @@ -474,7 +474,6 @@ &pcie0 { ep-gpios = <&gpio4 RK_PD3 GPIO_ACTIVE_HIGH>; - max-link-speed = <2>; num-lanes = <4>; pinctrl-0 = <&pcie_clkreqnb_cpm>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 634a91af8e83..3871c7fd83b0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -227,7 +227,7 @@ <&pcie_phy 2>, <&pcie_phy 3>; phy-names = "pcie-phy-0", "pcie-phy-1", "pcie-phy-2", "pcie-phy-3"; - ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>, + ranges = <0x82000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>, <0x81000000 0x0 0xfbe00000 0x0 0xfbe00000 0x0 0x100000>; resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>, @@ -968,126 +968,146 @@ #size-cells = <0>; /* These power domains are grouped by VD_CENTER */ - pd_iep@RK3399_PD_IEP { + power-domain@RK3399_PD_IEP { reg = ; clocks = <&cru ACLK_IEP>, <&cru HCLK_IEP>; pm_qos = <&qos_iep>; + #power-domain-cells = <0>; }; - pd_rga@RK3399_PD_RGA { + power-domain@RK3399_PD_RGA { reg = ; clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>; pm_qos = <&qos_rga_r>, <&qos_rga_w>; + #power-domain-cells = <0>; }; - pd_vcodec@RK3399_PD_VCODEC { + power-domain@RK3399_PD_VCODEC { reg = ; clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; pm_qos = <&qos_video_m0>; + #power-domain-cells = <0>; }; - pd_vdu@RK3399_PD_VDU { + power-domain@RK3399_PD_VDU { reg = ; clocks = <&cru ACLK_VDU>, <&cru HCLK_VDU>; pm_qos = <&qos_video_m1_r>, <&qos_video_m1_w>; + #power-domain-cells = <0>; }; /* These power domains are grouped by VD_GPU */ - pd_gpu@RK3399_PD_GPU { + power-domain@RK3399_PD_GPU { reg = ; clocks = <&cru ACLK_GPU>; pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; }; /* These power domains are grouped by VD_LOGIC */ - pd_edp@RK3399_PD_EDP { + power-domain@RK3399_PD_EDP { reg = ; clocks = <&cru PCLK_EDP_CTRL>; + #power-domain-cells = <0>; }; - pd_emmc@RK3399_PD_EMMC { + power-domain@RK3399_PD_EMMC { reg = ; clocks = <&cru ACLK_EMMC>; pm_qos = <&qos_emmc>; + #power-domain-cells = <0>; }; - pd_gmac@RK3399_PD_GMAC { + power-domain@RK3399_PD_GMAC { reg = ; clocks = <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; pm_qos = <&qos_gmac>; + #power-domain-cells = <0>; }; - pd_sd@RK3399_PD_SD { + power-domain@RK3399_PD_SD { reg = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>; pm_qos = <&qos_sd>; + #power-domain-cells = <0>; }; - pd_sdioaudio@RK3399_PD_SDIOAUDIO { + power-domain@RK3399_PD_SDIOAUDIO { reg = ; clocks = <&cru HCLK_SDIO>; pm_qos = <&qos_sdioaudio>; + #power-domain-cells = <0>; }; - pd_tcpc0@RK3399_PD_TCPD0 { + power-domain@RK3399_PD_TCPD0 { reg = ; clocks = <&cru SCLK_UPHY0_TCPDCORE>, <&cru SCLK_UPHY0_TCPDPHY_REF>; + #power-domain-cells = <0>; }; - pd_tcpc1@RK3399_PD_TCPD1 { + power-domain@RK3399_PD_TCPD1 { reg = ; clocks = <&cru SCLK_UPHY1_TCPDCORE>, <&cru SCLK_UPHY1_TCPDPHY_REF>; + #power-domain-cells = <0>; }; - pd_usb3@RK3399_PD_USB3 { + power-domain@RK3399_PD_USB3 { reg = ; clocks = <&cru ACLK_USB3>; pm_qos = <&qos_usb_otg0>, <&qos_usb_otg1>; + #power-domain-cells = <0>; }; - pd_vio@RK3399_PD_VIO { + power-domain@RK3399_PD_VIO { reg = ; + #power-domain-cells = <1>; #address-cells = <1>; #size-cells = <0>; - pd_hdcp@RK3399_PD_HDCP { + power-domain@RK3399_PD_HDCP { reg = ; clocks = <&cru ACLK_HDCP>, <&cru HCLK_HDCP>, <&cru PCLK_HDCP>; pm_qos = <&qos_hdcp>; + #power-domain-cells = <0>; }; - pd_isp0@RK3399_PD_ISP0 { + power-domain@RK3399_PD_ISP0 { reg = ; clocks = <&cru ACLK_ISP0>, <&cru HCLK_ISP0>; pm_qos = <&qos_isp0_m0>, <&qos_isp0_m1>; + #power-domain-cells = <0>; }; - pd_isp1@RK3399_PD_ISP1 { + power-domain@RK3399_PD_ISP1 { reg = ; clocks = <&cru ACLK_ISP1>, <&cru HCLK_ISP1>; pm_qos = <&qos_isp1_m0>, <&qos_isp1_m1>; + #power-domain-cells = <0>; }; - pd_vo@RK3399_PD_VO { + power-domain@RK3399_PD_VO { reg = ; + #power-domain-cells = <1>; #address-cells = <1>; #size-cells = <0>; - pd_vopb@RK3399_PD_VOPB { + power-domain@RK3399_PD_VOPB { reg = ; clocks = <&cru ACLK_VOP0>, <&cru HCLK_VOP0>; pm_qos = <&qos_vop_big_r>, <&qos_vop_big_w>; + #power-domain-cells = <0>; }; - pd_vopl@RK3399_PD_VOPL { + power-domain@RK3399_PD_VOPL { reg = ; clocks = <&cru ACLK_VOP1>, <&cru HCLK_VOP1>; pm_qos = <&qos_vop_little>; + #power-domain-cells = <0>; }; }; }; @@ -1398,7 +1418,7 @@ status = "disabled"; }; - u2phy0: usb2-phy@e450 { + u2phy0: usb2phy@e450 { compatible = "rockchip,rk3399-usb2phy"; reg = <0xe450 0x10>; clocks = <&cru SCLK_USB2PHY0_REF>; @@ -1425,7 +1445,7 @@ }; }; - u2phy1: usb2-phy@e460 { + u2phy1: usb2phy@e460 { compatible = "rockchip,rk3399-usb2phy"; reg = <0xe460 0x10>; clocks = <&cru SCLK_USB2PHY1_REF>; @@ -2354,7 +2374,7 @@ }; }; - sleep { + suspend { ap_pwroff: ap-pwroff { rockchip,pins = <1 RK_PA5 1 &pcfg_pull_none>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi index c0074b3ed4af..01d1a75c8b4d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi @@ -329,7 +329,6 @@ &pcie0 { ep-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; - max-link-speed = <2>; num-lanes = <4>; pinctrl-0 = <&pcie_clkreqnb_cpm>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts new file mode 100644 index 000000000000..69786557093d --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; +#include +#include +#include "rk3568.dtsi" + +/ { + model = "Rockchip RK3568 EVB1 DDR4 V10 Board"; + compatible = "rockchip,rk3568-evb1-v10", "rockchip,rk3568"; + + chosen: chosen { + stdout-path = "serial2:1500000n8"; + }; + + dc_12v: dc-12v { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc3v3_sys: vcc3v3-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_12v>; + }; + + vcc5v0_sys: vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_12v>; + }; + + vcc3v3_lcd0_n: vcc3v3-lcd0-n { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_lcd0_n"; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_lcd1_n: vcc3v3-lcd1-n { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_lcd1_n"; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&sdhci { + bus-width = <8>; + max-frequency = <200000000>; + non-removable; + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi new file mode 100644 index 000000000000..a588ca95ace2 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi @@ -0,0 +1,3111 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + */ + +#include +#include "rockchip-pinconf.dtsi" + +/* + * This file is auto generated by pin2dts tool, please keep these code + * by adding changes at end of this file. + */ +&pinctrl { + acodec { + /omit-if-no-ref/ + acodec_pins: acodec-pins { + rockchip,pins = + /* acodec_adc_sync */ + <1 RK_PB1 5 &pcfg_pull_none>, + /* acodec_adcclk */ + <1 RK_PA1 5 &pcfg_pull_none>, + /* acodec_adcdata */ + <1 RK_PA0 5 &pcfg_pull_none>, + /* acodec_dac_datal */ + <1 RK_PA7 5 &pcfg_pull_none>, + /* acodec_dac_datar */ + <1 RK_PB0 5 &pcfg_pull_none>, + /* acodec_dacclk */ + <1 RK_PA3 5 &pcfg_pull_none>, + /* acodec_dacsync */ + <1 RK_PA5 5 &pcfg_pull_none>; + }; + }; + + audiopwm { + /omit-if-no-ref/ + audiopwm_lout: audiopwm-lout { + rockchip,pins = + /* audiopwm_lout */ + <1 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + audiopwm_loutn: audiopwm-loutn { + rockchip,pins = + /* audiopwm_loutn */ + <1 RK_PA1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + audiopwm_loutp: audiopwm-loutp { + rockchip,pins = + /* audiopwm_loutp */ + <1 RK_PA0 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + audiopwm_rout: audiopwm-rout { + rockchip,pins = + /* audiopwm_rout */ + <1 RK_PA1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + audiopwm_routn: audiopwm-routn { + rockchip,pins = + /* audiopwm_routn */ + <1 RK_PA7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + audiopwm_routp: audiopwm-routp { + rockchip,pins = + /* audiopwm_routp */ + <1 RK_PA6 4 &pcfg_pull_none>; + }; + }; + + bt656 { + /omit-if-no-ref/ + bt656m0_pins: bt656m0-pins { + rockchip,pins = + /* bt656_clkm0 */ + <3 RK_PA0 2 &pcfg_pull_none>, + /* bt656_d0m0 */ + <2 RK_PD0 2 &pcfg_pull_none>, + /* bt656_d1m0 */ + <2 RK_PD1 2 &pcfg_pull_none>, + /* bt656_d2m0 */ + <2 RK_PD2 2 &pcfg_pull_none>, + /* bt656_d3m0 */ + <2 RK_PD3 2 &pcfg_pull_none>, + /* bt656_d4m0 */ + <2 RK_PD4 2 &pcfg_pull_none>, + /* bt656_d5m0 */ + <2 RK_PD5 2 &pcfg_pull_none>, + /* bt656_d6m0 */ + <2 RK_PD6 2 &pcfg_pull_none>, + /* bt656_d7m0 */ + <2 RK_PD7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + bt656m1_pins: bt656m1-pins { + rockchip,pins = + /* bt656_clkm1 */ + <4 RK_PB4 5 &pcfg_pull_none>, + /* bt656_d0m1 */ + <3 RK_PC6 5 &pcfg_pull_none>, + /* bt656_d1m1 */ + <3 RK_PC7 5 &pcfg_pull_none>, + /* bt656_d2m1 */ + <3 RK_PD0 5 &pcfg_pull_none>, + /* bt656_d3m1 */ + <3 RK_PD1 5 &pcfg_pull_none>, + /* bt656_d4m1 */ + <3 RK_PD2 5 &pcfg_pull_none>, + /* bt656_d5m1 */ + <3 RK_PD3 5 &pcfg_pull_none>, + /* bt656_d6m1 */ + <3 RK_PD4 5 &pcfg_pull_none>, + /* bt656_d7m1 */ + <3 RK_PD5 5 &pcfg_pull_none>; + }; + }; + + bt1120 { + /omit-if-no-ref/ + bt1120_pins: bt1120-pins { + rockchip,pins = + /* bt1120_clk */ + <3 RK_PA6 2 &pcfg_pull_none>, + /* bt1120_d0 */ + <3 RK_PA1 2 &pcfg_pull_none>, + /* bt1120_d1 */ + <3 RK_PA2 2 &pcfg_pull_none>, + /* bt1120_d2 */ + <3 RK_PA3 2 &pcfg_pull_none>, + /* bt1120_d3 */ + <3 RK_PA4 2 &pcfg_pull_none>, + /* bt1120_d4 */ + <3 RK_PA5 2 &pcfg_pull_none>, + /* bt1120_d5 */ + <3 RK_PA7 2 &pcfg_pull_none>, + /* bt1120_d6 */ + <3 RK_PB0 2 &pcfg_pull_none>, + /* bt1120_d7 */ + <3 RK_PB1 2 &pcfg_pull_none>, + /* bt1120_d8 */ + <3 RK_PB2 2 &pcfg_pull_none>, + /* bt1120_d9 */ + <3 RK_PB3 2 &pcfg_pull_none>, + /* bt1120_d10 */ + <3 RK_PB4 2 &pcfg_pull_none>, + /* bt1120_d11 */ + <3 RK_PB5 2 &pcfg_pull_none>, + /* bt1120_d12 */ + <3 RK_PB6 2 &pcfg_pull_none>, + /* bt1120_d13 */ + <3 RK_PC1 2 &pcfg_pull_none>, + /* bt1120_d14 */ + <3 RK_PC2 2 &pcfg_pull_none>, + /* bt1120_d15 */ + <3 RK_PC3 2 &pcfg_pull_none>; + }; + }; + + cam { + /omit-if-no-ref/ + cam_clkout0: cam-clkout0 { + rockchip,pins = + /* cam_clkout0 */ + <4 RK_PA7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cam_clkout1: cam-clkout1 { + rockchip,pins = + /* cam_clkout1 */ + <4 RK_PB0 1 &pcfg_pull_none>; + }; + }; + + can0 { + /omit-if-no-ref/ + can0m0_pins: can0m0-pins { + rockchip,pins = + /* can0_rxm0 */ + <0 RK_PB4 2 &pcfg_pull_none>, + /* can0_txm0 */ + <0 RK_PB3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can0m1_pins: can0m1-pins { + rockchip,pins = + /* can0_rxm1 */ + <2 RK_PA2 4 &pcfg_pull_none>, + /* can0_txm1 */ + <2 RK_PA1 4 &pcfg_pull_none>; + }; + }; + + can1 { + /omit-if-no-ref/ + can1m0_pins: can1m0-pins { + rockchip,pins = + /* can1_rxm0 */ + <1 RK_PA0 3 &pcfg_pull_none>, + /* can1_txm0 */ + <1 RK_PA1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can1m1_pins: can1m1-pins { + rockchip,pins = + /* can1_rxm1 */ + <4 RK_PC2 3 &pcfg_pull_none>, + /* can1_txm1 */ + <4 RK_PC3 3 &pcfg_pull_none>; + }; + }; + + can2 { + /omit-if-no-ref/ + can2m0_pins: can2m0-pins { + rockchip,pins = + /* can2_rxm0 */ + <4 RK_PB4 3 &pcfg_pull_none>, + /* can2_txm0 */ + <4 RK_PB5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can2m1_pins: can2m1-pins { + rockchip,pins = + /* can2_rxm1 */ + <2 RK_PB1 4 &pcfg_pull_none>, + /* can2_txm1 */ + <2 RK_PB2 4 &pcfg_pull_none>; + }; + }; + + cif { + /omit-if-no-ref/ + cif_clk: cif-clk { + rockchip,pins = + /* cif_clkout */ + <4 RK_PC0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cif_dvp_clk: cif-dvp-clk { + rockchip,pins = + /* cif_clkin */ + <4 RK_PC1 1 &pcfg_pull_none>, + /* cif_href */ + <4 RK_PB6 1 &pcfg_pull_none>, + /* cif_vsync */ + <4 RK_PB7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cif_dvp_bus16: cif-dvp-bus16 { + rockchip,pins = + /* cif_d8 */ + <3 RK_PD6 1 &pcfg_pull_none>, + /* cif_d9 */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* cif_d10 */ + <4 RK_PA0 1 &pcfg_pull_none>, + /* cif_d11 */ + <4 RK_PA1 1 &pcfg_pull_none>, + /* cif_d12 */ + <4 RK_PA2 1 &pcfg_pull_none>, + /* cif_d13 */ + <4 RK_PA3 1 &pcfg_pull_none>, + /* cif_d14 */ + <4 RK_PA4 1 &pcfg_pull_none>, + /* cif_d15 */ + <4 RK_PA5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cif_dvp_bus8: cif-dvp-bus8 { + rockchip,pins = + /* cif_d0 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* cif_d1 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* cif_d2 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* cif_d3 */ + <3 RK_PD1 1 &pcfg_pull_none>, + /* cif_d4 */ + <3 RK_PD2 1 &pcfg_pull_none>, + /* cif_d5 */ + <3 RK_PD3 1 &pcfg_pull_none>, + /* cif_d6 */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* cif_d7 */ + <3 RK_PD5 1 &pcfg_pull_none>; + }; + }; + + clk32k { + /omit-if-no-ref/ + clk32k_in: clk32k-in { + rockchip,pins = + /* clk32k_in */ + <0 RK_PB0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + clk32k_out0: clk32k-out0 { + rockchip,pins = + /* clk32k_out0 */ + <0 RK_PB0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + clk32k_out1: clk32k-out1 { + rockchip,pins = + /* clk32k_out1 */ + <2 RK_PC6 1 &pcfg_pull_none>; + }; + }; + + cpu { + /omit-if-no-ref/ + cpu_pins: cpu-pins { + rockchip,pins = + /* cpu_avs */ + <0 RK_PB7 2 &pcfg_pull_none>; + }; + }; + + ebc { + /omit-if-no-ref/ + ebc_extern: ebc-extern { + rockchip,pins = + /* ebc_sdce1 */ + <4 RK_PA7 2 &pcfg_pull_none>, + /* ebc_sdce2 */ + <4 RK_PB0 2 &pcfg_pull_none>, + /* ebc_sdce3 */ + <4 RK_PB1 2 &pcfg_pull_none>, + /* ebc_sdshr */ + <4 RK_PB5 2 &pcfg_pull_none>, + /* ebc_vcom */ + <4 RK_PB2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + ebc_pins: ebc-pins { + rockchip,pins = + /* ebc_gdclk */ + <4 RK_PC0 2 &pcfg_pull_none>, + /* ebc_gdoe */ + <4 RK_PB3 2 &pcfg_pull_none>, + /* ebc_gdsp */ + <4 RK_PB4 2 &pcfg_pull_none>, + /* ebc_sdce0 */ + <4 RK_PA6 2 &pcfg_pull_none>, + /* ebc_sdclk */ + <4 RK_PC1 2 &pcfg_pull_none>, + /* ebc_sddo0 */ + <3 RK_PC6 2 &pcfg_pull_none>, + /* ebc_sddo1 */ + <3 RK_PC7 2 &pcfg_pull_none>, + /* ebc_sddo2 */ + <3 RK_PD0 2 &pcfg_pull_none>, + /* ebc_sddo3 */ + <3 RK_PD1 2 &pcfg_pull_none>, + /* ebc_sddo4 */ + <3 RK_PD2 2 &pcfg_pull_none>, + /* ebc_sddo5 */ + <3 RK_PD3 2 &pcfg_pull_none>, + /* ebc_sddo6 */ + <3 RK_PD4 2 &pcfg_pull_none>, + /* ebc_sddo7 */ + <3 RK_PD5 2 &pcfg_pull_none>, + /* ebc_sddo8 */ + <3 RK_PD6 2 &pcfg_pull_none>, + /* ebc_sddo9 */ + <3 RK_PD7 2 &pcfg_pull_none>, + /* ebc_sddo10 */ + <4 RK_PA0 2 &pcfg_pull_none>, + /* ebc_sddo11 */ + <4 RK_PA1 2 &pcfg_pull_none>, + /* ebc_sddo12 */ + <4 RK_PA2 2 &pcfg_pull_none>, + /* ebc_sddo13 */ + <4 RK_PA3 2 &pcfg_pull_none>, + /* ebc_sddo14 */ + <4 RK_PA4 2 &pcfg_pull_none>, + /* ebc_sddo15 */ + <4 RK_PA5 2 &pcfg_pull_none>, + /* ebc_sdle */ + <4 RK_PB6 2 &pcfg_pull_none>, + /* ebc_sdoe */ + <4 RK_PB7 2 &pcfg_pull_none>; + }; + }; + + edpdp { + /omit-if-no-ref/ + edpdpm0_pins: edpdpm0-pins { + rockchip,pins = + /* edpdp_hpdinm0 */ + <4 RK_PC4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + edpdpm1_pins: edpdpm1-pins { + rockchip,pins = + /* edpdp_hpdinm1 */ + <0 RK_PC2 2 &pcfg_pull_none>; + }; + }; + + emmc { + /omit-if-no-ref/ + emmc_rstnout: emmc-rstnout { + rockchip,pins = + /* emmc_rstn */ + <1 RK_PC7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + emmc_bus8: emmc-bus8 { + rockchip,pins = + /* emmc_d0 */ + <1 RK_PB4 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d1 */ + <1 RK_PB5 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d2 */ + <1 RK_PB6 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d3 */ + <1 RK_PB7 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d4 */ + <1 RK_PC0 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d5 */ + <1 RK_PC1 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d6 */ + <1 RK_PC2 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d7 */ + <1 RK_PC3 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_clk: emmc-clk { + rockchip,pins = + /* emmc_clkout */ + <1 RK_PC5 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_cmd: emmc-cmd { + rockchip,pins = + /* emmc_cmd */ + <1 RK_PC4 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_datastrobe: emmc-datastrobe { + rockchip,pins = + /* emmc_datastrobe */ + <1 RK_PC6 1 &pcfg_pull_none>; + }; + }; + + eth0 { + /omit-if-no-ref/ + eth0_pins: eth0-pins { + rockchip,pins = + /* eth0_refclko25m */ + <2 RK_PC1 2 &pcfg_pull_none>; + }; + }; + + eth1 { + /omit-if-no-ref/ + eth1m0_pins: eth1m0-pins { + rockchip,pins = + /* eth1_refclko25mm0 */ + <3 RK_PB0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_pins: eth1m1-pins { + rockchip,pins = + /* eth1_refclko25mm1 */ + <4 RK_PB3 3 &pcfg_pull_none>; + }; + }; + + flash { + /omit-if-no-ref/ + flash_pins: flash-pins { + rockchip,pins = + /* flash_ale */ + <1 RK_PD0 2 &pcfg_pull_none>, + /* flash_cle */ + <1 RK_PC6 3 &pcfg_pull_none>, + /* flash_cs0n */ + <1 RK_PD3 2 &pcfg_pull_none>, + /* flash_cs1n */ + <1 RK_PD4 2 &pcfg_pull_none>, + /* flash_d0 */ + <1 RK_PB4 2 &pcfg_pull_none>, + /* flash_d1 */ + <1 RK_PB5 2 &pcfg_pull_none>, + /* flash_d2 */ + <1 RK_PB6 2 &pcfg_pull_none>, + /* flash_d3 */ + <1 RK_PB7 2 &pcfg_pull_none>, + /* flash_d4 */ + <1 RK_PC0 2 &pcfg_pull_none>, + /* flash_d5 */ + <1 RK_PC1 2 &pcfg_pull_none>, + /* flash_d6 */ + <1 RK_PC2 2 &pcfg_pull_none>, + /* flash_d7 */ + <1 RK_PC3 2 &pcfg_pull_none>, + /* flash_dqs */ + <1 RK_PC5 2 &pcfg_pull_none>, + /* flash_rdn */ + <1 RK_PD2 2 &pcfg_pull_none>, + /* flash_rdy */ + <1 RK_PD1 2 &pcfg_pull_none>, + /* flash_volsel */ + <0 RK_PA7 1 &pcfg_pull_none>, + /* flash_wpn */ + <1 RK_PC7 3 &pcfg_pull_none>, + /* flash_wrn */ + <1 RK_PC4 2 &pcfg_pull_none>; + }; + }; + + fspi { + /omit-if-no-ref/ + fspi_pins: fspi-pins { + rockchip,pins = + /* fspi_clk */ + <1 RK_PD0 1 &pcfg_pull_none>, + /* fspi_cs0n */ + <1 RK_PD3 1 &pcfg_pull_none>, + /* fspi_d0 */ + <1 RK_PD1 1 &pcfg_pull_none>, + /* fspi_d1 */ + <1 RK_PD2 1 &pcfg_pull_none>, + /* fspi_d2 */ + <1 RK_PC7 2 &pcfg_pull_none>, + /* fspi_d3 */ + <1 RK_PD4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + fspi_cs1: fspi-cs1 { + rockchip,pins = + /* fspi_cs1n */ + <1 RK_PC6 2 &pcfg_pull_up>; + }; + }; + + gmac0 { + /omit-if-no-ref/ + gmac0_miim: gmac0-miim { + rockchip,pins = + /* gmac0_mdc */ + <2 RK_PC3 2 &pcfg_pull_none>, + /* gmac0_mdio */ + <2 RK_PC4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_clkinout: gmac0-clkinout { + rockchip,pins = + /* gmac0_mclkinout */ + <2 RK_PC2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_rx_er: gmac0-rx-er { + rockchip,pins = + /* gmac0_rxer */ + <2 RK_PC5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_rx_bus2: gmac0-rx-bus2 { + rockchip,pins = + /* gmac0_rxd0 */ + <2 RK_PB6 1 &pcfg_pull_none>, + /* gmac0_rxd1 */ + <2 RK_PB7 2 &pcfg_pull_none>, + /* gmac0_rxdvcrs */ + <2 RK_PC0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_tx_bus2: gmac0-tx-bus2 { + rockchip,pins = + /* gmac0_txd0 */ + <2 RK_PB3 1 &pcfg_pull_none_drv_level_2>, + /* gmac0_txd1 */ + <2 RK_PB4 1 &pcfg_pull_none_drv_level_2>, + /* gmac0_txen */ + <2 RK_PB5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_rgmii_clk: gmac0-rgmii-clk { + rockchip,pins = + /* gmac0_rxclk */ + <2 RK_PA5 2 &pcfg_pull_none>, + /* gmac0_txclk */ + <2 RK_PB0 2 &pcfg_pull_none_drv_level_1>; + }; + + /omit-if-no-ref/ + gmac0_rgmii_bus: gmac0-rgmii-bus { + rockchip,pins = + /* gmac0_rxd2 */ + <2 RK_PA3 2 &pcfg_pull_none>, + /* gmac0_rxd3 */ + <2 RK_PA4 2 &pcfg_pull_none>, + /* gmac0_txd2 */ + <2 RK_PA6 2 &pcfg_pull_none_drv_level_2>, + /* gmac0_txd3 */ + <2 RK_PA7 2 &pcfg_pull_none_drv_level_2>; + }; + }; + + gmac1 { + /omit-if-no-ref/ + gmac1m0_miim: gmac1m0-miim { + rockchip,pins = + /* gmac1_mdcm0 */ + <3 RK_PC4 3 &pcfg_pull_none>, + /* gmac1_mdiom0 */ + <3 RK_PC5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_clkinout: gmac1m0-clkinout { + rockchip,pins = + /* gmac1_mclkinoutm0 */ + <3 RK_PC0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_rx_er: gmac1m0-rx-er { + rockchip,pins = + /* gmac1_rxerm0 */ + <3 RK_PB4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_rx_bus2: gmac1m0-rx-bus2 { + rockchip,pins = + /* gmac1_rxd0m0 */ + <3 RK_PB1 3 &pcfg_pull_none>, + /* gmac1_rxd1m0 */ + <3 RK_PB2 3 &pcfg_pull_none>, + /* gmac1_rxdvcrsm0 */ + <3 RK_PB3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_tx_bus2: gmac1m0-tx-bus2 { + rockchip,pins = + /* gmac1_txd0m0 */ + <3 RK_PB5 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txd1m0 */ + <3 RK_PB6 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txenm0 */ + <3 RK_PB7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_rgmii_clk: gmac1m0-rgmii-clk { + rockchip,pins = + /* gmac1_rxclkm0 */ + <3 RK_PA7 3 &pcfg_pull_none>, + /* gmac1_txclkm0 */ + <3 RK_PA6 3 &pcfg_pull_none_drv_level_1>; + }; + + /omit-if-no-ref/ + gmac1m0_rgmii_bus: gmac1m0-rgmii-bus { + rockchip,pins = + /* gmac1_rxd2m0 */ + <3 RK_PA4 3 &pcfg_pull_none>, + /* gmac1_rxd3m0 */ + <3 RK_PA5 3 &pcfg_pull_none>, + /* gmac1_txd2m0 */ + <3 RK_PA2 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txd3m0 */ + <3 RK_PA3 3 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + gmac1m1_miim: gmac1m1-miim { + rockchip,pins = + /* gmac1_mdcm1 */ + <4 RK_PB6 3 &pcfg_pull_none>, + /* gmac1_mdiom1 */ + <4 RK_PB7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_clkinout: gmac1m1-clkinout { + rockchip,pins = + /* gmac1_mclkinoutm1 */ + <4 RK_PC1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_rx_er: gmac1m1-rx-er { + rockchip,pins = + /* gmac1_rxerm1 */ + <4 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_rx_bus2: gmac1m1-rx-bus2 { + rockchip,pins = + /* gmac1_rxd0m1 */ + <4 RK_PA7 3 &pcfg_pull_none>, + /* gmac1_rxd1m1 */ + <4 RK_PB0 3 &pcfg_pull_none>, + /* gmac1_rxdvcrsm1 */ + <4 RK_PB1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_tx_bus2: gmac1m1-tx-bus2 { + rockchip,pins = + /* gmac1_txd0m1 */ + <4 RK_PA4 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txd1m1 */ + <4 RK_PA5 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txenm1 */ + <4 RK_PA6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_rgmii_clk: gmac1m1-rgmii-clk { + rockchip,pins = + /* gmac1_rxclkm1 */ + <4 RK_PA3 3 &pcfg_pull_none>, + /* gmac1_txclkm1 */ + <4 RK_PA0 3 &pcfg_pull_none_drv_level_1>; + }; + + /omit-if-no-ref/ + gmac1m1_rgmii_bus: gmac1m1-rgmii-bus { + rockchip,pins = + /* gmac1_rxd2m1 */ + <4 RK_PA1 3 &pcfg_pull_none>, + /* gmac1_rxd3m1 */ + <4 RK_PA2 3 &pcfg_pull_none>, + /* gmac1_txd2m1 */ + <3 RK_PD6 3 &pcfg_pull_none_drv_level_2>, + /* gmac1_txd3m1 */ + <3 RK_PD7 3 &pcfg_pull_none_drv_level_2>; + }; + }; + + gpu { + /omit-if-no-ref/ + gpu_pins: gpu-pins { + rockchip,pins = + /* gpu_avs */ + <0 RK_PC0 2 &pcfg_pull_none>, + /* gpu_pwren */ + <0 RK_PA6 4 &pcfg_pull_none>; + }; + }; + + hdmitx { + /omit-if-no-ref/ + hdmitxm0_cec: hdmitxm0-cec { + rockchip,pins = + /* hdmitxm0_cec */ + <4 RK_PD1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + hdmitxm1_cec: hdmitxm1-cec { + rockchip,pins = + /* hdmitxm1_cec */ + <0 RK_PC7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + hdmitx_scl: hdmitx-scl { + rockchip,pins = + /* hdmitx_scl */ + <4 RK_PC7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + hdmitx_sda: hdmitx-sda { + rockchip,pins = + /* hdmitx_sda */ + <4 RK_PD0 1 &pcfg_pull_none>; + }; + }; + + i2c0 { + /omit-if-no-ref/ + i2c0_xfer: i2c0-xfer { + rockchip,pins = + /* i2c0_scl */ + <0 RK_PB1 1 &pcfg_pull_none_smt>, + /* i2c0_sda */ + <0 RK_PB2 1 &pcfg_pull_none_smt>; + }; + }; + + i2c1 { + /omit-if-no-ref/ + i2c1_xfer: i2c1-xfer { + rockchip,pins = + /* i2c1_scl */ + <0 RK_PB3 1 &pcfg_pull_none_smt>, + /* i2c1_sda */ + <0 RK_PB4 1 &pcfg_pull_none_smt>; + }; + }; + + i2c2 { + /omit-if-no-ref/ + i2c2m0_xfer: i2c2m0-xfer { + rockchip,pins = + /* i2c2_sclm0 */ + <0 RK_PB5 1 &pcfg_pull_none_smt>, + /* i2c2_sdam0 */ + <0 RK_PB6 1 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c2m1_xfer: i2c2m1-xfer { + rockchip,pins = + /* i2c2_sclm1 */ + <4 RK_PB5 1 &pcfg_pull_none_smt>, + /* i2c2_sdam1 */ + <4 RK_PB4 1 &pcfg_pull_none_smt>; + }; + }; + + i2c3 { + /omit-if-no-ref/ + i2c3m0_xfer: i2c3m0-xfer { + rockchip,pins = + /* i2c3_sclm0 */ + <1 RK_PA1 1 &pcfg_pull_none_smt>, + /* i2c3_sdam0 */ + <1 RK_PA0 1 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c3m1_xfer: i2c3m1-xfer { + rockchip,pins = + /* i2c3_sclm1 */ + <3 RK_PB5 4 &pcfg_pull_none_smt>, + /* i2c3_sdam1 */ + <3 RK_PB6 4 &pcfg_pull_none_smt>; + }; + }; + + i2c4 { + /omit-if-no-ref/ + i2c4m0_xfer: i2c4m0-xfer { + rockchip,pins = + /* i2c4_sclm0 */ + <4 RK_PB3 1 &pcfg_pull_none_smt>, + /* i2c4_sdam0 */ + <4 RK_PB2 1 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c4m1_xfer: i2c4m1-xfer { + rockchip,pins = + /* i2c4_sclm1 */ + <2 RK_PB2 2 &pcfg_pull_none_smt>, + /* i2c4_sdam1 */ + <2 RK_PB1 2 &pcfg_pull_none_smt>; + }; + }; + + i2c5 { + /omit-if-no-ref/ + i2c5m0_xfer: i2c5m0-xfer { + rockchip,pins = + /* i2c5_sclm0 */ + <3 RK_PB3 4 &pcfg_pull_none_smt>, + /* i2c5_sdam0 */ + <3 RK_PB4 4 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c5m1_xfer: i2c5m1-xfer { + rockchip,pins = + /* i2c5_sclm1 */ + <4 RK_PC7 2 &pcfg_pull_none_smt>, + /* i2c5_sdam1 */ + <4 RK_PD0 2 &pcfg_pull_none_smt>; + }; + }; + + i2s1 { + /omit-if-no-ref/ + i2s1m0_lrckrx: i2s1m0-lrckrx { + rockchip,pins = + /* i2s1m0_lrckrx */ + <1 RK_PA6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_lrcktx: i2s1m0-lrcktx { + rockchip,pins = + /* i2s1m0_lrcktx */ + <1 RK_PA5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_mclk: i2s1m0-mclk { + rockchip,pins = + /* i2s1m0_mclk */ + <1 RK_PA2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sclkrx: i2s1m0-sclkrx { + rockchip,pins = + /* i2s1m0_sclkrx */ + <1 RK_PA4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sclktx: i2s1m0-sclktx { + rockchip,pins = + /* i2s1m0_sclktx */ + <1 RK_PA3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdi0: i2s1m0-sdi0 { + rockchip,pins = + /* i2s1m0_sdi0 */ + <1 RK_PB3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdi1: i2s1m0-sdi1 { + rockchip,pins = + /* i2s1m0_sdi1 */ + <1 RK_PB2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdi2: i2s1m0-sdi2 { + rockchip,pins = + /* i2s1m0_sdi2 */ + <1 RK_PB1 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdi3: i2s1m0-sdi3 { + rockchip,pins = + /* i2s1m0_sdi3 */ + <1 RK_PB0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdo0: i2s1m0-sdo0 { + rockchip,pins = + /* i2s1m0_sdo0 */ + <1 RK_PA7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdo1: i2s1m0-sdo1 { + rockchip,pins = + /* i2s1m0_sdo1 */ + <1 RK_PB0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdo2: i2s1m0-sdo2 { + rockchip,pins = + /* i2s1m0_sdo2 */ + <1 RK_PB1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m0_sdo3: i2s1m0-sdo3 { + rockchip,pins = + /* i2s1m0_sdo3 */ + <1 RK_PB2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_lrckrx: i2s1m1-lrckrx { + rockchip,pins = + /* i2s1m1_lrckrx */ + <4 RK_PA7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_lrcktx: i2s1m1-lrcktx { + rockchip,pins = + /* i2s1m1_lrcktx */ + <3 RK_PD0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_mclk: i2s1m1-mclk { + rockchip,pins = + /* i2s1m1_mclk */ + <3 RK_PC6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sclkrx: i2s1m1-sclkrx { + rockchip,pins = + /* i2s1m1_sclkrx */ + <4 RK_PA6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sclktx: i2s1m1-sclktx { + rockchip,pins = + /* i2s1m1_sclktx */ + <3 RK_PC7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdi0: i2s1m1-sdi0 { + rockchip,pins = + /* i2s1m1_sdi0 */ + <3 RK_PD2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdi1: i2s1m1-sdi1 { + rockchip,pins = + /* i2s1m1_sdi1 */ + <3 RK_PD3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdi2: i2s1m1-sdi2 { + rockchip,pins = + /* i2s1m1_sdi2 */ + <3 RK_PD4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdi3: i2s1m1-sdi3 { + rockchip,pins = + /* i2s1m1_sdi3 */ + <3 RK_PD5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdo0: i2s1m1-sdo0 { + rockchip,pins = + /* i2s1m1_sdo0 */ + <3 RK_PD1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdo1: i2s1m1-sdo1 { + rockchip,pins = + /* i2s1m1_sdo1 */ + <4 RK_PB0 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdo2: i2s1m1-sdo2 { + rockchip,pins = + /* i2s1m1_sdo2 */ + <4 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m1_sdo3: i2s1m1-sdo3 { + rockchip,pins = + /* i2s1m1_sdo3 */ + <4 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_lrckrx: i2s1m2-lrckrx { + rockchip,pins = + /* i2s1m2_lrckrx */ + <3 RK_PC5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_lrcktx: i2s1m2-lrcktx { + rockchip,pins = + /* i2s1m2_lrcktx */ + <2 RK_PD2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_mclk: i2s1m2-mclk { + rockchip,pins = + /* i2s1m2_mclk */ + <2 RK_PD0 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sclkrx: i2s1m2-sclkrx { + rockchip,pins = + /* i2s1m2_sclkrx */ + <3 RK_PC3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sclktx: i2s1m2-sclktx { + rockchip,pins = + /* i2s1m2_sclktx */ + <2 RK_PD1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdi0: i2s1m2-sdi0 { + rockchip,pins = + /* i2s1m2_sdi0 */ + <2 RK_PD3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdi1: i2s1m2-sdi1 { + rockchip,pins = + /* i2s1m2_sdi1 */ + <2 RK_PD4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdi2: i2s1m2-sdi2 { + rockchip,pins = + /* i2s1m2_sdi2 */ + <2 RK_PD5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdi3: i2s1m2-sdi3 { + rockchip,pins = + /* i2s1m2_sdi3 */ + <2 RK_PD6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdo0: i2s1m2-sdo0 { + rockchip,pins = + /* i2s1m2_sdo0 */ + <2 RK_PD7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdo1: i2s1m2-sdo1 { + rockchip,pins = + /* i2s1m2_sdo1 */ + <3 RK_PA0 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdo2: i2s1m2-sdo2 { + rockchip,pins = + /* i2s1m2_sdo2 */ + <3 RK_PC1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s1m2_sdo3: i2s1m2-sdo3 { + rockchip,pins = + /* i2s1m2_sdo3 */ + <3 RK_PC2 5 &pcfg_pull_none>; + }; + }; + + i2s2 { + /omit-if-no-ref/ + i2s2m0_lrckrx: i2s2m0-lrckrx { + rockchip,pins = + /* i2s2m0_lrckrx */ + <2 RK_PC0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_lrcktx: i2s2m0-lrcktx { + rockchip,pins = + /* i2s2m0_lrcktx */ + <2 RK_PC3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_mclk: i2s2m0-mclk { + rockchip,pins = + /* i2s2m0_mclk */ + <2 RK_PC1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_sclkrx: i2s2m0-sclkrx { + rockchip,pins = + /* i2s2m0_sclkrx */ + <2 RK_PB7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_sclktx: i2s2m0-sclktx { + rockchip,pins = + /* i2s2m0_sclktx */ + <2 RK_PC2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_sdi: i2s2m0-sdi { + rockchip,pins = + /* i2s2m0_sdi */ + <2 RK_PC5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m0_sdo: i2s2m0-sdo { + rockchip,pins = + /* i2s2m0_sdo */ + <2 RK_PC4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_lrckrx: i2s2m1-lrckrx { + rockchip,pins = + /* i2s2m1_lrckrx */ + <4 RK_PA5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_lrcktx: i2s2m1-lrcktx { + rockchip,pins = + /* i2s2m1_lrcktx */ + <4 RK_PA4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_mclk: i2s2m1-mclk { + rockchip,pins = + /* i2s2m1_mclk */ + <4 RK_PB6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_sclkrx: i2s2m1-sclkrx { + rockchip,pins = + /* i2s2m1_sclkrx */ + <4 RK_PC1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_sclktx: i2s2m1-sclktx { + rockchip,pins = + /* i2s2m1_sclktx */ + <4 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_sdi: i2s2m1-sdi { + rockchip,pins = + /* i2s2m1_sdi */ + <4 RK_PB2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s2m1_sdo: i2s2m1-sdo { + rockchip,pins = + /* i2s2m1_sdo */ + <4 RK_PB3 5 &pcfg_pull_none>; + }; + }; + + i2s3 { + /omit-if-no-ref/ + i2s3m0_lrck: i2s3m0-lrck { + rockchip,pins = + /* i2s3m0_lrck */ + <3 RK_PA4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m0_mclk: i2s3m0-mclk { + rockchip,pins = + /* i2s3m0_mclk */ + <3 RK_PA2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m0_sclk: i2s3m0-sclk { + rockchip,pins = + /* i2s3m0_sclk */ + <3 RK_PA3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m0_sdi: i2s3m0-sdi { + rockchip,pins = + /* i2s3m0_sdi */ + <3 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m0_sdo: i2s3m0-sdo { + rockchip,pins = + /* i2s3m0_sdo */ + <3 RK_PA5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m1_lrck: i2s3m1-lrck { + rockchip,pins = + /* i2s3m1_lrck */ + <4 RK_PC4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m1_mclk: i2s3m1-mclk { + rockchip,pins = + /* i2s3m1_mclk */ + <4 RK_PC2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m1_sclk: i2s3m1-sclk { + rockchip,pins = + /* i2s3m1_sclk */ + <4 RK_PC3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m1_sdi: i2s3m1-sdi { + rockchip,pins = + /* i2s3m1_sdi */ + <4 RK_PC6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i2s3m1_sdo: i2s3m1-sdo { + rockchip,pins = + /* i2s3m1_sdo */ + <4 RK_PC5 5 &pcfg_pull_none>; + }; + }; + + isp { + /omit-if-no-ref/ + isp_pins: isp-pins { + rockchip,pins = + /* isp_flashtrigin */ + <4 RK_PB4 4 &pcfg_pull_none>, + /* isp_flashtrigout */ + <4 RK_PA6 1 &pcfg_pull_none>, + /* isp_prelighttrig */ + <4 RK_PB1 1 &pcfg_pull_none>; + }; + }; + + jtag { + /omit-if-no-ref/ + jtag_pins: jtag-pins { + rockchip,pins = + /* jtag_tck */ + <1 RK_PD7 2 &pcfg_pull_none>, + /* jtag_tms */ + <2 RK_PA0 2 &pcfg_pull_none>; + }; + }; + + lcdc { + /omit-if-no-ref/ + lcdc_ctl: lcdc-ctl { + rockchip,pins = + /* lcdc_clk */ + <3 RK_PA0 1 &pcfg_pull_none>, + /* lcdc_d0 */ + <2 RK_PD0 1 &pcfg_pull_none>, + /* lcdc_d1 */ + <2 RK_PD1 1 &pcfg_pull_none>, + /* lcdc_d2 */ + <2 RK_PD2 1 &pcfg_pull_none>, + /* lcdc_d3 */ + <2 RK_PD3 1 &pcfg_pull_none>, + /* lcdc_d4 */ + <2 RK_PD4 1 &pcfg_pull_none>, + /* lcdc_d5 */ + <2 RK_PD5 1 &pcfg_pull_none>, + /* lcdc_d6 */ + <2 RK_PD6 1 &pcfg_pull_none>, + /* lcdc_d7 */ + <2 RK_PD7 1 &pcfg_pull_none>, + /* lcdc_d8 */ + <3 RK_PA1 1 &pcfg_pull_none>, + /* lcdc_d9 */ + <3 RK_PA2 1 &pcfg_pull_none>, + /* lcdc_d10 */ + <3 RK_PA3 1 &pcfg_pull_none>, + /* lcdc_d11 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* lcdc_d12 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* lcdc_d13 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* lcdc_d14 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* lcdc_d15 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* lcdc_d16 */ + <3 RK_PB1 1 &pcfg_pull_none>, + /* lcdc_d17 */ + <3 RK_PB2 1 &pcfg_pull_none>, + /* lcdc_d18 */ + <3 RK_PB3 1 &pcfg_pull_none>, + /* lcdc_d19 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* lcdc_d20 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* lcdc_d21 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* lcdc_d22 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* lcdc_d23 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* lcdc_den */ + <3 RK_PC3 1 &pcfg_pull_none>, + /* lcdc_hsync */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* lcdc_vsync */ + <3 RK_PC2 1 &pcfg_pull_none>; + }; + }; + + mcu { + /omit-if-no-ref/ + mcu_pins: mcu-pins { + rockchip,pins = + /* mcu_jtagtck */ + <0 RK_PB4 4 &pcfg_pull_none>, + /* mcu_jtagtdi */ + <0 RK_PC1 4 &pcfg_pull_none>, + /* mcu_jtagtdo */ + <0 RK_PB3 4 &pcfg_pull_none>, + /* mcu_jtagtms */ + <0 RK_PC2 4 &pcfg_pull_none>, + /* mcu_jtagtrstn */ + <0 RK_PC3 4 &pcfg_pull_none>; + }; + }; + + npu { + /omit-if-no-ref/ + npu_pins: npu-pins { + rockchip,pins = + /* npu_avs */ + <0 RK_PC1 2 &pcfg_pull_none>; + }; + }; + + pcie20 { + /omit-if-no-ref/ + pcie20m0_pins: pcie20m0-pins { + rockchip,pins = + /* pcie20_clkreqnm0 */ + <0 RK_PA5 3 &pcfg_pull_none>, + /* pcie20_perstnm0 */ + <0 RK_PB6 3 &pcfg_pull_none>, + /* pcie20_wakenm0 */ + <0 RK_PB5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20m1_pins: pcie20m1-pins { + rockchip,pins = + /* pcie20_clkreqnm1 */ + <2 RK_PD0 4 &pcfg_pull_none>, + /* pcie20_perstnm1 */ + <3 RK_PC1 4 &pcfg_pull_none>, + /* pcie20_wakenm1 */ + <2 RK_PD1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20m2_pins: pcie20m2-pins { + rockchip,pins = + /* pcie20_clkreqnm2 */ + <1 RK_PB0 4 &pcfg_pull_none>, + /* pcie20_perstnm2 */ + <1 RK_PB2 4 &pcfg_pull_none>, + /* pcie20_wakenm2 */ + <1 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20_buttonrstn: pcie20-buttonrstn { + rockchip,pins = + /* pcie20_buttonrstn */ + <0 RK_PB4 3 &pcfg_pull_none>; + }; + }; + + pcie30x1 { + /omit-if-no-ref/ + pcie30x1m0_pins: pcie30x1m0-pins { + rockchip,pins = + /* pcie30x1_clkreqnm0 */ + <0 RK_PA4 3 &pcfg_pull_none>, + /* pcie30x1_perstnm0 */ + <0 RK_PC3 3 &pcfg_pull_none>, + /* pcie30x1_wakenm0 */ + <0 RK_PC2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_pins: pcie30x1m1-pins { + rockchip,pins = + /* pcie30x1_clkreqnm1 */ + <2 RK_PD2 4 &pcfg_pull_none>, + /* pcie30x1_perstnm1 */ + <3 RK_PA1 4 &pcfg_pull_none>, + /* pcie30x1_wakenm1 */ + <2 RK_PD3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_pins: pcie30x1m2-pins { + rockchip,pins = + /* pcie30x1_clkreqnm2 */ + <1 RK_PA5 4 &pcfg_pull_none>, + /* pcie30x1_perstnm2 */ + <1 RK_PA2 4 &pcfg_pull_none>, + /* pcie30x1_wakenm2 */ + <1 RK_PA3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1_buttonrstn: pcie30x1-buttonrstn { + rockchip,pins = + /* pcie30x1_buttonrstn */ + <0 RK_PB3 3 &pcfg_pull_none>; + }; + }; + + pcie30x2 { + /omit-if-no-ref/ + pcie30x2m0_pins: pcie30x2m0-pins { + rockchip,pins = + /* pcie30x2_clkreqnm0 */ + <0 RK_PA6 2 &pcfg_pull_none>, + /* pcie30x2_perstnm0 */ + <0 RK_PC6 3 &pcfg_pull_none>, + /* pcie30x2_wakenm0 */ + <0 RK_PC5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m1_pins: pcie30x2m1-pins { + rockchip,pins = + /* pcie30x2_clkreqnm1 */ + <2 RK_PD4 4 &pcfg_pull_none>, + /* pcie30x2_perstnm1 */ + <2 RK_PD6 4 &pcfg_pull_none>, + /* pcie30x2_wakenm1 */ + <2 RK_PD5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m2_pins: pcie30x2m2-pins { + rockchip,pins = + /* pcie30x2_clkreqnm2 */ + <4 RK_PC2 4 &pcfg_pull_none>, + /* pcie30x2_perstnm2 */ + <4 RK_PC4 4 &pcfg_pull_none>, + /* pcie30x2_wakenm2 */ + <4 RK_PC3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2_buttonrstn: pcie30x2-buttonrstn { + rockchip,pins = + /* pcie30x2_buttonrstn */ + <0 RK_PB0 3 &pcfg_pull_none>; + }; + }; + + pdm { + /omit-if-no-ref/ + pdmm0_clk: pdmm0-clk { + rockchip,pins = + /* pdm_clk0m0 */ + <1 RK_PA6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm0_clk1: pdmm0-clk1 { + rockchip,pins = + /* pdmm0_clk1 */ + <1 RK_PA4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm0_sdi0: pdmm0-sdi0 { + rockchip,pins = + /* pdmm0_sdi0 */ + <1 RK_PB3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm0_sdi1: pdmm0-sdi1 { + rockchip,pins = + /* pdmm0_sdi1 */ + <1 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm0_sdi2: pdmm0-sdi2 { + rockchip,pins = + /* pdmm0_sdi2 */ + <1 RK_PB1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm0_sdi3: pdmm0-sdi3 { + rockchip,pins = + /* pdmm0_sdi3 */ + <1 RK_PB0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_clk: pdmm1-clk { + rockchip,pins = + /* pdm_clk0m1 */ + <3 RK_PD6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_clk1: pdmm1-clk1 { + rockchip,pins = + /* pdmm1_clk1 */ + <4 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_sdi0: pdmm1-sdi0 { + rockchip,pins = + /* pdmm1_sdi0 */ + <3 RK_PD7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_sdi1: pdmm1-sdi1 { + rockchip,pins = + /* pdmm1_sdi1 */ + <4 RK_PA1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_sdi2: pdmm1-sdi2 { + rockchip,pins = + /* pdmm1_sdi2 */ + <4 RK_PA2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm1_sdi3: pdmm1-sdi3 { + rockchip,pins = + /* pdmm1_sdi3 */ + <4 RK_PA3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm2_clk1: pdmm2-clk1 { + rockchip,pins = + /* pdmm2_clk1 */ + <3 RK_PC4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm2_sdi0: pdmm2-sdi0 { + rockchip,pins = + /* pdmm2_sdi0 */ + <3 RK_PB3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm2_sdi1: pdmm2-sdi1 { + rockchip,pins = + /* pdmm2_sdi1 */ + <3 RK_PB4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm2_sdi2: pdmm2-sdi2 { + rockchip,pins = + /* pdmm2_sdi2 */ + <3 RK_PB7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdmm2_sdi3: pdmm2-sdi3 { + rockchip,pins = + /* pdmm2_sdi3 */ + <3 RK_PC0 5 &pcfg_pull_none>; + }; + }; + + pmic { + /omit-if-no-ref/ + pmic_pins: pmic-pins { + rockchip,pins = + /* pmic_sleep */ + <0 RK_PA2 1 &pcfg_pull_none>; + }; + }; + + pmu { + /omit-if-no-ref/ + pmu_pins: pmu-pins { + rockchip,pins = + /* pmu_debug0 */ + <0 RK_PA5 4 &pcfg_pull_none>, + /* pmu_debug1 */ + <0 RK_PA6 3 &pcfg_pull_none>, + /* pmu_debug2 */ + <0 RK_PC4 4 &pcfg_pull_none>, + /* pmu_debug3 */ + <0 RK_PC5 4 &pcfg_pull_none>, + /* pmu_debug4 */ + <0 RK_PC6 4 &pcfg_pull_none>, + /* pmu_debug5 */ + <0 RK_PC7 4 &pcfg_pull_none>; + }; + }; + + pwm0 { + /omit-if-no-ref/ + pwm0m0_pins: pwm0m0-pins { + rockchip,pins = + /* pwm0_m0 */ + <0 RK_PB7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm0m1_pins: pwm0m1-pins { + rockchip,pins = + /* pwm0_m1 */ + <0 RK_PC7 2 &pcfg_pull_none>; + }; + }; + + pwm1 { + /omit-if-no-ref/ + pwm1m0_pins: pwm1m0-pins { + rockchip,pins = + /* pwm1_m0 */ + <0 RK_PC0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_pins: pwm1m1-pins { + rockchip,pins = + /* pwm1_m1 */ + <0 RK_PB5 4 &pcfg_pull_none>; + }; + }; + + pwm2 { + /omit-if-no-ref/ + pwm2m0_pins: pwm2m0-pins { + rockchip,pins = + /* pwm2_m0 */ + <0 RK_PC1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm2m1_pins: pwm2m1-pins { + rockchip,pins = + /* pwm2_m1 */ + <0 RK_PB6 4 &pcfg_pull_none>; + }; + }; + + pwm3 { + /omit-if-no-ref/ + pwm3_pins: pwm3-pins { + rockchip,pins = + /* pwm3_ir */ + <0 RK_PC2 1 &pcfg_pull_none>; + }; + }; + + pwm4 { + /omit-if-no-ref/ + pwm4_pins: pwm4-pins { + rockchip,pins = + /* pwm4 */ + <0 RK_PC3 1 &pcfg_pull_none>; + }; + }; + + pwm5 { + /omit-if-no-ref/ + pwm5_pins: pwm5-pins { + rockchip,pins = + /* pwm5 */ + <0 RK_PC4 1 &pcfg_pull_none>; + }; + }; + + pwm6 { + /omit-if-no-ref/ + pwm6_pins: pwm6-pins { + rockchip,pins = + /* pwm6 */ + <0 RK_PC5 1 &pcfg_pull_none>; + }; + }; + + pwm7 { + /omit-if-no-ref/ + pwm7_pins: pwm7-pins { + rockchip,pins = + /* pwm7_ir */ + <0 RK_PC6 1 &pcfg_pull_none>; + }; + }; + + pwm8 { + /omit-if-no-ref/ + pwm8m0_pins: pwm8m0-pins { + rockchip,pins = + /* pwm8_m0 */ + <3 RK_PB1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm8m1_pins: pwm8m1-pins { + rockchip,pins = + /* pwm8_m1 */ + <1 RK_PD5 4 &pcfg_pull_none>; + }; + }; + + pwm9 { + /omit-if-no-ref/ + pwm9m0_pins: pwm9m0-pins { + rockchip,pins = + /* pwm9_m0 */ + <3 RK_PB2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm9m1_pins: pwm9m1-pins { + rockchip,pins = + /* pwm9_m1 */ + <1 RK_PD6 4 &pcfg_pull_none>; + }; + }; + + pwm10 { + /omit-if-no-ref/ + pwm10m0_pins: pwm10m0-pins { + rockchip,pins = + /* pwm10_m0 */ + <3 RK_PB5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm10m1_pins: pwm10m1-pins { + rockchip,pins = + /* pwm10_m1 */ + <2 RK_PA1 2 &pcfg_pull_none>; + }; + }; + + pwm11 { + /omit-if-no-ref/ + pwm11m0_pins: pwm11m0-pins { + rockchip,pins = + /* pwm11_irm0 */ + <3 RK_PB6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm11m1_pins: pwm11m1-pins { + rockchip,pins = + /* pwm11_irm1 */ + <4 RK_PC0 3 &pcfg_pull_none>; + }; + }; + + pwm12 { + /omit-if-no-ref/ + pwm12m0_pins: pwm12m0-pins { + rockchip,pins = + /* pwm12_m0 */ + <3 RK_PB7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm12m1_pins: pwm12m1-pins { + rockchip,pins = + /* pwm12_m1 */ + <4 RK_PC5 1 &pcfg_pull_none>; + }; + }; + + pwm13 { + /omit-if-no-ref/ + pwm13m0_pins: pwm13m0-pins { + rockchip,pins = + /* pwm13_m0 */ + <3 RK_PC0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm13m1_pins: pwm13m1-pins { + rockchip,pins = + /* pwm13_m1 */ + <4 RK_PC6 1 &pcfg_pull_none>; + }; + }; + + pwm14 { + /omit-if-no-ref/ + pwm14m0_pins: pwm14m0-pins { + rockchip,pins = + /* pwm14_m0 */ + <3 RK_PC4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm14m1_pins: pwm14m1-pins { + rockchip,pins = + /* pwm14_m1 */ + <4 RK_PC2 1 &pcfg_pull_none>; + }; + }; + + pwm15 { + /omit-if-no-ref/ + pwm15m0_pins: pwm15m0-pins { + rockchip,pins = + /* pwm15_irm0 */ + <3 RK_PC5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm15m1_pins: pwm15m1-pins { + rockchip,pins = + /* pwm15_irm1 */ + <4 RK_PC3 1 &pcfg_pull_none>; + }; + }; + + refclk { + /omit-if-no-ref/ + refclk_pins: refclk-pins { + rockchip,pins = + /* refclk_ou */ + <0 RK_PA0 1 &pcfg_pull_none>; + }; + }; + + sata { + /omit-if-no-ref/ + sata_pins: sata-pins { + rockchip,pins = + /* sata_cpdet */ + <0 RK_PA4 2 &pcfg_pull_none>, + /* sata_cppod */ + <0 RK_PA6 1 &pcfg_pull_none>, + /* sata_mpswitch */ + <0 RK_PA5 2 &pcfg_pull_none>; + }; + }; + + sata0 { + /omit-if-no-ref/ + sata0_pins: sata0-pins { + rockchip,pins = + /* sata0_actled */ + <4 RK_PC6 3 &pcfg_pull_none>; + }; + }; + + sata1 { + /omit-if-no-ref/ + sata1_pins: sata1-pins { + rockchip,pins = + /* sata1_actled */ + <4 RK_PC5 3 &pcfg_pull_none>; + }; + }; + + sata2 { + /omit-if-no-ref/ + sata2_pins: sata2-pins { + rockchip,pins = + /* sata2_actled */ + <4 RK_PC4 3 &pcfg_pull_none>; + }; + }; + + scr { + /omit-if-no-ref/ + scr_pins: scr-pins { + rockchip,pins = + /* scr_clk */ + <1 RK_PA2 3 &pcfg_pull_none>, + /* scr_det */ + <1 RK_PA7 3 &pcfg_pull_up>, + /* scr_io */ + <1 RK_PA3 3 &pcfg_pull_up>, + /* scr_rst */ + <1 RK_PA5 3 &pcfg_pull_none>; + }; + }; + + sdmmc0 { + /omit-if-no-ref/ + sdmmc0_bus4: sdmmc0-bus4 { + rockchip,pins = + /* sdmmc0_d0 */ + <1 RK_PD5 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc0_d1 */ + <1 RK_PD6 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc0_d2 */ + <1 RK_PD7 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc0_d3 */ + <2 RK_PA0 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc0_clk: sdmmc0-clk { + rockchip,pins = + /* sdmmc0_clk */ + <2 RK_PA2 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc0_cmd: sdmmc0-cmd { + rockchip,pins = + /* sdmmc0_cmd */ + <2 RK_PA1 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc0_det: sdmmc0-det { + rockchip,pins = + /* sdmmc0_det */ + <0 RK_PA4 1 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc0_pwren: sdmmc0-pwren { + rockchip,pins = + /* sdmmc0_pwren */ + <0 RK_PA5 1 &pcfg_pull_none>; + }; + }; + + sdmmc1 { + /omit-if-no-ref/ + sdmmc1_bus4: sdmmc1-bus4 { + rockchip,pins = + /* sdmmc1_d0 */ + <2 RK_PA3 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d1 */ + <2 RK_PA4 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d2 */ + <2 RK_PA5 1 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d3 */ + <2 RK_PA6 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1_clk: sdmmc1-clk { + rockchip,pins = + /* sdmmc1_clk */ + <2 RK_PB0 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1_cmd: sdmmc1-cmd { + rockchip,pins = + /* sdmmc1_cmd */ + <2 RK_PA7 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1_det: sdmmc1-det { + rockchip,pins = + /* sdmmc1_det */ + <2 RK_PB2 1 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc1_pwren: sdmmc1-pwren { + rockchip,pins = + /* sdmmc1_pwren */ + <2 RK_PB1 1 &pcfg_pull_none>; + }; + }; + + sdmmc2 { + /omit-if-no-ref/ + sdmmc2m0_bus4: sdmmc2m0-bus4 { + rockchip,pins = + /* sdmmc2_d0m0 */ + <3 RK_PC6 3 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d1m0 */ + <3 RK_PC7 3 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d2m0 */ + <3 RK_PD0 3 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d3m0 */ + <3 RK_PD1 3 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m0_clk: sdmmc2m0-clk { + rockchip,pins = + /* sdmmc2_clkm0 */ + <3 RK_PD3 3 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m0_cmd: sdmmc2m0-cmd { + rockchip,pins = + /* sdmmc2_cmdm0 */ + <3 RK_PD2 3 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m0_det: sdmmc2m0-det { + rockchip,pins = + /* sdmmc2_detm0 */ + <3 RK_PD4 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc2m0_pwren: sdmmc2m0-pwren { + rockchip,pins = + /* sdmmc2m0_pwren */ + <3 RK_PD5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sdmmc2m1_bus4: sdmmc2m1-bus4 { + rockchip,pins = + /* sdmmc2_d0m1 */ + <3 RK_PA1 5 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d1m1 */ + <3 RK_PA2 5 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d2m1 */ + <3 RK_PA3 5 &pcfg_pull_up_drv_level_2>, + /* sdmmc2_d3m1 */ + <3 RK_PA4 5 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m1_clk: sdmmc2m1-clk { + rockchip,pins = + /* sdmmc2_clkm1 */ + <3 RK_PA6 5 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m1_cmd: sdmmc2m1-cmd { + rockchip,pins = + /* sdmmc2_cmdm1 */ + <3 RK_PA5 5 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc2m1_det: sdmmc2m1-det { + rockchip,pins = + /* sdmmc2_detm1 */ + <3 RK_PA7 4 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc2m1_pwren: sdmmc2m1-pwren { + rockchip,pins = + /* sdmmc2m1_pwren */ + <3 RK_PB0 4 &pcfg_pull_none>; + }; + }; + + spdif { + /omit-if-no-ref/ + spdifm0_tx: spdifm0-tx { + rockchip,pins = + /* spdifm0_tx */ + <1 RK_PA4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm1_tx: spdifm1-tx { + rockchip,pins = + /* spdifm1_tx */ + <3 RK_PC5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm2_tx: spdifm2-tx { + rockchip,pins = + /* spdifm2_tx */ + <4 RK_PC4 2 &pcfg_pull_none>; + }; + }; + + spi0 { + /omit-if-no-ref/ + spi0m0_pins: spi0m0-pins { + rockchip,pins = + /* spi0_clkm0 */ + <0 RK_PB5 2 &pcfg_pull_none>, + /* spi0_misom0 */ + <0 RK_PC5 2 &pcfg_pull_none>, + /* spi0_mosim0 */ + <0 RK_PB6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m0_cs0: spi0m0-cs0 { + rockchip,pins = + /* spi0_cs0m0 */ + <0 RK_PC6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m0_cs1: spi0m0-cs1 { + rockchip,pins = + /* spi0_cs1m0 */ + <0 RK_PC4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m1_pins: spi0m1-pins { + rockchip,pins = + /* spi0_clkm1 */ + <2 RK_PD3 3 &pcfg_pull_none>, + /* spi0_misom1 */ + <2 RK_PD0 3 &pcfg_pull_none>, + /* spi0_mosim1 */ + <2 RK_PD1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m1_cs0: spi0m1-cs0 { + rockchip,pins = + /* spi0_cs0m1 */ + <2 RK_PD2 3 &pcfg_pull_none>; + }; + }; + + spi1 { + /omit-if-no-ref/ + spi1m0_pins: spi1m0-pins { + rockchip,pins = + /* spi1_clkm0 */ + <2 RK_PB5 3 &pcfg_pull_none>, + /* spi1_misom0 */ + <2 RK_PB6 3 &pcfg_pull_none>, + /* spi1_mosim0 */ + <2 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m0_cs0: spi1m0-cs0 { + rockchip,pins = + /* spi1_cs0m0 */ + <2 RK_PC0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m0_cs1: spi1m0-cs1 { + rockchip,pins = + /* spi1_cs1m0 */ + <2 RK_PC6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m1_pins: spi1m1-pins { + rockchip,pins = + /* spi1_clkm1 */ + <3 RK_PC3 3 &pcfg_pull_none>, + /* spi1_misom1 */ + <3 RK_PC2 3 &pcfg_pull_none>, + /* spi1_mosim1 */ + <3 RK_PC1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m1_cs0: spi1m1-cs0 { + rockchip,pins = + /* spi1_cs0m1 */ + <3 RK_PA1 3 &pcfg_pull_none>; + }; + }; + + spi2 { + /omit-if-no-ref/ + spi2m0_pins: spi2m0-pins { + rockchip,pins = + /* spi2_clkm0 */ + <2 RK_PC1 4 &pcfg_pull_none>, + /* spi2_misom0 */ + <2 RK_PC2 4 &pcfg_pull_none>, + /* spi2_mosim0 */ + <2 RK_PC3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m0_cs0: spi2m0-cs0 { + rockchip,pins = + /* spi2_cs0m0 */ + <2 RK_PC4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m0_cs1: spi2m0-cs1 { + rockchip,pins = + /* spi2_cs1m0 */ + <2 RK_PC5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m1_pins: spi2m1-pins { + rockchip,pins = + /* spi2_clkm1 */ + <3 RK_PA0 3 &pcfg_pull_none>, + /* spi2_misom1 */ + <2 RK_PD7 3 &pcfg_pull_none>, + /* spi2_mosim1 */ + <2 RK_PD6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m1_cs0: spi2m1-cs0 { + rockchip,pins = + /* spi2_cs0m1 */ + <2 RK_PD5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m1_cs1: spi2m1-cs1 { + rockchip,pins = + /* spi2_cs1m1 */ + <2 RK_PD4 3 &pcfg_pull_none>; + }; + }; + + spi3 { + /omit-if-no-ref/ + spi3m0_pins: spi3m0-pins { + rockchip,pins = + /* spi3_clkm0 */ + <4 RK_PB3 4 &pcfg_pull_none>, + /* spi3_misom0 */ + <4 RK_PB0 4 &pcfg_pull_none>, + /* spi3_mosim0 */ + <4 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m0_cs0: spi3m0-cs0 { + rockchip,pins = + /* spi3_cs0m0 */ + <4 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m0_cs1: spi3m0-cs1 { + rockchip,pins = + /* spi3_cs1m0 */ + <4 RK_PA7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m1_pins: spi3m1-pins { + rockchip,pins = + /* spi3_clkm1 */ + <4 RK_PC2 2 &pcfg_pull_none>, + /* spi3_misom1 */ + <4 RK_PC5 2 &pcfg_pull_none>, + /* spi3_mosim1 */ + <4 RK_PC3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m1_cs0: spi3m1-cs0 { + rockchip,pins = + /* spi3_cs0m1 */ + <4 RK_PC6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m1_cs1: spi3m1-cs1 { + rockchip,pins = + /* spi3_cs1m1 */ + <4 RK_PD1 2 &pcfg_pull_none>; + }; + }; + + tsadc { + /omit-if-no-ref/ + tsadcm0_shut: tsadcm0-shut { + rockchip,pins = + /* tsadcm0_shut */ + <0 RK_PA1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + tsadcm1_shut: tsadcm1-shut { + rockchip,pins = + /* tsadcm1_shut */ + <0 RK_PA2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + tsadc_shutorg: tsadc-shutorg { + rockchip,pins = + /* tsadc_shutorg */ + <0 RK_PA1 2 &pcfg_pull_none>; + }; + }; + + uart0 { + /omit-if-no-ref/ + uart0_xfer: uart0-xfer { + rockchip,pins = + /* uart0_rx */ + <0 RK_PC0 3 &pcfg_pull_up>, + /* uart0_tx */ + <0 RK_PC1 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart0_ctsn: uart0-ctsn { + rockchip,pins = + /* uart0_ctsn */ + <0 RK_PC7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart0_rtsn: uart0-rtsn { + rockchip,pins = + /* uart0_rtsn */ + <0 RK_PC4 3 &pcfg_pull_none>; + }; + }; + + uart1 { + /omit-if-no-ref/ + uart1m0_xfer: uart1m0-xfer { + rockchip,pins = + /* uart1_rxm0 */ + <2 RK_PB3 2 &pcfg_pull_up>, + /* uart1_txm0 */ + <2 RK_PB4 2 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart1m0_ctsn: uart1m0-ctsn { + rockchip,pins = + /* uart1m0_ctsn */ + <2 RK_PB6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart1m0_rtsn: uart1m0-rtsn { + rockchip,pins = + /* uart1m0_rtsn */ + <2 RK_PB5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart1m1_xfer: uart1m1-xfer { + rockchip,pins = + /* uart1_rxm1 */ + <3 RK_PD7 4 &pcfg_pull_up>, + /* uart1_txm1 */ + <3 RK_PD6 4 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart1m1_ctsn: uart1m1-ctsn { + rockchip,pins = + /* uart1m1_ctsn */ + <4 RK_PC1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart1m1_rtsn: uart1m1-rtsn { + rockchip,pins = + /* uart1m1_rtsn */ + <4 RK_PB6 4 &pcfg_pull_none>; + }; + }; + + uart2 { + /omit-if-no-ref/ + uart2m0_xfer: uart2m0-xfer { + rockchip,pins = + /* uart2_rxm0 */ + <0 RK_PD0 1 &pcfg_pull_up>, + /* uart2_txm0 */ + <0 RK_PD1 1 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart2m1_xfer: uart2m1-xfer { + rockchip,pins = + /* uart2_rxm1 */ + <1 RK_PD6 2 &pcfg_pull_up>, + /* uart2_txm1 */ + <1 RK_PD5 2 &pcfg_pull_up>; + }; + }; + + uart3 { + /omit-if-no-ref/ + uart3m0_xfer: uart3m0-xfer { + rockchip,pins = + /* uart3_rxm0 */ + <1 RK_PA0 2 &pcfg_pull_up>, + /* uart3_txm0 */ + <1 RK_PA1 2 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart3m0_ctsn: uart3m0-ctsn { + rockchip,pins = + /* uart3m0_ctsn */ + <1 RK_PA3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart3m0_rtsn: uart3m0-rtsn { + rockchip,pins = + /* uart3m0_rtsn */ + <1 RK_PA2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart3m1_xfer: uart3m1-xfer { + rockchip,pins = + /* uart3_rxm1 */ + <3 RK_PC0 4 &pcfg_pull_up>, + /* uart3_txm1 */ + <3 RK_PB7 4 &pcfg_pull_up>; + }; + }; + + uart4 { + /omit-if-no-ref/ + uart4m0_xfer: uart4m0-xfer { + rockchip,pins = + /* uart4_rxm0 */ + <1 RK_PA4 2 &pcfg_pull_up>, + /* uart4_txm0 */ + <1 RK_PA6 2 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart4m0_ctsn: uart4m0-ctsn { + rockchip,pins = + /* uart4m0_ctsn */ + <1 RK_PA7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart4m0_rtsn: uart4m0-rtsn { + rockchip,pins = + /* uart4m0_rtsn */ + <1 RK_PA5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart4m1_xfer: uart4m1-xfer { + rockchip,pins = + /* uart4_rxm1 */ + <3 RK_PB1 4 &pcfg_pull_up>, + /* uart4_txm1 */ + <3 RK_PB2 4 &pcfg_pull_up>; + }; + }; + + uart5 { + /omit-if-no-ref/ + uart5m0_xfer: uart5m0-xfer { + rockchip,pins = + /* uart5_rxm0 */ + <2 RK_PA1 3 &pcfg_pull_up>, + /* uart5_txm0 */ + <2 RK_PA2 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart5m0_ctsn: uart5m0-ctsn { + rockchip,pins = + /* uart5m0_ctsn */ + <1 RK_PD7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart5m0_rtsn: uart5m0-rtsn { + rockchip,pins = + /* uart5m0_rtsn */ + <2 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart5m1_xfer: uart5m1-xfer { + rockchip,pins = + /* uart5_rxm1 */ + <3 RK_PC3 4 &pcfg_pull_up>, + /* uart5_txm1 */ + <3 RK_PC2 4 &pcfg_pull_up>; + }; + }; + + uart6 { + /omit-if-no-ref/ + uart6m0_xfer: uart6m0-xfer { + rockchip,pins = + /* uart6_rxm0 */ + <2 RK_PA3 3 &pcfg_pull_up>, + /* uart6_txm0 */ + <2 RK_PA4 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart6m0_ctsn: uart6m0-ctsn { + rockchip,pins = + /* uart6m0_ctsn */ + <2 RK_PC0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart6m0_rtsn: uart6m0-rtsn { + rockchip,pins = + /* uart6m0_rtsn */ + <2 RK_PB7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart6m1_xfer: uart6m1-xfer { + rockchip,pins = + /* uart6_rxm1 */ + <1 RK_PD6 3 &pcfg_pull_up>, + /* uart6_txm1 */ + <1 RK_PD5 3 &pcfg_pull_up>; + }; + }; + + uart7 { + /omit-if-no-ref/ + uart7m0_xfer: uart7m0-xfer { + rockchip,pins = + /* uart7_rxm0 */ + <2 RK_PA5 3 &pcfg_pull_up>, + /* uart7_txm0 */ + <2 RK_PA6 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart7m0_ctsn: uart7m0-ctsn { + rockchip,pins = + /* uart7m0_ctsn */ + <2 RK_PC2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart7m0_rtsn: uart7m0-rtsn { + rockchip,pins = + /* uart7m0_rtsn */ + <2 RK_PC1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart7m1_xfer: uart7m1-xfer { + rockchip,pins = + /* uart7_rxm1 */ + <3 RK_PC5 4 &pcfg_pull_up>, + /* uart7_txm1 */ + <3 RK_PC4 4 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart7m2_xfer: uart7m2-xfer { + rockchip,pins = + /* uart7_rxm2 */ + <4 RK_PA3 4 &pcfg_pull_up>, + /* uart7_txm2 */ + <4 RK_PA2 4 &pcfg_pull_up>; + }; + }; + + uart8 { + /omit-if-no-ref/ + uart8m0_xfer: uart8m0-xfer { + rockchip,pins = + /* uart8_rxm0 */ + <2 RK_PC6 2 &pcfg_pull_up>, + /* uart8_txm0 */ + <2 RK_PC5 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart8m0_ctsn: uart8m0-ctsn { + rockchip,pins = + /* uart8m0_ctsn */ + <2 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart8m0_rtsn: uart8m0-rtsn { + rockchip,pins = + /* uart8m0_rtsn */ + <2 RK_PB1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart8m1_xfer: uart8m1-xfer { + rockchip,pins = + /* uart8_rxm1 */ + <3 RK_PA0 4 &pcfg_pull_up>, + /* uart8_txm1 */ + <2 RK_PD7 4 &pcfg_pull_up>; + }; + }; + + uart9 { + /omit-if-no-ref/ + uart9m0_xfer: uart9m0-xfer { + rockchip,pins = + /* uart9_rxm0 */ + <2 RK_PA7 3 &pcfg_pull_up>, + /* uart9_txm0 */ + <2 RK_PB0 3 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart9m0_ctsn: uart9m0-ctsn { + rockchip,pins = + /* uart9m0_ctsn */ + <2 RK_PC4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart9m0_rtsn: uart9m0-rtsn { + rockchip,pins = + /* uart9m0_rtsn */ + <2 RK_PC3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart9m1_xfer: uart9m1-xfer { + rockchip,pins = + /* uart9_rxm1 */ + <4 RK_PC6 4 &pcfg_pull_up>, + /* uart9_txm1 */ + <4 RK_PC5 4 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart9m2_xfer: uart9m2-xfer { + rockchip,pins = + /* uart9_rxm2 */ + <4 RK_PA5 4 &pcfg_pull_up>, + /* uart9_txm2 */ + <4 RK_PA4 4 &pcfg_pull_up>; + }; + }; + + vop { + /omit-if-no-ref/ + vopm0_pins: vopm0-pins { + rockchip,pins = + /* vop_pwmm0 */ + <0 RK_PC3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + vopm1_pins: vopm1-pins { + rockchip,pins = + /* vop_pwmm1 */ + <3 RK_PC4 2 &pcfg_pull_none>; + }; + }; +}; + +/* + * This part is edited handly. + */ +&pinctrl { + spi0-hs { + /omit-if-no-ref/ + spi0m0_pins_hs: spi0m0-pins { + rockchip,pins = + /* spi0_clkm0 */ + <0 RK_PB5 2 &pcfg_pull_up_drv_level_1>, + /* spi0_misom0 */ + <0 RK_PC5 2 &pcfg_pull_up_drv_level_1>, + /* spi0_mosim0 */ + <0 RK_PB6 2 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi0m0_cs0_hs: spi0m0-cs0 { + rockchip,pins = + /* spi0_cs0m0 */ + <0 RK_PC6 2 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi0m0_cs1_hs: spi0m0-cs1 { + rockchip,pins = + /* spi0_cs1m0 */ + <0 RK_PC4 2 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi0m1_pins_hs: spi0m1-pins { + rockchip,pins = + /* spi0_clkm1 */ + <2 RK_PD3 3 &pcfg_pull_up_drv_level_1>, + /* spi0_misom1 */ + <2 RK_PD0 3 &pcfg_pull_up_drv_level_1>, + /* spi0_mosim1 */ + <2 RK_PD1 3 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi0m1_cs0_hs: spi0m1-cs0 { + rockchip,pins = + /* spi0_cs0m1 */ + <2 RK_PD2 3 &pcfg_pull_up_drv_level_1>; + }; + }; + + spi1-hs { + /omit-if-no-ref/ + spi1m0_pins_hs: spi1m0-pins { + rockchip,pins = + /* spi1_clkm0 */ + <2 RK_PB5 3 &pcfg_pull_up_drv_level_1>, + /* spi1_misom0 */ + <2 RK_PB6 3 &pcfg_pull_up_drv_level_1>, + /* spi1_mosim0 */ + <2 RK_PB7 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi1m0_cs0_hs: spi1m0-cs0 { + rockchip,pins = + /* spi1_cs0m0 */ + <2 RK_PC0 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi1m0_cs1_hs: spi1m0-cs1 { + rockchip,pins = + /* spi1_cs1m0 */ + <2 RK_PC6 3 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi1m1_pins_hs: spi1m1-pins { + rockchip,pins = + /* spi1_clkm1 */ + <3 RK_PC3 3 &pcfg_pull_up_drv_level_1>, + /* spi1_misom1 */ + <3 RK_PC2 3 &pcfg_pull_up_drv_level_1>, + /* spi1_mosim1 */ + <3 RK_PC1 3 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi1m1_cs0_hs: spi1m1-cs0 { + rockchip,pins = + /* spi1_cs0m1 */ + <3 RK_PA1 3 &pcfg_pull_up_drv_level_1>; + }; + }; + + spi2-hs { + /omit-if-no-ref/ + spi2m0_pins_hs: spi2m0-pins { + rockchip,pins = + /* spi2_clkm0 */ + <2 RK_PC1 4 &pcfg_pull_up_drv_level_1>, + /* spi2_misom0 */ + <2 RK_PC2 4 &pcfg_pull_up_drv_level_1>, + /* spi2_mosim0 */ + <2 RK_PC3 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi2m0_cs0_hs: spi2m0-cs0 { + rockchip,pins = + /* spi2_cs0m0 */ + <2 RK_PC4 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi2m0_cs1_hs: spi2m0-cs1 { + rockchip,pins = + /* spi2_cs1m0 */ + <2 RK_PC5 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi2m1_pins_hs: spi2m1-pins { + rockchip,pins = + /* spi2_clkm1 */ + <3 RK_PA0 3 &pcfg_pull_up_drv_level_1>, + /* spi2_misom1 */ + <2 RK_PD7 3 &pcfg_pull_up_drv_level_1>, + /* spi2_mosim1 */ + <2 RK_PD6 3 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi2m1_cs0_hs: spi2m1-cs0 { + rockchip,pins = + /* spi2_cs0m1 */ + <2 RK_PD5 3 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi2m1_cs1_hs: spi2m1-cs1 { + rockchip,pins = + /* spi2_cs1m1 */ + <2 RK_PD4 3 &pcfg_pull_up_drv_level_1>; + }; + }; + + spi3-hs { + /omit-if-no-ref/ + spi3m0_pins_hs: spi3m0-pins { + rockchip,pins = + /* spi3_clkm0 */ + <4 RK_PB3 4 &pcfg_pull_up_drv_level_1>, + /* spi3_misom0 */ + <4 RK_PB0 4 &pcfg_pull_up_drv_level_1>, + /* spi3_mosim0 */ + <4 RK_PB2 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi3m0_cs0_hs: spi3m0-cs0 { + rockchip,pins = + /* spi3_cs0m0 */ + <4 RK_PA6 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi3m0_cs1_hs: spi3m0-cs1 { + rockchip,pins = + /* spi3_cs1m0 */ + <4 RK_PA7 4 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi3m1_pins_hs: spi3m1-pins { + rockchip,pins = + /* spi3_clkm1 */ + <4 RK_PC2 2 &pcfg_pull_up_drv_level_1>, + /* spi3_misom1 */ + <4 RK_PC5 2 &pcfg_pull_up_drv_level_1>, + /* spi3_mosim1 */ + <4 RK_PC3 2 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi3m1_cs0_hs: spi3m1-cs0 { + rockchip,pins = + /* spi3_cs0m1 */ + <4 RK_PC6 2 &pcfg_pull_up_drv_level_1>; + }; + + /omit-if-no-ref/ + spi3m1_cs1_hs: spi3m1-cs1 { + rockchip,pins = + /* spi3_cs1m1 */ + <4 RK_PD1 2 &pcfg_pull_up_drv_level_1>; + }; + }; + + gmac-txd-level3 { + /omit-if-no-ref/ + gmac0_tx_bus2_level3: gmac0-tx-bus2-level3 { + rockchip,pins = + /* gmac0_txd0 */ + <2 RK_PB3 1 &pcfg_pull_none_drv_level_3>, + /* gmac0_txd1 */ + <2 RK_PB4 1 &pcfg_pull_none_drv_level_3>, + /* gmac0_txen */ + <2 RK_PB5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac0_rgmii_bus_level3: gmac0-rgmii-bus-level3 { + rockchip,pins = + /* gmac0_rxd2 */ + <2 RK_PA3 2 &pcfg_pull_none>, + /* gmac0_rxd3 */ + <2 RK_PA4 2 &pcfg_pull_none>, + /* gmac0_txd2 */ + <2 RK_PA6 2 &pcfg_pull_none_drv_level_3>, + /* gmac0_txd3 */ + <2 RK_PA7 2 &pcfg_pull_none_drv_level_3>; + }; + + /omit-if-no-ref/ + gmac1m0_tx_bus2_level3: gmac1m0-tx-bus2-level3 { + rockchip,pins = + /* gmac1_txd0m0 */ + <3 RK_PB5 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txd1m0 */ + <3 RK_PB6 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txenm0 */ + <3 RK_PB7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m0_rgmii_bus_level3: gmac1m0-rgmii-bus-level3 { + rockchip,pins = + /* gmac1_rxd2m0 */ + <3 RK_PA4 3 &pcfg_pull_none>, + /* gmac1_rxd3m0 */ + <3 RK_PA5 3 &pcfg_pull_none>, + /* gmac1_txd2m0 */ + <3 RK_PA2 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txd3m0 */ + <3 RK_PA3 3 &pcfg_pull_none_drv_level_3>; + }; + + /omit-if-no-ref/ + gmac1m1_tx_bus2_level3: gmac1m1-tx-bus2-level3 { + rockchip,pins = + /* gmac1_txd0m1 */ + <4 RK_PA4 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txd1m1 */ + <4 RK_PA5 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txenm1 */ + <4 RK_PA6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + gmac1m1_rgmii_bus_level3: gmac1m1-rgmii-bus-level3 { + rockchip,pins = + /* gmac1_rxd2m1 */ + <4 RK_PA1 3 &pcfg_pull_none>, + /* gmac1_rxd3m1 */ + <4 RK_PA2 3 &pcfg_pull_none>, + /* gmac1_txd2m1 */ + <3 RK_PD6 3 &pcfg_pull_none_drv_level_3>, + /* gmac1_txd3m1 */ + <3 RK_PD7 3 &pcfg_pull_none_drv_level_3>; + }; + }; + + gmac-txc-level2 { + /omit-if-no-ref/ + gmac0_rgmii_clk_level2: gmac0-rgmii-clk-level2 { + rockchip,pins = + /* gmac0_rxclk */ + <2 RK_PA5 2 &pcfg_pull_none>, + /* gmac0_txclk */ + <2 RK_PB0 2 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + gmac1m0_rgmii_clk_level2: gmac1m0-rgmii-clk-level2 { + rockchip,pins = + /* gmac1_rxclkm0 */ + <3 RK_PA7 3 &pcfg_pull_none>, + /* gmac1_txclkm0 */ + <3 RK_PA6 3 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + gmac1m1_rgmii_clk_level2: gmac1m1-rgmii-clk-level2 { + rockchip,pins = + /* gmac1_rxclkm1 */ + <4 RK_PA3 3 &pcfg_pull_none>, + /* gmac1_txclkm1 */ + <4 RK_PA0 3 &pcfg_pull_none_drv_level_2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi new file mode 100644 index 000000000000..d225e6a45d5c --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -0,0 +1,593 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "rockchip,rk3568"; + + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + clocks = <&scmi_clk 0>; + enable-method = "psci"; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: cpu0-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1150000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <900000 900000 1150000>; + opp-suspend; + }; + + opp-1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <900000 900000 1150000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <900000 900000 1150000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <975000 975000 1150000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1050000 1050000 1150000>; + }; + + opp-1992000000 { + opp-hz = /bits/ 64 <1992000000>; + opp-microvolt = <1150000 1150000 1150000>; + }; + }; + + firmware { + scmi: scmi { + compatible = "arm,scmi-smc"; + arm,smc-id = <0x82000010>; + shmem = <&scmi_shmem>; + #address-cells = <1>; + #size-cells = <0>; + + scmi_clk: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + }; + }; + + pmu { + compatible = "arm,cortex-a55-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + arm,no-tick-in-suspend; + }; + + xin24m: xin24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xin24m"; + #clock-cells = <0>; + }; + + xin32k: xin32k { + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "xin32k"; + pinctrl-0 = <&clk32k_out0>; + pinctrl-names = "default"; + #clock-cells = <0>; + }; + + sram@10f000 { + compatible = "mmio-sram"; + reg = <0x0 0x0010f000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x0010f000 0x100>; + + scmi_shmem: sram@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x100>; + }; + }; + + gic: interrupt-controller@fd400000 { + compatible = "arm,gic-v3"; + reg = <0x0 0xfd400000 0 0x10000>, /* GICD */ + <0x0 0xfd460000 0 0x80000>; /* GICR */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + mbi-alias = <0x0 0xfd100000>; + mbi-ranges = <296 24>; + msi-controller; + }; + + pmugrf: syscon@fdc20000 { + compatible = "rockchip,rk3568-pmugrf", "syscon", "simple-mfd"; + reg = <0x0 0xfdc20000 0x0 0x10000>; + }; + + grf: syscon@fdc60000 { + compatible = "rockchip,rk3568-grf", "syscon", "simple-mfd"; + reg = <0x0 0xfdc60000 0x0 0x10000>; + }; + + pmucru: clock-controller@fdd00000 { + compatible = "rockchip,rk3568-pmucru"; + reg = <0x0 0xfdd00000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@fdd20000 { + compatible = "rockchip,rk3568-cru"; + reg = <0x0 0xfdd20000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + i2c0: i2c@fdd40000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfdd40000 0x0 0x1000>; + interrupts = ; + clocks = <&pmucru CLK_I2C0>, <&pmucru PCLK_I2C0>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart0: serial@fdd50000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfdd50000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru SCLK_UART0>, <&pmucru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 0>, <&dmac0 1>; + pinctrl-0 = <&uart0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + sdmmc2: mmc@fe000000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe000000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC2>, <&cru CLK_SDMMC2>, + <&cru SCLK_SDMMC2_DRV>, <&cru SCLK_SDMMC2_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC2>; + reset-names = "reset"; + status = "disabled"; + }; + + sdmmc0: mmc@fe2b0000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe2b0000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>, + <&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC0>; + reset-names = "reset"; + status = "disabled"; + }; + + sdmmc1: mmc@fe2c0000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe2c0000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC1>, <&cru CLK_SDMMC1>, + <&cru SCLK_SDMMC1_DRV>, <&cru SCLK_SDMMC1_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC1>; + reset-names = "reset"; + status = "disabled"; + }; + + sdhci: mmc@fe310000 { + compatible = "rockchip,rk3568-dwcmshc"; + reg = <0x0 0xfe310000 0x0 0x10000>; + interrupts = ; + assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>; + assigned-clock-rates = <200000000>, <24000000>; + clocks = <&cru CCLK_EMMC>, <&cru HCLK_EMMC>, + <&cru ACLK_EMMC>, <&cru BCLK_EMMC>, + <&cru TCLK_EMMC>; + clock-names = "core", "bus", "axi", "block", "timer"; + status = "disabled"; + }; + + dmac0: dmac@fe530000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xfe530000 0x0 0x4000>; + interrupts = , + ; + arm,pl330-periph-burst; + clocks = <&cru ACLK_BUS>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + }; + + dmac1: dmac@fe550000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xfe550000 0x0 0x4000>; + interrupts = , + ; + arm,pl330-periph-burst; + clocks = <&cru ACLK_BUS>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + }; + + i2c1: i2c@fe5a0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5a0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c1_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@fe5b0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5b0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c2m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@fe5c0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5c0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c3m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@fe5d0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5d0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c4m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@fe5e0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5e0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C5>, <&cru PCLK_I2C5>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c5m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart1: serial@fe650000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe650000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 2>, <&dmac0 3>; + pinctrl-0 = <&uart1m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: serial@fe660000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe660000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 4>, <&dmac0 5>; + pinctrl-0 = <&uart2m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart3: serial@fe670000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe670000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 6>, <&dmac0 7>; + pinctrl-0 = <&uart3m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart4: serial@fe680000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe680000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 8>, <&dmac0 9>; + pinctrl-0 = <&uart4m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart5: serial@fe690000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe690000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 10>, <&dmac0 11>; + pinctrl-0 = <&uart5m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart6: serial@fe6a0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6a0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART6>, <&cru PCLK_UART6>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 12>, <&dmac0 13>; + pinctrl-0 = <&uart6m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart7: serial@fe6b0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6b0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART7>, <&cru PCLK_UART7>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 14>, <&dmac0 15>; + pinctrl-0 = <&uart7m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart8: serial@fe6c0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6c0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART8>, <&cru PCLK_UART8>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 16>, <&dmac0 17>; + pinctrl-0 = <&uart8m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart9: serial@fe6d0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6d0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART9>, <&cru PCLK_UART9>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 18>, <&dmac0 19>; + pinctrl-0 = <&uart9m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3568-pinctrl"; + rockchip,grf = <&grf>; + rockchip,pmu = <&pmugrf>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio0: gpio@fdd60000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfdd60000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru PCLK_GPIO0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@fe740000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe740000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@fe750000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe750000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@fe760000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe760000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO3>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@fe770000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe770000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO4>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + +#include "rk3568-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rockchip-pinconf.dtsi b/arch/arm64/boot/dts/rockchip/rockchip-pinconf.dtsi new file mode 100644 index 000000000000..5c645437b507 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rockchip-pinconf.dtsi @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + */ + +&pinctrl { + /omit-if-no-ref/ + pcfg_pull_up: pcfg-pull-up { + bias-pull-up; + }; + + /omit-if-no-ref/ + pcfg_pull_down: pcfg-pull-down { + bias-pull-down; + }; + + /omit-if-no-ref/ + pcfg_pull_none: pcfg-pull-none { + bias-disable; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_0: pcfg-pull-none-drv-level-0 { + bias-disable; + drive-strength = <0>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_1: pcfg-pull-none-drv-level-1 { + bias-disable; + drive-strength = <1>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_2: pcfg-pull-none-drv-level-2 { + bias-disable; + drive-strength = <2>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_3: pcfg-pull-none-drv-level-3 { + bias-disable; + drive-strength = <3>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_4: pcfg-pull-none-drv-level-4 { + bias-disable; + drive-strength = <4>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_5: pcfg-pull-none-drv-level-5 { + bias-disable; + drive-strength = <5>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_6: pcfg-pull-none-drv-level-6 { + bias-disable; + drive-strength = <6>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_7: pcfg-pull-none-drv-level-7 { + bias-disable; + drive-strength = <7>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_8: pcfg-pull-none-drv-level-8 { + bias-disable; + drive-strength = <8>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_9: pcfg-pull-none-drv-level-9 { + bias-disable; + drive-strength = <9>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_10: pcfg-pull-none-drv-level-10 { + bias-disable; + drive-strength = <10>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_11: pcfg-pull-none-drv-level-11 { + bias-disable; + drive-strength = <11>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_12: pcfg-pull-none-drv-level-12 { + bias-disable; + drive-strength = <12>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_13: pcfg-pull-none-drv-level-13 { + bias-disable; + drive-strength = <13>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_14: pcfg-pull-none-drv-level-14 { + bias-disable; + drive-strength = <14>; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_15: pcfg-pull-none-drv-level-15 { + bias-disable; + drive-strength = <15>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_0: pcfg-pull-up-drv-level-0 { + bias-pull-up; + drive-strength = <0>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_1: pcfg-pull-up-drv-level-1 { + bias-pull-up; + drive-strength = <1>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_2: pcfg-pull-up-drv-level-2 { + bias-pull-up; + drive-strength = <2>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_3: pcfg-pull-up-drv-level-3 { + bias-pull-up; + drive-strength = <3>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_4: pcfg-pull-up-drv-level-4 { + bias-pull-up; + drive-strength = <4>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_5: pcfg-pull-up-drv-level-5 { + bias-pull-up; + drive-strength = <5>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_6: pcfg-pull-up-drv-level-6 { + bias-pull-up; + drive-strength = <6>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_7: pcfg-pull-up-drv-level-7 { + bias-pull-up; + drive-strength = <7>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_8: pcfg-pull-up-drv-level-8 { + bias-pull-up; + drive-strength = <8>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_9: pcfg-pull-up-drv-level-9 { + bias-pull-up; + drive-strength = <9>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_10: pcfg-pull-up-drv-level-10 { + bias-pull-up; + drive-strength = <10>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_11: pcfg-pull-up-drv-level-11 { + bias-pull-up; + drive-strength = <11>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_12: pcfg-pull-up-drv-level-12 { + bias-pull-up; + drive-strength = <12>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_13: pcfg-pull-up-drv-level-13 { + bias-pull-up; + drive-strength = <13>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_14: pcfg-pull-up-drv-level-14 { + bias-pull-up; + drive-strength = <14>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_drv_level_15: pcfg-pull-up-drv-level-15 { + bias-pull-up; + drive-strength = <15>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_0: pcfg-pull-down-drv-level-0 { + bias-pull-down; + drive-strength = <0>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_1: pcfg-pull-down-drv-level-1 { + bias-pull-down; + drive-strength = <1>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_2: pcfg-pull-down-drv-level-2 { + bias-pull-down; + drive-strength = <2>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_3: pcfg-pull-down-drv-level-3 { + bias-pull-down; + drive-strength = <3>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_4: pcfg-pull-down-drv-level-4 { + bias-pull-down; + drive-strength = <4>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_5: pcfg-pull-down-drv-level-5 { + bias-pull-down; + drive-strength = <5>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_6: pcfg-pull-down-drv-level-6 { + bias-pull-down; + drive-strength = <6>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_7: pcfg-pull-down-drv-level-7 { + bias-pull-down; + drive-strength = <7>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_8: pcfg-pull-down-drv-level-8 { + bias-pull-down; + drive-strength = <8>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_9: pcfg-pull-down-drv-level-9 { + bias-pull-down; + drive-strength = <9>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_10: pcfg-pull-down-drv-level-10 { + bias-pull-down; + drive-strength = <10>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_11: pcfg-pull-down-drv-level-11 { + bias-pull-down; + drive-strength = <11>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_12: pcfg-pull-down-drv-level-12 { + bias-pull-down; + drive-strength = <12>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_13: pcfg-pull-down-drv-level-13 { + bias-pull-down; + drive-strength = <13>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_14: pcfg-pull-down-drv-level-14 { + bias-pull-down; + drive-strength = <14>; + }; + + /omit-if-no-ref/ + pcfg_pull_down_drv_level_15: pcfg-pull-down-drv-level-15 { + bias-pull-down; + drive-strength = <15>; + }; + + /omit-if-no-ref/ + pcfg_pull_up_smt: pcfg-pull-up-smt { + bias-pull-up; + input-schmitt-enable; + }; + + /omit-if-no-ref/ + pcfg_pull_down_smt: pcfg-pull-down-smt { + bias-pull-down; + input-schmitt-enable; + }; + + /omit-if-no-ref/ + pcfg_pull_none_smt: pcfg-pull-none-smt { + bias-disable; + input-schmitt-enable; + }; + + /omit-if-no-ref/ + pcfg_pull_none_drv_level_0_smt: pcfg-pull-none-drv-level-0-smt { + bias-disable; + drive-strength = <0>; + input-schmitt-enable; + }; + + /omit-if-no-ref/ + pcfg_output_high: pcfg-output-high { + output-high; + }; + + /omit-if-no-ref/ + pcfg_output_low: pcfg-output-low { + output-low; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index ca59d1f711f8..02c3fdf9cc46 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -5,6 +5,17 @@ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ */ +#include +#include + +/ { + serdes_refclk: clock-cmnrefclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; + &cbass_main { oc_sram: sram@70000000 { compatible = "mmio-sram"; @@ -13,8 +24,30 @@ #size-cells = <1>; ranges = <0x0 0x00 0x70000000 0x200000>; - atf-sram@0 { - reg = <0x0 0x1a000>; + tfa-sram@1c0000 { + reg = <0x1c0000 0x20000>; + }; + + dmsc-sram@1e0000 { + reg = <0x1e0000 0x1c000>; + }; + + sproxy-sram@1fc000 { + reg = <0x1fc000 0x4000>; + }; + }; + + main_conf: syscon@43000000 { + compatible = "ti,j721e-system-controller", "syscon", "simple-mfd"; + reg = <0x0 0x43000000 0x0 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x43000000 0x20000>; + + serdes_ln_ctrl: mux-controller { + compatible = "mmio-mux"; + #mux-control-cells = <1>; + mux-reg-masks = <0x4080 0x3>; /* SERDES0 lane0 select */ }; }; @@ -189,8 +222,6 @@ main_uart0: serial@2800000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02800000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -202,8 +233,6 @@ main_uart1: serial@2810000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02810000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -215,8 +244,6 @@ main_uart2: serial@2820000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02820000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -228,8 +255,6 @@ main_uart3: serial@2830000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02830000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -241,8 +266,6 @@ main_uart4: serial@2840000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02840000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -254,8 +277,6 @@ main_uart5: serial@2850000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02850000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -267,8 +288,6 @@ main_uart6: serial@2860000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x02860000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -489,7 +508,8 @@ ti,mac-only; label = "port1"; phys = <&phy_gmii_sel 1>; - mac-address = [00 00 de ad be ef]; + mac-address = [00 00 00 00 00 00]; + ti,syscon-efuse = <&main_conf 0x200>; }; cpsw_port2: port@2 { @@ -497,7 +517,7 @@ ti,mac-only; label = "port2"; phys = <&phy_gmii_sel 2>; - mac-address = [00 01 de ad be ef]; + mac-address = [00 00 00 00 00 00]; }; }; @@ -673,4 +693,170 @@ ti,mbox-num-users = <4>; ti,mbox-num-fifos = <16>; }; + + main_r5fss0: r5fss@78000000 { + compatible = "ti,am64-r5fss"; + ti,cluster-mode = <0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x78000000 0x00 0x78000000 0x10000>, + <0x78100000 0x00 0x78100000 0x10000>, + <0x78200000 0x00 0x78200000 0x08000>, + <0x78300000 0x00 0x78300000 0x08000>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss0_core0: r5f@78000000 { + compatible = "ti,am64-r5f"; + reg = <0x78000000 0x00010000>, + <0x78100000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <121>; + ti,sci-proc-ids = <0x01 0xff>; + resets = <&k3_reset 121 1>; + firmware-name = "am64-main-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss0_core1: r5f@78200000 { + compatible = "ti,am64-r5f"; + reg = <0x78200000 0x00008000>, + <0x78300000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <122>; + ti,sci-proc-ids = <0x02 0xff>; + resets = <&k3_reset 122 1>; + firmware-name = "am64-main-r5f0_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + main_r5fss1: r5fss@78400000 { + compatible = "ti,am64-r5fss"; + ti,cluster-mode = <0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x78400000 0x00 0x78400000 0x10000>, + <0x78500000 0x00 0x78500000 0x10000>, + <0x78600000 0x00 0x78600000 0x08000>, + <0x78700000 0x00 0x78700000 0x08000>; + power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss1_core0: r5f@78400000 { + compatible = "ti,am64-r5f"; + reg = <0x78400000 0x00010000>, + <0x78500000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <123>; + ti,sci-proc-ids = <0x06 0xff>; + resets = <&k3_reset 123 1>; + firmware-name = "am64-main-r5f1_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss1_core1: r5f@78600000 { + compatible = "ti,am64-r5f"; + reg = <0x78600000 0x00008000>, + <0x78700000 0x00008000>; + reg-names = "atcm", "btcm"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <124>; + ti,sci-proc-ids = <0x07 0xff>; + resets = <&k3_reset 124 1>; + firmware-name = "am64-main-r5f1_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + serdes_wiz0: wiz@f000000 { + compatible = "ti,am64-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 162 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 162 0>, <&k3_clks 162 1>, <&serdes_refclk>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk"; + num-lanes = <1>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x0f000000 0x0 0x0f000000 0x00010000>; + + assigned-clocks = <&k3_clks 162 1>; + assigned-clock-parents = <&k3_clks 162 5>; + + serdes0: serdes@f000000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x0f000000 0x00010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz0 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz0 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 162 1>, + <&k3_clks 162 1>, + <&k3_clks 162 1>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + }; + }; + + pcie0_rc: pcie@f102000 { + compatible = "ti,am64-pcie-host", "ti,j721e-pcie-host"; + reg = <0x00 0x0f102000 0x00 0x1000>, + <0x00 0x0f100000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x68000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&main_conf 0x4070>; + max-link-speed = <2>; + num-lanes = <1>; + power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 114 0>, <&serdes0 CDNS_TORRENT_REFCLK_DRIVER>; + clock-names = "fck", "pcie_refclk"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + cdns,no-bar-match-nbits = <64>; + vendor-id = <0x104c>; + device-id = <0xb010>; + msi-map = <0x0 &gic_its 0x0 0x10000>; + ranges = <0x01000000 0x00 0x68001000 0x00 0x68001000 0x00 0x0010000>, + <0x02000000 0x00 0x68011000 0x00 0x68011000 0x00 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x00000010 0x0>; + }; + + pcie0_ep: pcie-ep@f102000 { + compatible = "ti,am64-pcie-ep", "ti,j721e-pcie-ep"; + reg = <0x00 0x0f102000 0x00 0x1000>, + <0x00 0x0f100000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x68000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&main_conf 0x4070>; + max-link-speed = <2>; + num-lanes = <1>; + power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 114 0>; + clock-names = "fck"; + max-functions = /bits/ 8 <1>; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi index deb19ae5e168..59cc58f7d0c8 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi @@ -9,8 +9,6 @@ mcu_uart0: serial@4a00000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x04a00000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -22,8 +20,6 @@ mcu_uart1: serial@4a10000 { compatible = "ti,am64-uart", "ti,am654-uart"; reg = <0x00 0x04a10000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -87,7 +83,7 @@ }; mcu_gpio0: gpio@4201000 { - compatible = "ti,am64-gpio", "keystone-gpio"; + compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x4201000 0x0 0x100>; gpio-controller; #gpio-cells = <2>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts index dad0efa961ed..030712221188 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -5,6 +5,8 @@ /dts-v1/; +#include +#include #include #include #include @@ -36,6 +38,60 @@ 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; + }; + + rtos_ipc_memory_region: ipc-memories@a5000000 { + reg = <0x00 0xa5000000 0x00 0x00800000>; + alignment = <0x1000>; + no-map; + }; }; evm_12v0: fixedregulator-evm12v0 { @@ -334,7 +390,7 @@ &main_spi0 { pinctrl-names = "default"; pinctrl-0 = <&main_spi0_pins_default>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; eeprom@0 { compatible = "microchip,93lc46b"; reg = <0>; @@ -466,3 +522,55 @@ &mailbox0_cluster7 { status = "disabled"; }; + +&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>; +}; + +&serdes_ln_ctrl { + idle-states = ; +}; + +&serdes0 { + serdes0_pcie_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>; + }; +}; + +&pcie0_rc { + reset-gpios = <&exp1 5 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + num-lanes = <1>; +}; + +&pcie0_ep { + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + num-lanes = <1>; + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts index 8424cd071955..d3aa2901e6fd 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -5,6 +5,8 @@ /dts-v1/; +#include +#include #include #include #include "k3-am642.dtsi" @@ -35,6 +37,60 @@ 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; + }; + + rtos_ipc_memory_region: ipc-memories@a5000000 { + reg = <0x00 0xa5000000 0x00 0x00800000>; + alignment = <0x1000>; + no-map; + }; }; vusb_main: fixed-regulator-vusb-main5v0 { @@ -85,6 +141,12 @@ >; }; + main_usb0_pins_default: main-usb0-pins-default { + pinctrl-single,pins = < + AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */ + >; + }; + main_i2c1_pins_default: main-i2c1-pins-default { pinctrl-single,pins = < AM64X_IOPAD(0x0268, PIN_INPUT_PULLUP, 0) /* (C18) I2C1_SCL */ @@ -235,6 +297,33 @@ disable-wp; }; +&serdes_ln_ctrl { + idle-states = ; +}; + +&serdes0 { + serdes0_usb_link: phy@0 { + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>; + }; +}; + +&usbss0 { + ti,vbus-divider; +}; + +&usb0 { + dr_mode = "host"; + maximum-speed = "super-speed"; + pinctrl-names = "default"; + pinctrl-0 = <&main_usb0_pins_default>; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; + &cpsw3g { pinctrl-names = "default"; pinctrl-0 = <&mdio1_pins_default @@ -332,3 +421,35 @@ &mailbox0_cluster7 { status = "disabled"; }; + +&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>; +}; + +&pcie0_rc { + status = "disabled"; +}; + +&pcie0_ep { + 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 de763ca9251c..1008e9162ba2 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -555,6 +555,7 @@ pinctrl-0 = <&main_mmc1_pins_default>; ti,driver-strength-ohm = <50>; disable-wp; + no-1-8-v; }; &usb0 { @@ -575,7 +576,7 @@ #address-cells = <1>; #size-cells= <0>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; }; &tscadc0 { @@ -653,3 +654,63 @@ &pcie1_ep { status = "disabled"; }; + +&mailbox0_cluster0 { + status = "disabled"; +}; + +&mailbox0_cluster1 { + status = "disabled"; +}; + +&mailbox0_cluster2 { + status = "disabled"; +}; + +&mailbox0_cluster3 { + status = "disabled"; +}; + +&mailbox0_cluster4 { + status = "disabled"; +}; + +&mailbox0_cluster5 { + status = "disabled"; +}; + +&mailbox0_cluster6 { + status = "disabled"; +}; + +&mailbox0_cluster7 { + status = "disabled"; +}; + +&mailbox0_cluster8 { + status = "disabled"; +}; + +&mailbox0_cluster9 { + status = "disabled"; +}; + +&mailbox0_cluster10 { + status = "disabled"; +}; + +&mailbox0_cluster11 { + status = "disabled"; +}; + +&icssg0_mdio { + status = "disabled"; +}; + +&icssg1_mdio { + status = "disabled"; +}; + +&icssg2_mdio { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 6cd3131eb9ff..ba4e5d3e1ed7 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -84,8 +84,6 @@ main_uart0: serial@2800000 { compatible = "ti,am654-uart"; reg = <0x00 0x02800000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -95,8 +93,6 @@ main_uart1: serial@2810000 { compatible = "ti,am654-uart"; reg = <0x00 0x02810000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>; @@ -105,8 +101,6 @@ main_uart2: serial@2820000 { compatible = "ti,am654-uart"; reg = <0x00 0x02820000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>; @@ -301,7 +295,6 @@ ti,otap-del-sel = <0x2>; ti,trm-icp = <0x8>; dma-coherent; - no-1-8-v; }; scm_conf: scm-conf@100000 { @@ -1053,6 +1046,16 @@ reg-names = "iram", "control", "debug"; firmware-name = "am65x-txpru0_1-fw"; }; + + icssg0_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x100>; + clocks = <&k3_clks 62 3>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; }; icssg1: icssg@b100000 { @@ -1184,6 +1187,16 @@ reg-names = "iram", "control", "debug"; firmware-name = "am65x-txpru1_1-fw"; }; + + icssg1_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x100>; + clocks = <&k3_clks 63 3>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; }; icssg2: icssg@b200000 { @@ -1315,5 +1328,15 @@ reg-names = "iram", "control", "debug"; firmware-name = "am65x-txpru2_1-fw"; }; + + icssg2_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x100>; + clocks = <&k3_clks 64 3>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi index f5b8ef2f5f77..c93ff1520a0e 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi @@ -23,8 +23,6 @@ mcu_uart0: serial@40a00000 { compatible = "ti,am654-uart"; reg = <0x00 0x40a00000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <96000000>; current-speed = <115200>; diff --git a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi index 7cb864b4d74a..9d21cdf6fce8 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi @@ -50,8 +50,6 @@ wkup_uart0: serial@42300000 { compatible = "ti,am654-uart"; reg = <0x42300000 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts index 4f7e3f2a6265..94bb5dd39122 100644 --- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts @@ -59,3 +59,8 @@ pinctrl-names = "default"; pinctrl-0 = <&main_uart0_pins_default>; }; + +&mcu_r5fss0 { + /* lock-step mode not supported on this board */ + ti,cluster-mode = <0>; +}; 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 eddb2ffb93ca..cfbcebfa37c1 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts @@ -85,6 +85,38 @@ gpios = <&wkup_gpio0 27 GPIO_ACTIVE_LOW>; }; }; + + evm_12v0: fixedregulator-evm12v0 { + /* main supply */ + compatible = "regulator-fixed"; + regulator-name = "evm_12v0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + vcc3v3_io: fixedregulator-vcc3v3io { + /* Output of TPS54334 */ + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&evm_12v0>; + }; + + vdd_mmc1_sd: fixedregulator-sd { + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + vin-supply = <&vcc3v3_io>; + gpio = <&pca9554 4 GPIO_ACTIVE_HIGH>; + }; }; &wkup_pmx0 { @@ -136,7 +168,7 @@ AM65X_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* (L5) MCU_RGMII1_RD2 */ AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* (M6) MCU_RGMII1_RD1 */ AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* (L6) MCU_RGMII1_RD0 */ - AM65X_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* (N1) MCU_RGMII1_TXC */ + AM65X_WKUP_IOPAD(0x0070, PIN_OUTPUT, 0) /* (N1) MCU_RGMII1_TXC */ AM65X_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* (M1) MCU_RGMII1_RXC */ >; }; @@ -299,7 +331,7 @@ pinctrl-0 = <&main_spi0_pins_default>; #address-cells = <1>; #size-cells= <0>; - ti,pindir-d0-out-d1-in = <1>; + ti,pindir-d0-out-d1-in; flash@0{ compatible = "jedec,spi-nor"; @@ -327,6 +359,7 @@ * disable sdhci1 */ &sdhci1 { + vmmc-supply = <&vdd_mmc1_sd>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; ti,driver-strength-ohm = <50>; @@ -506,3 +539,15 @@ &dss { status = "disabled"; }; + +&icssg0_mdio { + status = "disabled"; +}; + +&icssg1_mdio { + status = "disabled"; +}; + +&icssg2_mdio { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts index bedd01b7a32c..d14f3c18b65f 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts @@ -90,7 +90,7 @@ J721E_WKUP_IOPAD(0x008c, PIN_INPUT, 0) /* MCU_RGMII1_RD2 */ J721E_WKUP_IOPAD(0x0090, PIN_INPUT, 0) /* MCU_RGMII1_RD1 */ J721E_WKUP_IOPAD(0x0094, PIN_INPUT, 0) /* MCU_RGMII1_RD0 */ - J721E_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* MCU_RGMII1_TXC */ + J721E_WKUP_IOPAD(0x0080, PIN_OUTPUT, 0) /* MCU_RGMII1_TXC */ J721E_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* MCU_RGMII1_RXC */ >; }; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index 19fea8adbcff..e8a41d09b45f 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -301,8 +301,6 @@ main_uart0: serial@2800000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02800000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -314,8 +312,6 @@ main_uart1: serial@2810000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02810000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -327,8 +323,6 @@ main_uart2: serial@2820000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02820000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -340,8 +334,6 @@ main_uart3: serial@2830000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02830000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -353,8 +345,6 @@ main_uart4: serial@2840000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02840000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -366,8 +356,6 @@ main_uart5: serial@2850000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02850000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -379,8 +367,6 @@ main_uart6: serial@2860000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02860000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -392,8 +378,6 @@ main_uart7: serial@2870000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02870000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -405,8 +389,6 @@ main_uart8: serial@2880000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02880000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -418,8 +400,6 @@ main_uart9: serial@2890000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02890000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -683,6 +663,7 @@ "otg"; maximum-speed = "super-speed"; dr_mode = "otg"; + cdns,phyrst-a-enable; }; }; @@ -696,7 +677,6 @@ <149>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <69>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; @@ -714,7 +694,6 @@ <158>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <69>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; @@ -732,7 +711,6 @@ <167>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <69>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 109 TI_SCI_PD_EXCLUSIVE>; @@ -750,7 +728,6 @@ <176>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <69>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 111 TI_SCI_PD_EXCLUSIVE>; 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 5663fe3ea466..1044ec6c4b0d 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi @@ -73,8 +73,6 @@ wkup_uart0: serial@42300000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x42300000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -86,8 +84,6 @@ mcu_uart0: serial@40a00000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x40a00000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <96000000>; current-speed = <115200>; @@ -117,7 +113,6 @@ interrupts = <103>, <104>, <105>, <106>, <107>, <108>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <85>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 113 TI_SCI_PD_EXCLUSIVE>; @@ -134,7 +129,6 @@ interrupts = <112>, <113>, <114>, <115>, <116>, <117>; interrupt-controller; #interrupt-cells = <2>; - #address-cells = <0>; ti,ngpio = <85>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts index 60764366e22b..8bd02d9e28ad 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts @@ -9,6 +9,7 @@ #include #include #include +#include / { chosen { @@ -237,7 +238,7 @@ J721E_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* MCU_RGMII1_RD2 */ J721E_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* MCU_RGMII1_RD1 */ J721E_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* MCU_RGMII1_RD0 */ - J721E_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* MCU_RGMII1_TXC */ + J721E_WKUP_IOPAD(0x0070, PIN_OUTPUT, 0) /* MCU_RGMII1_TXC */ J721E_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* MCU_RGMII1_RXC */ >; }; @@ -358,7 +359,7 @@ }; &serdes3 { - serdes3_usb_link: link@0 { + serdes3_usb_link: phy@0 { reg = <0>; cdns,num-lanes = <2>; #phy-cells = <0>; @@ -635,8 +636,45 @@ status = "disabled"; }; +&cmn_refclk1 { + clock-frequency = <100000000>; +}; + +&wiz0_pll1_refclk { + assigned-clocks = <&wiz0_pll1_refclk>; + assigned-clock-parents = <&cmn_refclk1>; +}; + +&wiz0_refclk_dig { + assigned-clocks = <&wiz0_refclk_dig>; + assigned-clock-parents = <&cmn_refclk1>; +}; + +&wiz1_pll1_refclk { + assigned-clocks = <&wiz1_pll1_refclk>; + assigned-clock-parents = <&cmn_refclk1>; +}; + +&wiz1_refclk_dig { + assigned-clocks = <&wiz1_refclk_dig>; + assigned-clock-parents = <&cmn_refclk1>; +}; + +&wiz2_pll1_refclk { + assigned-clocks = <&wiz2_pll1_refclk>; + assigned-clock-parents = <&cmn_refclk1>; +}; + +&wiz2_refclk_dig { + assigned-clocks = <&wiz2_refclk_dig>; + assigned-clock-parents = <&cmn_refclk1>; +}; + &serdes0 { - serdes0_pcie_link: link@0 { + assigned-clocks = <&serdes0 CDNS_SIERRA_PLL_CMNLC>; + assigned-clock-parents = <&wiz0_pll1_refclk>; + + serdes0_pcie_link: phy@0 { reg = <0>; cdns,num-lanes = <1>; #phy-cells = <0>; @@ -646,7 +684,10 @@ }; &serdes1 { - serdes1_pcie_link: link@0 { + assigned-clocks = <&serdes1 CDNS_SIERRA_PLL_CMNLC>; + assigned-clock-parents = <&wiz1_pll1_refclk>; + + serdes1_pcie_link: phy@0 { reg = <0>; cdns,num-lanes = <2>; #phy-cells = <0>; @@ -656,7 +697,10 @@ }; &serdes2 { - serdes2_pcie_link: link@0 { + assigned-clocks = <&serdes2 CDNS_SIERRA_PLL_CMNLC>; + assigned-clock-parents = <&wiz2_pll1_refclk>; + + serdes2_pcie_link: phy@0 { reg = <0>; cdns,num-lanes = <2>; #phy-cells = <0>; @@ -718,3 +762,11 @@ &dss { status = "disabled"; }; + +&icssg0_mdio { + status = "disabled"; +}; + +&icssg1_mdio { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 3bcafe4c1742..cf3482376c1e 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -8,6 +8,20 @@ #include #include +/ { + cmn_refclk: clock-cmnrefclk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + cmn_refclk1: clock-cmnrefclk1 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +}; + &cbass_main { msmc_ram: sram@70000000 { compatible = "mmio-sram"; @@ -338,24 +352,12 @@ pinctrl-single,function-mask = <0xffffffff>; }; - dummy_cmn_refclk: dummy-cmn-refclk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <100000000>; - }; - - dummy_cmn_refclk1: dummy-cmn-refclk1 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <100000000>; - }; - serdes_wiz0: wiz@5000000 { compatible = "ti,j721e-wiz-16g"; #address-cells = <1>; #size-cells = <1>; power-domains = <&k3_pds 292 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 292 5>, <&k3_clks 292 11>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 292 5>, <&k3_clks 292 11>, <&cmn_refclk>; clock-names = "fck", "core_ref_clk", "ext_ref_clk"; assigned-clocks = <&k3_clks 292 11>, <&k3_clks 292 0>; assigned-clock-parents = <&k3_clks 292 15>, <&k3_clks 292 4>; @@ -364,21 +366,21 @@ ranges = <0x5000000 0x0 0x5000000 0x10000>; wiz0_pll0_refclk: pll0-refclk { - clocks = <&k3_clks 292 11>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 292 11>, <&cmn_refclk>; #clock-cells = <0>; assigned-clocks = <&wiz0_pll0_refclk>; assigned-clock-parents = <&k3_clks 292 11>; }; wiz0_pll1_refclk: pll1-refclk { - clocks = <&k3_clks 292 0>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 292 0>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz0_pll1_refclk>; assigned-clock-parents = <&k3_clks 292 0>; }; wiz0_refclk_dig: refclk-dig { - clocks = <&k3_clks 292 11>, <&k3_clks 292 0>, <&dummy_cmn_refclk>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 292 11>, <&k3_clks 292 0>, <&cmn_refclk>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz0_refclk_dig>; assigned-clock-parents = <&k3_clks 292 11>; @@ -400,10 +402,13 @@ reg = <0x5000000 0x10000>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <1>; resets = <&serdes_wiz0 0>; reset-names = "sierra_reset"; - clocks = <&wiz0_cmn_refclk_dig_div>, <&wiz0_cmn_refclk1_dig_div>; - clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div"; + clocks = <&wiz0_cmn_refclk_dig_div>, <&wiz0_cmn_refclk1_dig_div>, + <&wiz0_pll0_refclk>, <&wiz0_pll1_refclk>; + clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div", + "pll0_refclk", "pll1_refclk"; }; }; @@ -412,7 +417,7 @@ #address-cells = <1>; #size-cells = <1>; power-domains = <&k3_pds 293 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 293 5>, <&k3_clks 293 13>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 293 5>, <&k3_clks 293 13>, <&cmn_refclk>; clock-names = "fck", "core_ref_clk", "ext_ref_clk"; assigned-clocks = <&k3_clks 293 13>, <&k3_clks 293 0>; assigned-clock-parents = <&k3_clks 293 17>, <&k3_clks 293 4>; @@ -421,21 +426,21 @@ ranges = <0x5010000 0x0 0x5010000 0x10000>; wiz1_pll0_refclk: pll0-refclk { - clocks = <&k3_clks 293 13>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 293 13>, <&cmn_refclk>; #clock-cells = <0>; assigned-clocks = <&wiz1_pll0_refclk>; assigned-clock-parents = <&k3_clks 293 13>; }; wiz1_pll1_refclk: pll1-refclk { - clocks = <&k3_clks 293 0>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 293 0>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz1_pll1_refclk>; assigned-clock-parents = <&k3_clks 293 0>; }; wiz1_refclk_dig: refclk-dig { - clocks = <&k3_clks 293 13>, <&k3_clks 293 0>, <&dummy_cmn_refclk>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 293 13>, <&k3_clks 293 0>, <&cmn_refclk>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz1_refclk_dig>; assigned-clock-parents = <&k3_clks 293 13>; @@ -457,10 +462,13 @@ reg = <0x5010000 0x10000>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <1>; resets = <&serdes_wiz1 0>; reset-names = "sierra_reset"; - clocks = <&wiz1_cmn_refclk_dig_div>, <&wiz1_cmn_refclk1_dig_div>; - clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div"; + clocks = <&wiz1_cmn_refclk_dig_div>, <&wiz1_cmn_refclk1_dig_div>, + <&wiz1_pll0_refclk>, <&wiz1_pll1_refclk>; + clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div", + "pll0_refclk", "pll1_refclk"; }; }; @@ -469,7 +477,7 @@ #address-cells = <1>; #size-cells = <1>; power-domains = <&k3_pds 294 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 294 5>, <&k3_clks 294 11>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 294 5>, <&k3_clks 294 11>, <&cmn_refclk>; clock-names = "fck", "core_ref_clk", "ext_ref_clk"; assigned-clocks = <&k3_clks 294 11>, <&k3_clks 294 0>; assigned-clock-parents = <&k3_clks 294 15>, <&k3_clks 294 4>; @@ -478,21 +486,21 @@ ranges = <0x5020000 0x0 0x5020000 0x10000>; wiz2_pll0_refclk: pll0-refclk { - clocks = <&k3_clks 294 11>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 294 11>, <&cmn_refclk>; #clock-cells = <0>; assigned-clocks = <&wiz2_pll0_refclk>; assigned-clock-parents = <&k3_clks 294 11>; }; wiz2_pll1_refclk: pll1-refclk { - clocks = <&k3_clks 294 0>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 294 0>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz2_pll1_refclk>; assigned-clock-parents = <&k3_clks 294 0>; }; wiz2_refclk_dig: refclk-dig { - clocks = <&k3_clks 294 11>, <&k3_clks 294 0>, <&dummy_cmn_refclk>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 294 11>, <&k3_clks 294 0>, <&cmn_refclk>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz2_refclk_dig>; assigned-clock-parents = <&k3_clks 294 11>; @@ -514,10 +522,13 @@ reg = <0x5020000 0x10000>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <1>; resets = <&serdes_wiz2 0>; reset-names = "sierra_reset"; - clocks = <&wiz2_cmn_refclk_dig_div>, <&wiz2_cmn_refclk1_dig_div>; - clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div"; + clocks = <&wiz2_cmn_refclk_dig_div>, <&wiz2_cmn_refclk1_dig_div>, + <&wiz2_pll0_refclk>, <&wiz2_pll1_refclk>; + clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div", + "pll0_refclk", "pll1_refclk"; }; }; @@ -526,7 +537,7 @@ #address-cells = <1>; #size-cells = <1>; power-domains = <&k3_pds 295 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 295 5>, <&k3_clks 295 9>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 295 5>, <&k3_clks 295 9>, <&cmn_refclk>; clock-names = "fck", "core_ref_clk", "ext_ref_clk"; assigned-clocks = <&k3_clks 295 9>, <&k3_clks 295 0>; assigned-clock-parents = <&k3_clks 295 13>, <&k3_clks 295 4>; @@ -535,21 +546,21 @@ ranges = <0x5030000 0x0 0x5030000 0x10000>; wiz3_pll0_refclk: pll0-refclk { - clocks = <&k3_clks 295 9>, <&dummy_cmn_refclk>; + clocks = <&k3_clks 295 9>, <&cmn_refclk>; #clock-cells = <0>; assigned-clocks = <&wiz3_pll0_refclk>; assigned-clock-parents = <&k3_clks 295 9>; }; wiz3_pll1_refclk: pll1-refclk { - clocks = <&k3_clks 295 0>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 295 0>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz3_pll1_refclk>; assigned-clock-parents = <&k3_clks 295 0>; }; wiz3_refclk_dig: refclk-dig { - clocks = <&k3_clks 295 9>, <&k3_clks 295 0>, <&dummy_cmn_refclk>, <&dummy_cmn_refclk1>; + clocks = <&k3_clks 295 9>, <&k3_clks 295 0>, <&cmn_refclk>, <&cmn_refclk1>; #clock-cells = <0>; assigned-clocks = <&wiz3_refclk_dig>; assigned-clock-parents = <&k3_clks 295 9>; @@ -571,10 +582,13 @@ reg = <0x5030000 0x10000>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <1>; resets = <&serdes_wiz3 0>; reset-names = "sierra_reset"; - clocks = <&wiz3_cmn_refclk_dig_div>, <&wiz3_cmn_refclk1_dig_div>; - clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div"; + clocks = <&wiz3_cmn_refclk_dig_div>, <&wiz3_cmn_refclk1_dig_div>, + <&wiz3_pll0_refclk>, <&wiz3_pll1_refclk>; + clock-names = "cmn_refclk_dig_div", "cmn_refclk1_dig_div", + "pll0_refclk", "pll1_refclk"; }; }; @@ -775,8 +789,6 @@ main_uart0: serial@2800000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02800000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -788,8 +800,6 @@ main_uart1: serial@2810000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02810000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -801,8 +811,6 @@ main_uart2: serial@2820000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02820000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -814,8 +822,6 @@ main_uart3: serial@2830000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02830000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -827,8 +833,6 @@ main_uart4: serial@2840000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02840000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -840,8 +844,6 @@ main_uart5: serial@2850000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02850000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -853,8 +855,6 @@ main_uart6: serial@2860000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02860000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -866,8 +866,6 @@ main_uart7: serial@2870000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02870000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -879,8 +877,6 @@ main_uart8: serial@2880000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02880000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -892,8 +888,6 @@ main_uart9: serial@2890000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x02890000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -1794,6 +1788,16 @@ reg-names = "iram", "control", "debug"; firmware-name = "j7-txpru0_1-fw"; }; + + icssg0_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x100>; + clocks = <&k3_clks 119 1>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; }; icssg1: icssg@b100000 { @@ -1925,5 +1929,15 @@ reg-names = "iram", "control", "debug"; firmware-name = "j7-txpru1_1-fw"; }; + + icssg1_mdio: mdio@32400 { + compatible = "ti,davinci_mdio"; + reg = <0x32400 0x100>; + clocks = <&k3_clks 120 4>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; }; }; 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 5e825e4d0306..d2dceda72fe9 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi @@ -73,8 +73,6 @@ wkup_uart0: serial@42300000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x42300000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <48000000>; current-speed = <115200>; @@ -86,8 +84,6 @@ mcu_uart0: serial@40a00000 { compatible = "ti,j721e-uart", "ti,am654-uart"; reg = <0x00 0x40a00000 0x00 0x100>; - reg-shift = <2>; - reg-io-width = <4>; interrupts = ; clock-frequency = <96000000>; current-speed = <115200>; diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts index bf0620afe117..29a4d9fc1e47 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts @@ -68,3 +68,11 @@ &gpio { status = "okay"; }; + +&pwm_mux { + groups = "pwm0_gpio16_grp", "pwm1_gpio17_grp", "pwm2_gpio18_grp", "pwm3_gpio19_grp"; +}; + +&pwm { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi index 17934fd9a14c..4b4231ff43cf 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi +++ b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi @@ -432,6 +432,15 @@ reg = <0 0x28330000 0 0x1000>; status = "disabled"; }; + + pwm: pwm@241c0000 { + compatible = "toshiba,visconti-pwm"; + reg = <0 0x241c0000 0 0x1000>; + pinctrl-names = "default"; + pinctrl-0 = <&pwm_mux>; + #pwm-cells = <2>; + status = "disabled"; + }; }; }; diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi index 34de00015a7f..a480c6ba5f5d 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi +++ b/arch/arm64/boot/dts/toshiba/tmpv7708_pins.dtsi @@ -90,4 +90,9 @@ groups = "i2c8_grp"; bias-pull-up; }; + + pwm_mux: pwm_mux { + function = "pwm"; + }; + }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 08c6f769df9a..f423d08b9a71 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -289,6 +289,7 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=m CONFIG_SCSI_UFS_HISI=y +CONFIG_SCSI_UFS_EXYNOS=y CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_SATA_AHCI_PLATFORM=y @@ -491,7 +492,6 @@ CONFIG_SPI_S3C64XX=y CONFIG_SPI_SH_MSIOF=m CONFIG_SPI_SUN6I=y CONFIG_SPI_SPIDEV=m -CONFIG_MTK_PMIC_WRAP=m CONFIG_SPMI=y CONFIG_PINCTRL_SINGLE=y CONFIG_PINCTRL_MAX77620=y @@ -530,6 +530,7 @@ CONFIG_GPIO_MXC=y CONFIG_GPIO_PL061=y CONFIG_GPIO_RCAR=y CONFIG_GPIO_UNIPHIER=y +CONFIG_GPIO_VISCONTI=y CONFIG_GPIO_WCD934X=m CONFIG_GPIO_XGENE=y CONFIG_GPIO_XGENE_SB=y @@ -662,6 +663,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m CONFIG_VIDEO_RENESAS_FDP1=m CONFIG_VIDEO_RENESAS_FCP=m CONFIG_VIDEO_RENESAS_VSP1=m +CONFIG_VIDEO_QCOM_VENUS=m CONFIG_SDR_PLATFORM_DRIVERS=y CONFIG_VIDEO_RCAR_DRIF=m CONFIG_VIDEO_IMX219=m @@ -701,6 +703,7 @@ CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_SITRONIX_ST7703=m CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_LONTIUM_LT8912B=m CONFIG_DRM_NWL_MIPI_DSI=m CONFIG_DRM_LONTIUM_LT9611=m CONFIG_DRM_PARADE_PS8640=m @@ -774,6 +777,8 @@ CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_ES7134=m CONFIG_SND_SOC_ES7241=m CONFIG_SND_SOC_GTM601=m +CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m +CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m CONFIG_SND_SOC_PCM3168A_I2C=m CONFIG_SND_SOC_RT5659=m CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m @@ -795,6 +800,8 @@ CONFIG_USB_CONN_GPIO=m CONFIG_USB=y CONFIG_USB_OTG=y CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=m +CONFIG_USB_XHCI_PCI_RENESAS=m CONFIG_USB_XHCI_TEGRA=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_EXYNOS=y @@ -866,6 +873,7 @@ CONFIG_MMC_DW_K3=y CONFIG_MMC_DW_ROCKCHIP=y CONFIG_MMC_SUNXI=y CONFIG_MMC_BCM2835=y +CONFIG_MMC_MTK=y CONFIG_MMC_SDHCI_XENON=y CONFIG_MMC_SDHCI_AM654=y CONFIG_MMC_OWL=y @@ -884,6 +892,7 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_EDAC=y CONFIG_EDAC_GHES=y +CONFIG_EDAC_LAYERSCAPE=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=m CONFIG_RTC_DRV_HYM8563=m @@ -987,6 +996,7 @@ CONFIG_SM_GPUCC_8250=y CONFIG_SM_DISPCC_8250=y CONFIG_QCOM_HFPLL=y CONFIG_CLK_GFM_LPASS_SM8250=m +CONFIG_CLK_RCAR_USB2_CLOCK_SEL=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_ARM_MHU=y @@ -1043,6 +1053,7 @@ CONFIG_ARCH_R8A77980=y CONFIG_ARCH_R8A77990=y CONFIG_ARCH_R8A77995=y CONFIG_ARCH_R8A779A0=y +CONFIG_ARCH_R9A07G044=y CONFIG_ROCKCHIP_PM_DOMAINS=y CONFIG_ARCH_TEGRA_132_SOC=y CONFIG_ARCH_TEGRA_210_SOC=y @@ -1059,6 +1070,7 @@ CONFIG_RENESAS_RPCIF=m CONFIG_IIO=y CONFIG_EXYNOS_ADC=y CONFIG_MAX9611=m +CONFIG_QCOM_SPMI_VADC=m CONFIG_QCOM_SPMI_ADC5=m CONFIG_ROCKCHIP_SARADC=m CONFIG_IIO_CROS_EC_SENSORS_CORE=m @@ -1083,6 +1095,7 @@ CONFIG_PWM_SAMSUNG=y CONFIG_PWM_SL28CPLD=m CONFIG_PWM_SUN4I=m CONFIG_PWM_TEGRA=m +CONFIG_PWM_VISCONTI=m CONFIG_SL28CPLD_INTC=y CONFIG_QCOM_PDC=y CONFIG_RESET_IMX7=y @@ -1110,6 +1123,7 @@ CONFIG_PHY_ROCKCHIP_INNO_USB2=y CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=m CONFIG_PHY_ROCKCHIP_PCIE=m CONFIG_PHY_ROCKCHIP_TYPEC=y +CONFIG_PHY_SAMSUNG_UFS=y CONFIG_PHY_UNIPHIER_USB2=y CONFIG_PHY_UNIPHIER_USB3=y CONFIG_PHY_TEGRA_XUSB=y @@ -1148,6 +1162,7 @@ CONFIG_INTERCONNECT_QCOM_OSM_L3=m CONFIG_INTERCONNECT_QCOM_SDM845=y CONFIG_INTERCONNECT_QCOM_SM8150=m CONFIG_INTERCONNECT_QCOM_SM8250=m +CONFIG_INTERCONNECT_QCOM_SM8350=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_POSIX_ACL=y diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 26889dbfe904..64202010b700 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -3,7 +3,6 @@ generic-y += early_ioremap.h generic-y += mcs_spinlock.h generic-y += qrwlock.h generic-y += qspinlock.h -generic-y += set_memory.h generic-y += user.h generated-y += cpucaps.h diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 543c997eb3b7..5a228e203ef9 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -144,12 +144,6 @@ static __always_inline void icache_inval_all_pou(void) dsb(ish); } -int set_memory_valid(unsigned long addr, int numpages, int enable); - -int set_direct_map_invalid_noflush(struct page *page); -int set_direct_map_default_noflush(struct page *page); -bool kernel_page_present(struct page *page); - #include #endif /* __ASM_CACHEFLUSH_H */ diff --git a/arch/arm64/include/asm/kfence.h b/arch/arm64/include/asm/kfence.h index d061176d57ea..aa855c6a0ae6 100644 --- a/arch/arm64/include/asm/kfence.h +++ b/arch/arm64/include/asm/kfence.h @@ -8,7 +8,7 @@ #ifndef __ASM_KFENCE_H #define __ASM_KFENCE_H -#include +#include static inline bool arch_kfence_init_pool(void) { return true; } diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 508c7ffad515..f09bf5c02891 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -649,9 +649,9 @@ static inline phys_addr_t pud_page_paddr(pud_t pud) return __pud_to_phys(pud); } -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { - return (unsigned long)__va(pud_page_paddr(pud)); + return (pmd_t *)__va(pud_page_paddr(pud)); } /* Find an entry in the second-level page table. */ @@ -710,9 +710,9 @@ static inline phys_addr_t p4d_page_paddr(p4d_t p4d) return __p4d_to_phys(p4d); } -static inline unsigned long p4d_page_vaddr(p4d_t p4d) +static inline pud_t *p4d_pgtable(p4d_t p4d) { - return (unsigned long)__va(p4d_page_paddr(p4d)); + return (pud_t *)__va(p4d_page_paddr(p4d)); } /* Find an entry in the frst-level page table. */ diff --git a/arch/arm64/include/asm/set_memory.h b/arch/arm64/include/asm/set_memory.h new file mode 100644 index 000000000000..0f740b781187 --- /dev/null +++ b/arch/arm64/include/asm/set_memory.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_ARM64_SET_MEMORY_H +#define _ASM_ARM64_SET_MEMORY_H + +#include + +bool can_set_direct_map(void); +#define can_set_direct_map can_set_direct_map + +int set_memory_valid(unsigned long addr, int numpages, int enable); + +int set_direct_map_invalid_noflush(struct page *page); +int set_direct_map_default_noflush(struct page *page); +bool kernel_page_present(struct page *page); + +#endif /* _ASM_ARM64_SET_MEMORY_H */ diff --git a/arch/arm64/include/uapi/asm/unistd.h b/arch/arm64/include/uapi/asm/unistd.h index f83a70e07df8..ce2ee8f1e361 100644 --- a/arch/arm64/include/uapi/asm/unistd.h +++ b/arch/arm64/include/uapi/asm/unistd.h @@ -20,5 +20,6 @@ #define __ARCH_WANT_SET_GET_RLIMIT #define __ARCH_WANT_TIME32_SYSCALLS #define __ARCH_WANT_SYS_CLONE3 +#define __ARCH_WANT_MEMFD_SECRET #include diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 03ceabe4d912..213d56c14f60 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 880f40bae60e..be5f85b0a24d 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -293,10 +293,7 @@ u64 cpu_logical_map(unsigned int cpu) void __init __no_sanitize_address setup_arch(char **cmdline_p) { - init_mm.start_code = (unsigned long) _stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_stext, _etext, _edata, _end); *cmdline_p = boot_command_line; diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index cca6e4abc0ee..9aa3dc91af92 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -153,7 +153,7 @@ NOKPROBE_SYMBOL(walk_stackframe); static void dump_backtrace_entry(unsigned long where, const char *loglvl) { - printk("%s %pS\n", loglvl, (void *)where); + printk("%s %pSb\n", loglvl, (void *)where); } void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 595fde9a47dd..d74586508448 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -515,8 +516,7 @@ static void __init map_mem(pgd_t *pgdp) */ BUILD_BUG_ON(pgd_index(direct_map_end - 1) == pgd_index(direct_map_end)); - if (rodata_full || crash_mem_map || debug_pagealloc_enabled() || - IS_ENABLED(CONFIG_KFENCE)) + if (can_set_direct_map() || crash_mem_map || IS_ENABLED(CONFIG_KFENCE)) flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; /* @@ -1489,8 +1489,7 @@ int arch_add_memory(int nid, u64 start, u64 size, * KFENCE requires linear map to be mapped at page granularity, so that * it is possible to protect/unprotect single pages in the KFENCE pool. */ - if (rodata_full || debug_pagealloc_enabled() || - IS_ENABLED(CONFIG_KFENCE)) + if (can_set_direct_map() || IS_ENABLED(CONFIG_KFENCE)) flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 92eccaf595c8..a3bacd79507a 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -19,6 +19,11 @@ struct page_change_data { bool rodata_full __ro_after_init = IS_ENABLED(CONFIG_RODATA_FULL_DEFAULT_ENABLED); +bool can_set_direct_map(void) +{ + return rodata_full || debug_pagealloc_enabled(); +} + static int change_page_range(pte_t *ptep, unsigned long addr, void *data) { struct page_change_data *cdata = data; @@ -155,7 +160,7 @@ int set_direct_map_invalid_noflush(struct page *page) .clear_mask = __pgprot(PTE_VALID), }; - if (!debug_pagealloc_enabled() && !rodata_full) + if (!can_set_direct_map()) return 0; return apply_to_page_range(&init_mm, @@ -170,7 +175,7 @@ int set_direct_map_default_noflush(struct page *page) .clear_mask = __pgprot(PTE_RDONLY), }; - if (!debug_pagealloc_enabled() && !rodata_full) + if (!can_set_direct_map()) return 0; return apply_to_page_range(&init_mm, @@ -181,7 +186,7 @@ int set_direct_map_default_noflush(struct page *page) #ifdef CONFIG_DEBUG_PAGEALLOC void __kernel_map_pages(struct page *page, int numpages, int enable) { - if (!debug_pagealloc_enabled() && !rodata_full) + if (!can_set_direct_map()) return; set_memory_valid((unsigned long)page_address(page), numpages, enable); @@ -206,7 +211,7 @@ bool kernel_page_present(struct page *page) pte_t *ptep; unsigned long addr = (unsigned long)page_address(page); - if (!debug_pagealloc_enabled() && !rodata_full) + if (!can_set_direct_map()) return true; pgdp = pgd_offset_k(addr); diff --git a/arch/csky/Kbuild b/arch/csky/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/csky/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/csky/kernel/setup.c b/arch/csky/kernel/setup.c index e93bc6f74432..c64e7be2045b 100644 --- a/arch/csky/kernel/setup.c +++ b/arch/csky/kernel/setup.c @@ -78,10 +78,7 @@ void __init setup_arch(char **cmdline_p) pr_info("Phys. mem: %ldMB\n", (unsigned long) memblock_phys_mem_size()/1024/1024); - init_mm.start_code = (unsigned long) _stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_stext, _etext, _edata, _end); parse_early_param(); diff --git a/arch/h8300/Kbuild b/arch/h8300/Kbuild new file mode 100644 index 000000000000..b2583e7efbd1 --- /dev/null +++ b/arch/h8300/Kbuild @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += kernel/ mm/ boot/dts/ diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile index ba0f26cfad61..eb4cb8f6830c 100644 --- a/arch/h8300/Makefile +++ b/arch/h8300/Makefile @@ -30,9 +30,6 @@ ifeq ($(CROSS_COMPILE),) CROSS_COMPILE := $(call cc-cross-prefix, h8300-unknown-linux- h8300-linux-) endif -core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ -core-y += arch/$(ARCH)/boot/dts/ - libs-y += arch/$(ARCH)/lib/ boot := arch/h8300/boot diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c index c3590b2e9592..61091a76eb7e 100644 --- a/arch/h8300/kernel/setup.c +++ b/arch/h8300/kernel/setup.c @@ -95,10 +95,7 @@ void __init setup_arch(char **cmdline_p) { unflatten_and_copy_device_tree(); - init_mm.start_code = (unsigned long) _stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) 0; + setup_initial_init_mm(_stext, _etext, _edata, NULL); pr_notice("\r\n\nuClinux " CPU "\n"); pr_notice("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n"); diff --git a/arch/hexagon/Kbuild b/arch/hexagon/Kbuild new file mode 100644 index 000000000000..8421baba1351 --- /dev/null +++ b/arch/hexagon/Kbuild @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += kernel/ mm/ lib/ diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index 44a409967af1..e5a852080730 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig @@ -30,6 +30,7 @@ config HEXAGON select MODULES_USE_ELF_RELA select GENERIC_CPU_DEVICES select SET_FS + select ARCH_WANT_LD_ORPHAN_WARN help Qualcomm Hexagon is a processor architecture designed for high performance and low power across a wide variety of applications. diff --git a/arch/hexagon/Makefile b/arch/hexagon/Makefile index 74b644ea8a00..44312bc147d8 100644 --- a/arch/hexagon/Makefile +++ b/arch/hexagon/Makefile @@ -34,7 +34,3 @@ KBUILD_CFLAGS += -ffixed-$(TIR_NAME) -DTHREADINFO_REG=$(TIR_NAME) -D__linux__ KBUILD_AFLAGS += -DTHREADINFO_REG=$(TIR_NAME) head-y := arch/hexagon/kernel/head.o - -core-y += arch/hexagon/kernel/ \ - arch/hexagon/mm/ \ - arch/hexagon/lib/ diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S index 35b18e55eae8..57465bff1fe4 100644 --- a/arch/hexagon/kernel/vmlinux.lds.S +++ b/arch/hexagon/kernel/vmlinux.lds.S @@ -38,6 +38,8 @@ SECTIONS .text : AT(ADDR(.text)) { _text = .; TEXT_TEXT + IRQENTRY_TEXT + SOFTIRQENTRY_TEXT SCHED_TEXT CPUIDLE_TEXT LOCK_TEXT @@ -59,14 +61,9 @@ SECTIONS _end = .; - /DISCARD/ : { - EXIT_TEXT - EXIT_DATA - EXIT_CALL - } - STABS_DEBUG DWARF_DEBUG ELF_DETAILS + DISCARDS } diff --git a/arch/ia64/Kbuild b/arch/ia64/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/ia64/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h index 3f5dbbd8b9d8..9584b2c5f394 100644 --- a/arch/ia64/include/asm/pgtable.h +++ b/arch/ia64/include/asm/pgtable.h @@ -273,7 +273,7 @@ ia64_phys_addr_valid (unsigned long addr) #define pud_bad(pud) (!ia64_phys_addr_valid(pud_val(pud))) #define pud_present(pud) (pud_val(pud) != 0UL) #define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) -#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK)) +#define pud_pgtable(pud) ((pmd_t *) __va(pud_val(pud) & _PFN_MASK)) #define pud_page(pud) virt_to_page((pud_val(pud) + PAGE_OFFSET)) #if CONFIG_PGTABLE_LEVELS == 4 @@ -281,7 +281,7 @@ ia64_phys_addr_valid (unsigned long addr) #define p4d_bad(p4d) (!ia64_phys_addr_valid(p4d_val(p4d))) #define p4d_present(p4d) (p4d_val(p4d) != 0UL) #define p4d_clear(p4dp) (p4d_val(*(p4dp)) = 0UL) -#define p4d_page_vaddr(p4d) ((unsigned long) __va(p4d_val(p4d) & _PFN_MASK)) +#define p4d_pgtable(p4d) ((pud_t *) __va(p4d_val(p4d) & _PFN_MASK)) #define p4d_page(p4d) virt_to_page((p4d_val(p4d) + PAGE_OFFSET)) #endif diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index c54055a3d284..dd0c0ec67f67 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -97,7 +97,6 @@ head-$(CONFIG_SUN3) := arch/m68k/kernel/sun3-head.o head-$(CONFIG_M68000) := arch/m68k/68000/head.o head-$(CONFIG_COLDFIRE) := arch/m68k/coldfire/head.o -core-y += arch/m68k/ libs-y += arch/m68k/lib/ diff --git a/arch/m68k/include/asm/motorola_pgtable.h b/arch/m68k/include/asm/motorola_pgtable.h index a2908164ee6f..022c3abc280d 100644 --- a/arch/m68k/include/asm/motorola_pgtable.h +++ b/arch/m68k/include/asm/motorola_pgtable.h @@ -131,7 +131,7 @@ static inline void pud_set(pud_t *pudp, pmd_t *pmdp) #define __pte_page(pte) ((unsigned long)__va(pte_val(pte) & PAGE_MASK)) #define pmd_page_vaddr(pmd) ((unsigned long)__va(pmd_val(pmd) & _TABLE_MASK)) -#define pud_page_vaddr(pud) ((unsigned long)__va(pud_val(pud) & _TABLE_MASK)) +#define pud_pgtable(pud) ((pmd_t *)__va(pud_val(pud) & _TABLE_MASK)) #define pte_none(pte) (!pte_val(pte)) diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c index 017bac3aab80..4b51bfd38e5f 100644 --- a/arch/m68k/kernel/setup_mm.c +++ b/arch/m68k/kernel/setup_mm.c @@ -258,10 +258,7 @@ void __init setup_arch(char **cmdline_p) } } - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long)_etext; - init_mm.end_data = (unsigned long)_edata; - init_mm.brk = (unsigned long)_end; + setup_initial_init_mm((void *)PAGE_OFFSET, _etext, _edata, _end); #if defined(CONFIG_BOOTPARAM) strncpy(m68k_command_line, CONFIG_BOOTPARAM_STRING, CL_SIZE); diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index d1b7988efc91..5e4104f07a44 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -87,10 +87,7 @@ void __init setup_arch(char **cmdline_p) memory_start = PAGE_ALIGN(_ramstart); memory_end = _ramend; - init_mm.start_code = (unsigned long) &_stext; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) 0; + setup_initial_init_mm(_stext, _etext, _edata, NULL); config_BSP(&command_line[0], sizeof(command_line)); diff --git a/arch/microblaze/Kbuild b/arch/microblaze/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/microblaze/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 258234c35a09..4e942b7ef022 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -332,9 +332,6 @@ head-y := arch/mips/kernel/head.o libs-y += arch/mips/lib/ libs-$(CONFIG_MIPS_FP_SUPPORT) += arch/mips/math-emu/ -# See arch/mips/Kbuild for content of core part of the kernel -core-y += arch/mips/ - drivers-y += arch/mips/crypto/ # suspend and hibernation support diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index e4b7839293e1..3548b3b45269 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -40,7 +40,7 @@ GCOV_PROFILE := n UBSAN_SANITIZE := n # decompressor objects (linked with vmlinuz) -vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o +vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/bswapsi.o ifdef CONFIG_DEBUG_ZBOOT vmlinuzobjs-$(CONFIG_DEBUG_ZBOOT) += $(obj)/dbg.o @@ -54,7 +54,7 @@ extra-y += uart-ath79.c $(obj)/uart-ath79.c: $(srctree)/arch/mips/ath79/early_printk.c $(call cmd,shipped) -vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o $(obj)/bswapsi.o +vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o extra-y += ashldi3.c $(obj)/ashldi3.c: $(obj)/%.c: $(srctree)/lib/%.c FORCE diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c index 3d70d15ada28..aae1346a509a 100644 --- a/arch/mips/boot/compressed/decompress.c +++ b/arch/mips/boot/compressed/decompress.c @@ -7,6 +7,8 @@ * Author: Wu Zhangjin */ +#define DISABLE_BRANCH_PROFILING + #include #include #include diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index d1477ecb1af9..57561e0e6e8d 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -57,6 +57,9 @@ asmlinkage void plat_irq_dispatch(void); extern void do_IRQ(unsigned int irq); +struct irq_domain; +extern void do_domain_IRQ(struct irq_domain *domain, unsigned int irq); + extern void arch_init_irq(void); extern void spurious_interrupt(void); diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index 046465906c82..41921acdc9d8 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -209,9 +209,9 @@ static inline void p4d_clear(p4d_t *p4dp) p4d_val(*p4dp) = (unsigned long)invalid_pud_table; } -static inline unsigned long p4d_page_vaddr(p4d_t p4d) +static inline pud_t *p4d_pgtable(p4d_t p4d) { - return p4d_val(p4d); + return (pud_t *)p4d_val(p4d); } #define p4d_phys(p4d) virt_to_phys((void *)p4d_val(p4d)) @@ -313,9 +313,9 @@ static inline void pud_clear(pud_t *pudp) #endif #ifndef __PAGETABLE_PMD_FOLDED -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { - return pud_val(pud); + return (pmd_t *)pud_val(pud); } #define pud_phys(pud) virt_to_phys((void *)pud_val(pud)) #define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT)) diff --git a/arch/mips/include/asm/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h index 737ddfc3411c..a327ca21270e 100644 --- a/arch/mips/include/asm/vdso/vdso.h +++ b/arch/mips/include/asm/vdso/vdso.h @@ -67,7 +67,7 @@ static inline const struct vdso_data *get_vdso_data(void) static inline void __iomem *get_gic(const struct vdso_data *data) { - return (void __iomem *)data - PAGE_SIZE; + return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE; } #endif /* CONFIG_CLKSRC_MIPS_GIC */ diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 85b6c60f285d..d20e002b3246 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -107,3 +108,18 @@ void __irq_entry do_IRQ(unsigned int irq) irq_exit(); } +#ifdef CONFIG_IRQ_DOMAIN +void __irq_entry do_domain_IRQ(struct irq_domain *domain, unsigned int hwirq) +{ + struct irq_desc *desc; + + irq_enter(); + check_stack_overflow(); + + desc = irq_resolve_mapping(domain, hwirq); + if (likely(desc)) + handle_irq_desc(desc); + + irq_exit(); +} +#endif diff --git a/arch/nds32/Kbuild b/arch/nds32/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/nds32/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/nds32/boot/.gitignore b/arch/nds32/boot/.gitignore new file mode 100644 index 000000000000..9182a3a1ea0a --- /dev/null +++ b/arch/nds32/boot/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +/Image diff --git a/arch/nds32/kernel/setup.c b/arch/nds32/kernel/setup.c index af82e996f412..41725eaf8bac 100644 --- a/arch/nds32/kernel/setup.c +++ b/arch/nds32/kernel/setup.c @@ -294,10 +294,7 @@ void __init setup_arch(char **cmdline_p) setup_cpuinfo(); - init_mm.start_code = (unsigned long)&_stext; - init_mm.end_code = (unsigned long)&_etext; - init_mm.end_data = (unsigned long)&_edata; - init_mm.brk = (unsigned long)&_end; + setup_initial_init_mm(_stext, _etext, _edata, _end); /* setup bootmem allocator */ setup_memory(); diff --git a/arch/nios2/Kbuild b/arch/nios2/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/nios2/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/nios2/kernel/setup.c b/arch/nios2/kernel/setup.c index d2f21957e99c..cf8d687a2644 100644 --- a/arch/nios2/kernel/setup.c +++ b/arch/nios2/kernel/setup.c @@ -156,10 +156,7 @@ void __init setup_arch(char **cmdline_p) memory_start = memblock_start_of_DRAM(); memory_end = memblock_end_of_DRAM(); - init_mm.start_code = (unsigned long) _stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_stext, _etext, _edata, _end); init_task.thread.kregs = &fake_regs; /* Keep a copy of command line */ diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile index 410e7abfac69..c52de526e518 100644 --- a/arch/openrisc/Makefile +++ b/arch/openrisc/Makefile @@ -42,7 +42,6 @@ endif head-y := arch/openrisc/kernel/head.o -core-y += arch/openrisc/ libs-y += $(LIBGCC) PHONY += vmlinux.bin diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c index c6f9e7b9f7cb..8ae2da6ac097 100644 --- a/arch/openrisc/kernel/setup.c +++ b/arch/openrisc/kernel/setup.c @@ -293,10 +293,7 @@ void __init setup_arch(char **cmdline_p) #endif /* process 1's initial memory region is the kernel code/data */ - init_mm.start_code = (unsigned long)_stext; - init_mm.end_code = (unsigned long)_etext; - init_mm.end_data = (unsigned long)_edata; - init_mm.brk = (unsigned long)_end; + setup_initial_init_mm(_stext, _etext, _edata, _end); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start == initrd_end) { diff --git a/arch/parisc/Kbuild b/arch/parisc/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/parisc/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 7f33c29764cc..43937af127b1 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -322,8 +322,8 @@ static inline void pmd_clear(pmd_t *pmd) { #if CONFIG_PGTABLE_LEVELS == 3 -#define pud_page_vaddr(pud) ((unsigned long) __va(pud_address(pud))) -#define pud_page(pud) virt_to_page((void *)pud_page_vaddr(pud)) +#define pud_pgtable(pud) ((pmd_t *) __va(pud_address(pud))) +#define pud_page(pud) virt_to_page((void *)pud_pgtable(pud)) /* For 64 bit we have three level tables */ diff --git a/arch/parisc/kernel/syscalls/Makefile b/arch/parisc/kernel/syscalls/Makefile index 0f2ea5bcb0d7..d63f18dd058d 100644 --- a/arch/parisc/kernel/syscalls/Makefile +++ b/arch/parisc/kernel/syscalls/Makefile @@ -10,25 +10,15 @@ syshdr := $(srctree)/scripts/syscallhdr.sh systbl := $(srctree)/scripts/syscalltbl.sh quiet_cmd_syshdr = SYSHDR $@ - cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr --abis $(abis) $< $@ + cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr --abis common,$* $< $@ quiet_cmd_systbl = SYSTBL $@ - cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis $(abis) $< $@ + cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis common,$* $< $@ -$(uapi)/unistd_32.h: abis := common,32 -$(uapi)/unistd_32.h: $(syscall) $(syshdr) FORCE +$(uapi)/unistd_%.h: $(syscall) $(syshdr) FORCE $(call if_changed,syshdr) -$(uapi)/unistd_64.h: abis := common,64 -$(uapi)/unistd_64.h: $(syscall) $(syshdr) FORCE - $(call if_changed,syshdr) - -$(kapi)/syscall_table_32.h: abis := common,32 -$(kapi)/syscall_table_32.h: $(syscall) $(systbl) FORCE - $(call if_changed,systbl) - -$(kapi)/syscall_table_64.h: abis := common,64 -$(kapi)/syscall_table_64.h: $(syscall) $(systbl) FORCE +$(kapi)/syscall_table_%.h: $(syscall) $(systbl) FORCE $(call if_changed,systbl) uapisyshdr-y += unistd_32.h unistd_64.h diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 712c5e8768ce..6505d66f1193 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -267,9 +267,6 @@ head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o head-$(CONFIG_ALTIVEC) += arch/powerpc/kernel/vector.o head-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += arch/powerpc/kernel/prom_init.o -# See arch/powerpc/Kbuild for content of core part of the kernel -core-y += arch/powerpc/ - # Default to zImage, override when needed all: zImage diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 4d9941b2fe51..5d34a8646f08 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1051,8 +1051,15 @@ extern struct page *p4d_page(p4d_t p4d); /* Pointers in the page table tree are physical addresses */ #define __pgtable_ptr_val(ptr) __pa(ptr) -#define pud_page_vaddr(pud) __va(pud_val(pud) & ~PUD_MASKED_BITS) -#define p4d_page_vaddr(p4d) __va(p4d_val(p4d) & ~P4D_MASKED_BITS) +static inline pud_t *p4d_pgtable(p4d_t p4d) +{ + return (pud_t *)__va(p4d_val(p4d) & ~P4D_MASKED_BITS); +} + +static inline pmd_t *pud_pgtable(pud_t pud) +{ + return (pmd_t *)__va(pud_val(pud) & ~PUD_MASKED_BITS); +} #define pte_ERROR(e) \ pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h index a46fd37ad552..77797a2a82eb 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h @@ -64,6 +64,8 @@ extern void radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, unsigned long end, int psize); +void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, + unsigned long end, int psize); extern void radix__flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start, diff --git a/arch/powerpc/include/asm/nohash/64/pgtable-4k.h b/arch/powerpc/include/asm/nohash/64/pgtable-4k.h index fe2f4c9acd9e..10f5cf444d72 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable-4k.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable-4k.h @@ -56,10 +56,14 @@ #define p4d_none(p4d) (!p4d_val(p4d)) #define p4d_bad(p4d) (p4d_val(p4d) == 0) #define p4d_present(p4d) (p4d_val(p4d) != 0) -#define p4d_page_vaddr(p4d) (p4d_val(p4d) & ~P4D_MASKED_BITS) #ifndef __ASSEMBLY__ +static inline pud_t *p4d_pgtable(p4d_t p4d) +{ + return (pud_t *) (p4d_val(p4d) & ~P4D_MASKED_BITS); +} + static inline void p4d_clear(p4d_t *p4dp) { *p4dp = __p4d(0); diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index 53fbfdfac93d..d081704b13fb 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -162,7 +162,11 @@ static inline void pud_clear(pud_t *pudp) #define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \ || (pud_val(pud) & PUD_BAD_BITS)) #define pud_present(pud) (pud_val(pud) != 0) -#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS) + +static inline pmd_t *pud_pgtable(pud_t pud) +{ + return (pmd_t *)(pud_val(pud) & ~PUD_MASKED_BITS); +} extern struct page *pud_page(pud_t pud); diff --git a/arch/powerpc/include/asm/tlb.h b/arch/powerpc/include/asm/tlb.h index 160422a439aa..09a9ae5f3656 100644 --- a/arch/powerpc/include/asm/tlb.h +++ b/arch/powerpc/include/asm/tlb.h @@ -83,5 +83,11 @@ static inline int mm_is_thread_local(struct mm_struct *mm) } #endif +#define arch_supports_page_table_move arch_supports_page_table_move +static inline bool arch_supports_page_table_move(void) +{ + return radix_enabled(); +} + #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_TLB_H */ diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S index 4063e8a3f704..d4212d2ff0b5 100644 --- a/arch/powerpc/kernel/interrupt_64.S +++ b/arch/powerpc/kernel/interrupt_64.S @@ -311,9 +311,13 @@ END_BTB_FLUSH_SECTION * trace_hardirqs_off(). */ li r11,IRQS_ALL_DISABLED - li r12,-1 /* Set MSR_EE and MSR_RI */ stb r11,PACAIRQSOFTMASK(r13) +#ifdef CONFIG_PPC_BOOK3S + li r12,-1 /* Set MSR_EE and MSR_RI */ mtmsrd r12,1 +#else + wrteei 1 +#endif /* Calling convention has r9 = orig r0, r10 = regs */ mr r9,r0 diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 26328fd2990c..aa9c2d01424a 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -926,10 +926,7 @@ void __init setup_arch(char **cmdline_p) klp_init_thread_info(&init_task); - init_mm.start_code = (unsigned long)_stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long)_end; + setup_initial_init_mm(_stext, _etext, _edata, _end); mm_iommu_init(&init_mm); irqstack_early_init(); diff --git a/arch/powerpc/mm/book3s64/radix_hugetlbpage.c b/arch/powerpc/mm/book3s64/radix_hugetlbpage.c index cb91071eef52..23d3e08911d3 100644 --- a/arch/powerpc/mm/book3s64/radix_hugetlbpage.c +++ b/arch/powerpc/mm/book3s64/radix_hugetlbpage.c @@ -32,7 +32,13 @@ void radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long st struct hstate *hstate = hstate_file(vma->vm_file); psize = hstate_get_psize(hstate); - radix__flush_tlb_range_psize(vma->vm_mm, start, end, psize); + /* + * Flush PWC even if we get PUD_SIZE hugetlb invalidate to keep this simpler. + */ + if (end - start >= PUD_SIZE) + radix__flush_tlb_pwc_range_psize(vma->vm_mm, start, end, psize); + else + radix__flush_tlb_range_psize(vma->vm_mm, start, end, psize); } /* diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index 2176a5f70746..e50ddf129c15 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -820,7 +820,7 @@ static void __meminit remove_pud_table(pud_t *pud_start, unsigned long addr, continue; } - pmd_base = (pmd_t *)pud_page_vaddr(*pud); + pmd_base = pud_pgtable(*pud); remove_pmd_table(pmd_base, addr, next); free_pmd_table(pmd_base, pud); } @@ -854,7 +854,7 @@ static void __meminit remove_pagetable(unsigned long start, unsigned long end) continue; } - pud_base = (pud_t *)p4d_page_vaddr(*p4d); + pud_base = p4d_pgtable(*p4d); remove_pud_table(pud_base, addr, next); free_pud_table(pud_base, p4d); } @@ -1105,7 +1105,7 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) pmd_t *pmd; int i; - pmd = (pmd_t *)pud_page_vaddr(*pud); + pmd = pud_pgtable(*pud); pud_clear(pud); flush_tlb_kernel_range(addr, addr + PUD_SIZE); diff --git a/arch/powerpc/mm/book3s64/radix_tlb.c b/arch/powerpc/mm/book3s64/radix_tlb.c index ae12fb5559cb..aefc100d79a7 100644 --- a/arch/powerpc/mm/book3s64/radix_tlb.c +++ b/arch/powerpc/mm/book3s64/radix_tlb.c @@ -1111,14 +1111,13 @@ static unsigned long tlb_local_single_page_flush_ceiling __read_mostly = POWER9_ static inline void __radix__flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) - { unsigned long pid; unsigned int page_shift = mmu_psize_defs[mmu_virtual_psize].shift; unsigned long page_size = 1UL << page_shift; unsigned long nr_pages = (end - start) >> page_shift; bool fullmm = (end == TLB_FLUSH_ALL); - bool flush_pid; + bool flush_pid, flush_pwc = false; enum tlb_flush_type type; pid = mm->context.id; @@ -1137,8 +1136,16 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm, flush_pid = nr_pages > tlb_single_page_flush_ceiling; else flush_pid = nr_pages > tlb_local_single_page_flush_ceiling; + /* + * full pid flush already does the PWC flush. if it is not full pid + * flush check the range is more than PMD and force a pwc flush + * mremap() depends on this behaviour. + */ + if (!flush_pid && (end - start) >= PMD_SIZE) + flush_pwc = true; if (!mmu_has_feature(MMU_FTR_GTSE) && type == FLUSH_TYPE_GLOBAL) { + unsigned long type = H_RPTI_TYPE_TLB; unsigned long tgt = H_RPTI_TARGET_CMMU; unsigned long pg_sizes = psize_to_rpti_pgsize(mmu_virtual_psize); @@ -1146,19 +1153,20 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm, pg_sizes |= psize_to_rpti_pgsize(MMU_PAGE_2M); if (atomic_read(&mm->context.copros) > 0) tgt |= H_RPTI_TARGET_NMMU; - pseries_rpt_invalidate(pid, tgt, H_RPTI_TYPE_TLB, pg_sizes, - start, end); + if (flush_pwc) + type |= H_RPTI_TYPE_PWC; + pseries_rpt_invalidate(pid, tgt, type, pg_sizes, start, end); } else if (flush_pid) { + /* + * We are now flushing a range larger than PMD size force a RIC_FLUSH_ALL + */ if (type == FLUSH_TYPE_LOCAL) { - _tlbiel_pid(pid, RIC_FLUSH_TLB); + _tlbiel_pid(pid, RIC_FLUSH_ALL); } else { if (cputlb_use_tlbie()) { - if (mm_needs_flush_escalation(mm)) - _tlbie_pid(pid, RIC_FLUSH_ALL); - else - _tlbie_pid(pid, RIC_FLUSH_TLB); + _tlbie_pid(pid, RIC_FLUSH_ALL); } else { - _tlbiel_pid_multicast(mm, pid, RIC_FLUSH_TLB); + _tlbiel_pid_multicast(mm, pid, RIC_FLUSH_ALL); } } } else { @@ -1174,6 +1182,9 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm, if (type == FLUSH_TYPE_LOCAL) { asm volatile("ptesync": : :"memory"); + if (flush_pwc) + /* For PWC, only one flush is needed */ + __tlbiel_pid(pid, 0, RIC_FLUSH_PWC); __tlbiel_va_range(start, end, pid, page_size, mmu_virtual_psize); if (hflush) __tlbiel_va_range(hstart, hend, pid, @@ -1181,6 +1192,8 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm, ppc_after_tlbiel_barrier(); } else if (cputlb_use_tlbie()) { asm volatile("ptesync": : :"memory"); + if (flush_pwc) + __tlbie_pid(pid, RIC_FLUSH_PWC); __tlbie_va_range(start, end, pid, page_size, mmu_virtual_psize); if (hflush) __tlbie_va_range(hstart, hend, pid, @@ -1188,10 +1201,10 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm, asm volatile("eieio; tlbsync; ptesync": : :"memory"); } else { _tlbiel_va_range_multicast(mm, - start, end, pid, page_size, mmu_virtual_psize, false); + start, end, pid, page_size, mmu_virtual_psize, flush_pwc); if (hflush) _tlbiel_va_range_multicast(mm, - hstart, hend, pid, PMD_SIZE, MMU_PAGE_2M, false); + hstart, hend, pid, PMD_SIZE, MMU_PAGE_2M, flush_pwc); } } out: @@ -1265,9 +1278,6 @@ void radix__flush_all_lpid_guest(unsigned int lpid) _tlbie_lpid_guest(lpid, RIC_FLUSH_ALL); } -static void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, - unsigned long end, int psize); - void radix__tlb_flush(struct mmu_gather *tlb) { int psize = 0; @@ -1374,8 +1384,8 @@ void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, return __radix__flush_tlb_range_psize(mm, start, end, psize, false); } -static void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, - unsigned long end, int psize) +void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, + unsigned long end, int psize) { __radix__flush_tlb_range_psize(mm, start, end, psize, true); } diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 34f641d4a2fe..a8d0ce85d39a 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -199,9 +199,7 @@ static bool bad_kernel_fault(struct pt_regs *regs, unsigned long error_code, { int is_exec = TRAP(regs) == INTERRUPT_INST_STORAGE; - /* NX faults set DSISR_PROTFAULT on the 8xx, DSISR_NOEXEC_OR_G on others */ - if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT | - DSISR_PROTFAULT))) { + if (is_exec) { pr_crit_ratelimited("kernel tried to execute %s page (%lx) - exploit attempt? (uid: %d)\n", address >= TASK_SIZE ? "exec-protected" : "user", address, diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index cc6e2f94517f..78c8cf01db5f 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -105,7 +105,7 @@ struct page *p4d_page(p4d_t p4d) VM_WARN_ON(!p4d_huge(p4d)); return pte_page(p4d_pte(p4d)); } - return virt_to_page(p4d_page_vaddr(p4d)); + return virt_to_page(p4d_pgtable(p4d)); } #endif @@ -115,7 +115,7 @@ struct page *pud_page(pud_t pud) VM_WARN_ON(!pud_huge(pud)); return pte_page(pud_pte(pud)); } - return virt_to_page(pud_page_vaddr(pud)); + return virt_to_page(pud_pgtable(pud)); } /* diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c index cbe5b399ed86..34bb1583fc0c 100644 --- a/arch/powerpc/net/bpf_jit_comp32.c +++ b/arch/powerpc/net/bpf_jit_comp32.c @@ -773,9 +773,17 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * break; /* - * BPF_STX XADD (atomic_add) + * BPF_STX ATOMIC (atomic ops) */ - case BPF_STX | BPF_XADD | BPF_W: /* *(u32 *)(dst + off) += src */ + case BPF_STX | BPF_ATOMIC | BPF_W: + if (imm != BPF_ADD) { + pr_err_ratelimited("eBPF filter atomic op code %02x (@%d) unsupported\n", + code, i); + return -ENOTSUPP; + } + + /* *(u32 *)(dst + off) += src */ + bpf_set_seen_register(ctx, tmp_reg); /* Get offset into TMP_REG */ EMIT(PPC_RAW_LI(tmp_reg, off)); @@ -789,7 +797,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * PPC_BCC_SHORT(COND_NE, (ctx->idx - 3) * 4); break; - case BPF_STX | BPF_XADD | BPF_DW: /* *(u64 *)(dst + off) += src */ + case BPF_STX | BPF_ATOMIC | BPF_DW: /* *(u64 *)(dst + off) += src */ return -EOPNOTSUPP; /* diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 5cad5b5a7e97..de8595880fee 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -667,7 +667,7 @@ emit_clear: * BPF_STX ATOMIC (atomic ops) */ case BPF_STX | BPF_ATOMIC | BPF_W: - if (insn->imm != BPF_ADD) { + if (imm != BPF_ADD) { pr_err_ratelimited( "eBPF filter atomic op code %02x (@%d) unsupported\n", code, i); @@ -689,7 +689,7 @@ emit_clear: PPC_BCC_SHORT(COND_NE, tmp_idx); break; case BPF_STX | BPF_ATOMIC | BPF_DW: - if (insn->imm != BPF_ADD) { + if (imm != BPF_ADD) { pr_err_ratelimited( "eBPF filter atomic op code %02x (@%d) unsupported\n", code, i); diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 0e1bb1cedd13..6794145603de 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -102,6 +102,8 @@ config PPC_BOOK3S_64 select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_SUPPORTS_HUGETLBFS select ARCH_SUPPORTS_NUMA_BALANCING + select HAVE_MOVE_PMD + select HAVE_MOVE_PUD select IRQ_WORK select PPC_MM_SLICES select PPC_HAVE_KUEP diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index c855a0aeb49c..d7ab868aab54 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -78,9 +78,6 @@ static inline int smp_startup_cpu(unsigned int lcpu) pcpu = get_hard_smp_processor_id(lcpu); - /* Fixup atomic count: it exited inside IRQ handler. */ - task_thread_info(paca_ptrs[lcpu]->__current)->preempt_count = 0; - /* * If the RTAS start-cpu token does not exist then presume the * cpu is already spinning. diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 096629f54576..f47429323eee 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -105,9 +105,6 @@ static inline int smp_startup_cpu(unsigned int lcpu) return 1; } - /* Fixup atomic count: it exited inside IRQ handler. */ - task_thread_info(paca_ptrs[lcpu]->__current)->preempt_count = 0; - /* * If the RTAS start-cpu token does not exist then presume the * cpu is already spinning. diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index a8304327072d..dbdbbc2f1dc5 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -1153,11 +1153,10 @@ static int __init xive_request_ipi(void) * Since the HW interrupt number doesn't have any meaning, * simply use the node number. */ - xid->irq = irq_domain_alloc_irqs(ipi_domain, 1, node, &info); - if (xid->irq < 0) { - ret = xid->irq; + ret = irq_domain_alloc_irqs(ipi_domain, 1, node, &info); + if (ret < 0) goto out_free_xive_ipis; - } + xid->irq = ret; snprintf(xid->name, sizeof(xid->name), "IPI-%d", node); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 469a70bd8da6..8fcceb8eda07 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -26,8 +26,8 @@ config RISCV select ARCH_HAS_KCOV select ARCH_HAS_MMIOWB select ARCH_HAS_PTE_SPECIAL - select ARCH_HAS_SET_DIRECT_MAP - select ARCH_HAS_SET_MEMORY + select ARCH_HAS_SET_DIRECT_MAP if MMU + select ARCH_HAS_SET_MEMORY if MMU select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST @@ -65,11 +65,14 @@ config RISCV select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL select HAVE_ARCH_KASAN if MMU && 64BIT select HAVE_ARCH_KASAN_VMALLOC if MMU && 64BIT + select HAVE_ARCH_KFENCE if MMU && 64BIT select HAVE_ARCH_KGDB if !XIP_KERNEL select HAVE_ARCH_KGDB_QXFER_PKT select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK + select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT && MMU + select HAVE_ARCH_VMAP_STACK if MMU && 64BIT select HAVE_ASM_MODVERSIONS select HAVE_CONTEXT_TRACKING select HAVE_DEBUG_KMEMLEAK @@ -83,11 +86,14 @@ config RISCV select HAVE_KPROBES if !XIP_KERNEL select HAVE_KPROBES_ON_FTRACE if !XIP_KERNEL select HAVE_KRETPROBES if !XIP_KERNEL + select HAVE_MOVE_PMD + select HAVE_MOVE_PUD select HAVE_PCI select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN @@ -488,13 +494,8 @@ config STACKPROTECTOR_PER_TASK def_bool y depends on STACKPROTECTOR && CC_HAVE_STACKPROTECTOR_TLS -config PHYS_RAM_BASE_FIXED - bool "Explicitly specified physical RAM address" - default n - config PHYS_RAM_BASE hex "Platform Physical RAM address" - depends on PHYS_RAM_BASE_FIXED default "0x80000000" help This is the physical address of RAM in the system. It has to be @@ -507,7 +508,6 @@ config XIP_KERNEL # This prevents XIP from being enabled by all{yes,mod}config, which # fail to build since XIP doesn't support large kernels. depends on !COMPILE_TEST - select PHYS_RAM_BASE_FIXED help Execute-In-Place allows the kernel to run from non-volatile storage directly addressable by the CPU, such as NOR flash. This saves RAM diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 99ecd8bcfd77..bc74afdbf31e 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -99,7 +99,6 @@ endif head-y := arch/riscv/kernel/head.o -core-y += arch/riscv/ core-$(CONFIG_RISCV_ERRATA_ALTERNATIVE) += arch/riscv/errata/ libs-y += arch/riscv/lib/ diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h index 2a652b0c987d..ef386fcf3939 100644 --- a/arch/riscv/include/asm/asm-prototypes.h +++ b/arch/riscv/include/asm/asm-prototypes.h @@ -25,4 +25,7 @@ DECLARE_DO_ERROR_INFO(do_trap_ecall_s); DECLARE_DO_ERROR_INFO(do_trap_ecall_m); DECLARE_DO_ERROR_INFO(do_trap_break); +asmlinkage unsigned long get_overflow_stack(void); +asmlinkage void handle_bad_stack(struct pt_regs *regs); + #endif /* _ASM_RISCV_PROTOTYPES_H */ diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index c025a746a148..69605a474270 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -52,19 +52,6 @@ #define __io_pbw() __asm__ __volatile__ ("fence iow,o" : : : "memory"); #define __io_paw() __asm__ __volatile__ ("fence o,io" : : : "memory"); -#define inb(c) ({ u8 __v; __io_pbr(); __v = readb_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) -#define inw(c) ({ u16 __v; __io_pbr(); __v = readw_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) -#define inl(c) ({ u32 __v; __io_pbr(); __v = readl_cpu((void*)(PCI_IOBASE + (c))); __io_par(__v); __v; }) - -#define outb(v,c) ({ __io_pbw(); writeb_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) -#define outw(v,c) ({ __io_pbw(); writew_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) -#define outl(v,c) ({ __io_pbw(); writel_cpu((v),(void*)(PCI_IOBASE + (c))); __io_paw(); }) - -#ifdef CONFIG_64BIT -#define inq(c) ({ u64 __v; __io_pbr(); __v = readq_cpu((void*)(c)); __io_par(__v); __v; }) -#define outq(v,c) ({ __io_pbw(); writeq_cpu((v),(void*)(c)); __io_paw(); }) -#endif - /* * Accesses from a single hart to a single I/O address must be ordered. This * allows us to use the raw read macros, but we still need to fence before and diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h new file mode 100644 index 000000000000..d887a54042aa --- /dev/null +++ b/arch/riscv/include/asm/kfence.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_KFENCE_H +#define _ASM_RISCV_KFENCE_H + +#include +#include +#include +#include + +static inline int split_pmd_page(unsigned long addr) +{ + int i; + unsigned long pfn = PFN_DOWN(__pa((addr & PMD_MASK))); + pmd_t *pmd = pmd_off_k(addr); + pte_t *pte = pte_alloc_one_kernel(&init_mm); + + if (!pte) + return -ENOMEM; + + for (i = 0; i < PTRS_PER_PTE; i++) + set_pte(pte + i, pfn_pte(pfn + i, PAGE_KERNEL)); + set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(pte)), PAGE_TABLE)); + + flush_tlb_kernel_range(addr, addr + PMD_SIZE); + return 0; +} + +static inline bool arch_kfence_init_pool(void) +{ + int ret; + unsigned long addr; + pmd_t *pmd; + + for (addr = (unsigned long)__kfence_pool; is_kfence_address((void *)addr); + addr += PAGE_SIZE) { + pmd = pmd_off_k(addr); + + if (pmd_leaf(*pmd)) { + ret = split_pmd_page(addr); + if (ret) + return false; + } + } + + return true; +} + +static inline bool kfence_protect_page(unsigned long addr, bool protect) +{ + pte_t *pte = virt_to_kpte(addr); + + if (protect) + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + else + set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + + return true; +} + +#endif /* _ASM_RISCV_KFENCE_H */ diff --git a/arch/riscv/include/asm/kprobes.h b/arch/riscv/include/asm/kprobes.h index 4647d38018f6..9ea9b5ec3113 100644 --- a/arch/riscv/include/asm/kprobes.h +++ b/arch/riscv/include/asm/kprobes.h @@ -29,18 +29,11 @@ struct prev_kprobe { unsigned int status; }; -/* Single step context for kprobe */ -struct kprobe_step_ctx { - unsigned long ss_pending; - unsigned long match_addr; -}; - /* per-cpu kprobe control block */ struct kprobe_ctlblk { unsigned int kprobe_status; unsigned long saved_status; struct prev_kprobe prev_kprobe; - struct kprobe_step_ctx ss_ctx; }; void arch_remove_kprobe(struct kprobe *p); diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h index b0659413a080..7030837adc1a 100644 --- a/arch/riscv/include/asm/mmu_context.h +++ b/arch/riscv/include/asm/mmu_context.h @@ -33,6 +33,8 @@ static inline int init_new_context(struct task_struct *tsk, return 0; } +DECLARE_STATIC_KEY_FALSE(use_asid_allocator); + #include #endif /* _ASM_RISCV_MMU_CONTEXT_H */ diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 6a7761c86ec2..cca8764aed83 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -37,16 +37,6 @@ #ifndef __ASSEMBLY__ -#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) -#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1))) - -/* align addr on a size boundary - adjust address up/down if needed */ -#define _ALIGN_UP(addr, size) (((addr)+((size)-1))&(~((size)-1))) -#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) - -/* align addr on a size boundary - adjust address up if needed */ -#define _ALIGN(addr, size) _ALIGN_UP(addr, size) - #define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE) #define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) @@ -89,59 +79,68 @@ typedef struct page *pgtable_t; #endif #ifdef CONFIG_MMU -extern unsigned long va_pa_offset; -#ifdef CONFIG_64BIT -extern unsigned long va_kernel_pa_offset; -#endif -#ifdef CONFIG_XIP_KERNEL -extern unsigned long va_kernel_xip_pa_offset; -#endif extern unsigned long pfn_base; #define ARCH_PFN_OFFSET (pfn_base) #else -#define va_pa_offset 0 -#ifdef CONFIG_64BIT -#define va_kernel_pa_offset 0 -#endif #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) #endif /* CONFIG_MMU */ -extern unsigned long kernel_virt_addr; +struct kernel_mapping { + unsigned long virt_addr; + uintptr_t phys_addr; + uintptr_t size; + /* Offset between linear mapping virtual address and kernel load address */ + unsigned long va_pa_offset; +#ifdef CONFIG_64BIT + /* Offset between kernel mapping virtual address and kernel load address */ + unsigned long va_kernel_pa_offset; +#endif + unsigned long va_kernel_xip_pa_offset; +#ifdef CONFIG_XIP_KERNEL + uintptr_t xiprom; + uintptr_t xiprom_sz; +#endif +}; + +extern struct kernel_mapping kernel_map; #ifdef CONFIG_64BIT -#define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + va_pa_offset)) -#ifdef CONFIG_XIP_KERNEL +#define is_kernel_mapping(x) \ + ((x) >= kernel_map.virt_addr && (x) < (kernel_map.virt_addr + kernel_map.size)) +#define is_linear_mapping(x) \ + ((x) >= PAGE_OFFSET && (x) < kernel_map.virt_addr) + +#define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset)) #define kernel_mapping_pa_to_va(y) ({ \ unsigned long _y = y; \ (_y >= CONFIG_PHYS_RAM_BASE) ? \ - (void *)((unsigned long)(_y) + va_kernel_pa_offset + XIP_OFFSET) : \ - (void *)((unsigned long)(_y) + va_kernel_xip_pa_offset); \ + (void *)((unsigned long)(_y) + kernel_map.va_kernel_pa_offset + XIP_OFFSET) : \ + (void *)((unsigned long)(_y) + kernel_map.va_kernel_xip_pa_offset); \ }) -#else -#define kernel_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + va_kernel_pa_offset)) -#endif #define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x) -#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - va_pa_offset) -#ifdef CONFIG_XIP_KERNEL +#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset) #define kernel_mapping_va_to_pa(y) ({ \ unsigned long _y = y; \ - (_y < kernel_virt_addr + XIP_OFFSET) ? \ - ((unsigned long)(_y) - va_kernel_xip_pa_offset) : \ - ((unsigned long)(_y) - va_kernel_pa_offset - XIP_OFFSET); \ + (_y < kernel_map.virt_addr + XIP_OFFSET) ? \ + ((unsigned long)(_y) - kernel_map.va_kernel_xip_pa_offset) : \ + ((unsigned long)(_y) - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \ }) -#else -#define kernel_mapping_va_to_pa(x) ((unsigned long)(x) - va_kernel_pa_offset) -#endif + #define __va_to_pa_nodebug(x) ({ \ unsigned long _x = x; \ - (_x < kernel_virt_addr) ? \ + is_linear_mapping(_x) ? \ linear_mapping_va_to_pa(_x) : kernel_mapping_va_to_pa(_x); \ }) #else -#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + va_pa_offset)) -#define __va_to_pa_nodebug(x) ((unsigned long)(x) - va_pa_offset) -#endif +#define is_kernel_mapping(x) \ + ((x) >= kernel_map.virt_addr && (x) < (kernel_map.virt_addr + kernel_map.size)) +#define is_linear_mapping(x) \ + ((x) >= PAGE_OFFSET) + +#define __pa_to_va_nodebug(x) ((void *)((unsigned long) (x) + kernel_map.va_pa_offset)) +#define __va_to_pa_nodebug(x) ((unsigned long)(x) - kernel_map.va_pa_offset) +#endif /* CONFIG_64BIT */ #ifdef CONFIG_DEBUG_VIRTUAL extern phys_addr_t __virt_to_phys(unsigned long x); diff --git a/arch/riscv/include/asm/pci.h b/arch/riscv/include/asm/pci.h index 658e112c3ce7..7fd52a30e605 100644 --- a/arch/riscv/include/asm/pci.h +++ b/arch/riscv/include/asm/pci.h @@ -18,6 +18,8 @@ /* RISC-V shim does not initialize PCI bus */ #define pcibios_assign_all_busses() 1 +#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1 + extern int isa_dma_bridge_buggy; #ifdef CONFIG_PCI diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index f3b0da64c6c8..228261aa9628 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -46,8 +46,7 @@ static inline int pud_bad(pud_t pud) #define pud_leaf pud_leaf static inline int pud_leaf(pud_t pud) { - return pud_present(pud) && - (pud_val(pud) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)); + return pud_present(pud) && (pud_val(pud) & _PAGE_LEAF); } static inline void set_pud(pud_t *pudp, pud_t pud) @@ -60,9 +59,9 @@ static inline void pud_clear(pud_t *pudp) set_pud(pudp, __pud(0)); } -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { - return (unsigned long)pfn_to_virt(pud_val(pud) >> _PAGE_PFN_SHIFT); + return (pmd_t *)pfn_to_virt(pud_val(pud) >> _PAGE_PFN_SHIFT); } static inline struct page *pud_page(pud_t pud) @@ -80,6 +79,8 @@ static inline unsigned long _pmd_pfn(pmd_t pmd) return pmd_val(pmd) >> _PAGE_PFN_SHIFT; } +#define mk_pmd(page, prot) pfn_pmd(page_to_pfn(page), prot) + #define pmd_ERROR(e) \ pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) diff --git a/arch/riscv/include/asm/pgtable-bits.h b/arch/riscv/include/asm/pgtable-bits.h index bbaeb5d35842..2ee413912926 100644 --- a/arch/riscv/include/asm/pgtable-bits.h +++ b/arch/riscv/include/asm/pgtable-bits.h @@ -39,5 +39,10 @@ #define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \ _PAGE_WRITE | _PAGE_EXEC | \ _PAGE_USER | _PAGE_GLOBAL)) +/* + * when all of R/W/X are zero, the PTE is a pointer to the next level + * of the page table; otherwise, it is a leaf PTE. + */ +#define _PAGE_LEAF (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC) #endif /* _ASM_RISCV_PGTABLE_BITS_H */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 62f3fe7368f3..39b550310ec6 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -76,6 +76,8 @@ #ifdef CONFIG_XIP_KERNEL #define XIP_OFFSET SZ_8M +#else +#define XIP_OFFSET 0 #endif #ifndef __ASSEMBLY__ @@ -133,7 +135,8 @@ | _PAGE_WRITE \ | _PAGE_PRESENT \ | _PAGE_ACCESSED \ - | _PAGE_DIRTY) + | _PAGE_DIRTY \ + | _PAGE_GLOBAL) #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) #define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE) @@ -171,10 +174,23 @@ extern pgd_t swapper_pg_dir[]; #define __S110 PAGE_SHARED_EXEC #define __S111 PAGE_SHARED_EXEC +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline int pmd_present(pmd_t pmd) +{ + /* + * Checking for _PAGE_LEAF is needed too because: + * When splitting a THP, split_huge_page() will temporarily clear + * the present bit, in this situation, pmd_present() and + * pmd_trans_huge() still needs to return true. + */ + return (pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROT_NONE | _PAGE_LEAF)); +} +#else static inline int pmd_present(pmd_t pmd) { return (pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROT_NONE)); } +#endif static inline int pmd_none(pmd_t pmd) { @@ -183,14 +199,13 @@ static inline int pmd_none(pmd_t pmd) static inline int pmd_bad(pmd_t pmd) { - return !pmd_present(pmd); + return !pmd_present(pmd) || (pmd_val(pmd) & _PAGE_LEAF); } #define pmd_leaf pmd_leaf static inline int pmd_leaf(pmd_t pmd) { - return pmd_present(pmd) && - (pmd_val(pmd) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)); + return pmd_present(pmd) && (pmd_val(pmd) & _PAGE_LEAF); } static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) @@ -228,6 +243,11 @@ static inline pte_t pmd_pte(pmd_t pmd) return __pte(pmd_val(pmd)); } +static inline pte_t pud_pte(pud_t pud) +{ + return __pte(pud_val(pud)); +} + /* Yields the page frame number (PFN) of a page table entry */ static inline unsigned long pte_pfn(pte_t pte) { @@ -266,8 +286,7 @@ static inline int pte_exec(pte_t pte) static inline int pte_huge(pte_t pte) { - return pte_present(pte) - && (pte_val(pte) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)); + return pte_present(pte) && (pte_val(pte) & _PAGE_LEAF); } static inline int pte_dirty(pte_t pte) @@ -370,6 +389,14 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, local_flush_tlb_page(address); } +static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp) +{ + pte_t *ptep = (pte_t *)pmdp; + + update_mmu_cache(vma, address, ptep); +} + #define __HAVE_ARCH_PTE_SAME static inline int pte_same(pte_t pte_a, pte_t pte_b) { @@ -463,6 +490,137 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, return ptep_test_and_clear_young(vma, address, ptep); } +/* + * THP functions + */ +static inline pmd_t pte_pmd(pte_t pte) +{ + return __pmd(pte_val(pte)); +} + +static inline pmd_t pmd_mkhuge(pmd_t pmd) +{ + return pmd; +} + +static inline pmd_t pmd_mkinvalid(pmd_t pmd) +{ + return __pmd(pmd_val(pmd) & ~(_PAGE_PRESENT|_PAGE_PROT_NONE)); +} + +#define __pmd_to_phys(pmd) (pmd_val(pmd) >> _PAGE_PFN_SHIFT << PAGE_SHIFT) + +static inline unsigned long pmd_pfn(pmd_t pmd) +{ + return ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT); +} + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); +} + +#define pmd_write pmd_write +static inline int pmd_write(pmd_t pmd) +{ + return pte_write(pmd_pte(pmd)); +} + +static inline int pmd_dirty(pmd_t pmd) +{ + return pte_dirty(pmd_pte(pmd)); +} + +static inline int pmd_young(pmd_t pmd) +{ + return pte_young(pmd_pte(pmd)); +} + +static inline pmd_t pmd_mkold(pmd_t pmd) +{ + return pte_pmd(pte_mkold(pmd_pte(pmd))); +} + +static inline pmd_t pmd_mkyoung(pmd_t pmd) +{ + return pte_pmd(pte_mkyoung(pmd_pte(pmd))); +} + +static inline pmd_t pmd_mkwrite(pmd_t pmd) +{ + return pte_pmd(pte_mkwrite(pmd_pte(pmd))); +} + +static inline pmd_t pmd_wrprotect(pmd_t pmd) +{ + return pte_pmd(pte_wrprotect(pmd_pte(pmd))); +} + +static inline pmd_t pmd_mkclean(pmd_t pmd) +{ + return pte_pmd(pte_mkclean(pmd_pte(pmd))); +} + +static inline pmd_t pmd_mkdirty(pmd_t pmd) +{ + return pte_pmd(pte_mkdirty(pmd_pte(pmd))); +} + +static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd) +{ + return set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)); +} + +static inline void set_pud_at(struct mm_struct *mm, unsigned long addr, + pud_t *pudp, pud_t pud) +{ + return set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud)); +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline int pmd_trans_huge(pmd_t pmd) +{ + return pmd_leaf(pmd); +} + +#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS +static inline int pmdp_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp, + pmd_t entry, int dirty) +{ + return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty); +} + +#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG +static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp) +{ + return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp); +} + +#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR +static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp)); +} + +#define __HAVE_ARCH_PMDP_SET_WRPROTECT +static inline void pmdp_set_wrprotect(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + ptep_set_wrprotect(mm, address, (pte_t *)pmdp); +} + +#define pmdp_establish pmdp_establish +static inline pmd_t pmdp_establish(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp, pmd_t pmd) +{ + return __pmd(atomic_long_xchg((atomic_long_t *)pmdp, pmd_val(pmd))); +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + /* * Encode and decode a swap entry * @@ -532,7 +690,6 @@ extern uintptr_t _dtb_early_pa; #define dtb_early_pa _dtb_early_pa #endif /* CONFIG_XIP_KERNEL */ -void setup_bootmem(void); void paging_init(void); void misc_mem_init(void); diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 09ad4e923510..6ecd461129d2 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -141,6 +141,37 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, return *(unsigned long *)((unsigned long)regs + offset); } + +/** + * regs_get_kernel_argument() - get Nth function argument in kernel + * @regs: pt_regs of that context + * @n: function argument number (start from 0) + * + * regs_get_argument() returns @n th argument of the function call. + * + * Note you can get the parameter correctly if the function has no + * more than eight arguments. + */ +static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs, + unsigned int n) +{ + static const int nr_reg_arguments = 8; + static const unsigned int argument_offs[] = { + offsetof(struct pt_regs, a0), + offsetof(struct pt_regs, a1), + offsetof(struct pt_regs, a2), + offsetof(struct pt_regs, a3), + offsetof(struct pt_regs, a4), + offsetof(struct pt_regs, a5), + offsetof(struct pt_regs, a6), + offsetof(struct pt_regs, a7), + }; + + if (n < nr_reg_arguments) + return regs_get_register(regs, argument_offs[n]); + return 0; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h index 8a303fb1ee3b..32336e8a17cb 100644 --- a/arch/riscv/include/asm/sections.h +++ b/arch/riscv/include/asm/sections.h @@ -6,6 +6,7 @@ #define __ASM_SECTIONS_H #include +#include extern char _start[]; extern char _start_kernel[]; @@ -13,4 +14,20 @@ extern char __init_data_begin[], __init_data_end[]; extern char __init_text_begin[], __init_text_end[]; extern char __alt_start[], __alt_end[]; +static inline bool is_va_kernel_text(uintptr_t va) +{ + uintptr_t start = (uintptr_t)_start; + uintptr_t end = (uintptr_t)__init_data_begin; + + return va >= start && va < end; +} + +static inline bool is_va_kernel_lm_alias_text(uintptr_t va) +{ + uintptr_t start = (uintptr_t)lm_alias(_start); + uintptr_t end = (uintptr_t)lm_alias(__init_data_begin); + + return va >= start && va < end; +} + #endif /* __ASM_SECTIONS_H */ diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h index 086f757e8ba3..a2c14d4b3993 100644 --- a/arch/riscv/include/asm/set_memory.h +++ b/arch/riscv/include/asm/set_memory.h @@ -16,20 +16,28 @@ int set_memory_rw(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); int set_memory_rw_nx(unsigned long addr, int numpages); -void protect_kernel_text_data(void); +static __always_inline int set_kernel_memory(char *startp, char *endp, + int (*set_memory)(unsigned long start, + int num_pages)) +{ + unsigned long start = (unsigned long)startp; + unsigned long end = (unsigned long)endp; + int num_pages = PAGE_ALIGN(end - start) >> PAGE_SHIFT; + + return set_memory(start, num_pages); +} #else static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; } static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; } static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } -static inline void protect_kernel_text_data(void) {} static inline int set_memory_rw_nx(unsigned long addr, int numpages) { return 0; } -#endif - -#if defined(CONFIG_64BIT) && defined(CONFIG_STRICT_KERNEL_RWX) -void protect_kernel_linear_mapping_text_rodata(void); -#else -static inline void protect_kernel_linear_mapping_text_rodata(void) {} +static inline int set_kernel_memory(char *startp, char *endp, + int (*set_memory)(unsigned long start, + int num_pages)) +{ + return 0; +} #endif int set_direct_map_invalid_noflush(struct page *page); diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 407bcc96a710..0a3f4f95c555 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -6,6 +6,7 @@ #ifndef _ASM_RISCV_SWITCH_TO_H #define _ASM_RISCV_SWITCH_TO_H +#include #include #include #include @@ -55,9 +56,13 @@ static inline void __switch_to_aux(struct task_struct *prev, fstate_restore(next, task_pt_regs(next)); } -extern bool has_fpu; +extern struct static_key_false cpu_hwcap_fpu; +static __always_inline bool has_fpu(void) +{ + return static_branch_likely(&cpu_hwcap_fpu); +} #else -#define has_fpu false +static __always_inline bool has_fpu(void) { return false; } #define fstate_save(task, regs) do { } while (0) #define fstate_restore(task, regs) do { } while (0) #define __switch_to_aux(__prev, __next) do { } while (0) @@ -70,7 +75,7 @@ extern struct task_struct *__switch_to(struct task_struct *, do { \ struct task_struct *__prev = (prev); \ struct task_struct *__next = (next); \ - if (has_fpu) \ + if (has_fpu()) \ __switch_to_aux(__prev, __next); \ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 0e549a3089b3..60da0dcacf14 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -19,6 +19,21 @@ #endif #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) +/* + * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect overflow by + * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the entry + * assembly. + */ +#ifdef CONFIG_VMAP_STACK +#define THREAD_ALIGN (2 * THREAD_SIZE) +#else +#define THREAD_ALIGN THREAD_SIZE +#endif + +#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER) +#define OVERFLOW_STACK_SIZE SZ_4K +#define SHADOW_OVERFLOW_STACK_SIZE (1024) + #ifndef __ASSEMBLY__ #include diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index c84218ad7afc..801019381dea 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -33,6 +33,11 @@ void flush_tlb_mm(struct mm_struct *mm); void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE +void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +#endif #else /* CONFIG_SMP && CONFIG_MMU */ #define flush_tlb_all() local_flush_tlb_all() diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index 977ee6181dab..6c316093a1e5 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -9,6 +9,7 @@ */ #define __ARCH_WANT_SYS_CLONE +#define __ARCH_WANT_MEMFD_SECRET #include diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 9ef33346853c..90f8ce64fa6f 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -311,4 +311,6 @@ void asm_offsets(void) * ensures the alignment is sane. */ DEFINE(PT_SIZE_ON_STACK, ALIGN(sizeof(struct pt_regs), STACK_ALIGN)); + + OFFSET(KERNEL_MAP_VIRT_ADDR, kernel_mapping, virt_addr); } diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index ac202f44a670..d959d207a40d 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -19,7 +19,7 @@ unsigned long elf_hwcap __read_mostly; static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly; #ifdef CONFIG_FPU -bool has_fpu __read_mostly; +__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu); #endif /** @@ -59,7 +59,7 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit) } EXPORT_SYMBOL_GPL(__riscv_isa_extension_available); -void riscv_fill_hwcap(void) +void __init riscv_fill_hwcap(void) { struct device_node *node; const char *isa; @@ -146,6 +146,6 @@ void riscv_fill_hwcap(void) #ifdef CONFIG_FPU if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)) - has_fpu = true; + static_branch_enable(&cpu_hwcap_fpu); #endif } diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 80d5a9e017b0..98f502654edd 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -30,6 +30,15 @@ ENTRY(handle_exception) _restore_kernel_tpsp: csrr tp, CSR_SCRATCH REG_S sp, TASK_TI_KERNEL_SP(tp) + +#ifdef CONFIG_VMAP_STACK + addi sp, sp, -(PT_SIZE_ON_STACK) + srli sp, sp, THREAD_SHIFT + andi sp, sp, 0x1 + bnez sp, handle_kernel_stack_overflow + REG_L sp, TASK_TI_KERNEL_SP(tp) +#endif + _save_context: REG_S sp, TASK_TI_USER_SP(tp) REG_L sp, TASK_TI_KERNEL_SP(tp) @@ -376,6 +385,105 @@ handle_syscall_trace_exit: call do_syscall_trace_exit j ret_from_exception +#ifdef CONFIG_VMAP_STACK +handle_kernel_stack_overflow: + la sp, shadow_stack + addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE + + //save caller register to shadow stack + addi sp, sp, -(PT_SIZE_ON_STACK) + REG_S x1, PT_RA(sp) + REG_S x5, PT_T0(sp) + REG_S x6, PT_T1(sp) + REG_S x7, PT_T2(sp) + REG_S x10, PT_A0(sp) + REG_S x11, PT_A1(sp) + REG_S x12, PT_A2(sp) + REG_S x13, PT_A3(sp) + REG_S x14, PT_A4(sp) + REG_S x15, PT_A5(sp) + REG_S x16, PT_A6(sp) + REG_S x17, PT_A7(sp) + REG_S x28, PT_T3(sp) + REG_S x29, PT_T4(sp) + REG_S x30, PT_T5(sp) + REG_S x31, PT_T6(sp) + + la ra, restore_caller_reg + tail get_overflow_stack + +restore_caller_reg: + //save per-cpu overflow stack + REG_S a0, -8(sp) + //restore caller register from shadow_stack + REG_L x1, PT_RA(sp) + REG_L x5, PT_T0(sp) + REG_L x6, PT_T1(sp) + REG_L x7, PT_T2(sp) + REG_L x10, PT_A0(sp) + REG_L x11, PT_A1(sp) + REG_L x12, PT_A2(sp) + REG_L x13, PT_A3(sp) + REG_L x14, PT_A4(sp) + REG_L x15, PT_A5(sp) + REG_L x16, PT_A6(sp) + REG_L x17, PT_A7(sp) + REG_L x28, PT_T3(sp) + REG_L x29, PT_T4(sp) + REG_L x30, PT_T5(sp) + REG_L x31, PT_T6(sp) + + //load per-cpu overflow stack + REG_L sp, -8(sp) + addi sp, sp, -(PT_SIZE_ON_STACK) + + //save context to overflow stack + REG_S x1, PT_RA(sp) + REG_S x3, PT_GP(sp) + REG_S x5, PT_T0(sp) + REG_S x6, PT_T1(sp) + REG_S x7, PT_T2(sp) + REG_S x8, PT_S0(sp) + REG_S x9, PT_S1(sp) + REG_S x10, PT_A0(sp) + REG_S x11, PT_A1(sp) + REG_S x12, PT_A2(sp) + REG_S x13, PT_A3(sp) + REG_S x14, PT_A4(sp) + REG_S x15, PT_A5(sp) + REG_S x16, PT_A6(sp) + REG_S x17, PT_A7(sp) + REG_S x18, PT_S2(sp) + REG_S x19, PT_S3(sp) + REG_S x20, PT_S4(sp) + REG_S x21, PT_S5(sp) + REG_S x22, PT_S6(sp) + REG_S x23, PT_S7(sp) + REG_S x24, PT_S8(sp) + REG_S x25, PT_S9(sp) + REG_S x26, PT_S10(sp) + REG_S x27, PT_S11(sp) + REG_S x28, PT_T3(sp) + REG_S x29, PT_T4(sp) + REG_S x30, PT_T5(sp) + REG_S x31, PT_T6(sp) + + REG_L s0, TASK_TI_KERNEL_SP(tp) + csrr s1, CSR_STATUS + csrr s2, CSR_EPC + csrr s3, CSR_TVAL + csrr s4, CSR_CAUSE + csrr s5, CSR_SCRATCH + REG_S s0, PT_SP(sp) + REG_S s1, PT_STATUS(sp) + REG_S s2, PT_EPC(sp) + REG_S s3, PT_BADADDR(sp) + REG_S s4, PT_CAUSE(sp) + REG_S s5, PT_TP(sp) + move a0, sp + tail handle_bad_stack +#endif + END(handle_exception) ENTRY(ret_from_fork) diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 89cc58ab52b4..fce5184b22c3 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -81,9 +81,9 @@ pe_head_start: #ifdef CONFIG_MMU relocate: /* Relocate return address */ - la a1, kernel_virt_addr + la a1, kernel_map XIP_FIXUP_OFFSET a1 - REG_L a1, 0(a1) + REG_L a1, KERNEL_MAP_VIRT_ADDR(a1) la a2, _start sub a1, a1, a2 add ra, ra, a1 diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S index 88c3beabe9b4..a80b52a74f58 100644 --- a/arch/riscv/kernel/kexec_relocate.S +++ b/arch/riscv/kernel/kexec_relocate.S @@ -20,7 +20,7 @@ SYM_CODE_START(riscv_kexec_relocate) * s4: Pointer to the destination address for the relocation * s5: (const) Number of words per page * s6: (const) 1, used for subtraction - * s7: (const) va_pa_offset, used when switching MMU off + * s7: (const) kernel_map.va_pa_offset, used when switching MMU off * s8: (const) Physical address of the main loop * s9: (debug) indirection page counter * s10: (debug) entry counter @@ -159,7 +159,7 @@ SYM_CODE_START(riscv_kexec_norelocate) * s0: (const) Phys address to jump to * s1: (const) Phys address of the FDT image * s2: (const) The hartid of the current hart - * s3: (const) va_pa_offset, used when switching MMU off + * s3: (const) kernel_map.va_pa_offset, used when switching MMU off */ mv s0, a1 mv s1, a2 diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c index 9e99e1db156b..e6eca271a4d6 100644 --- a/arch/riscv/kernel/machine_kexec.c +++ b/arch/riscv/kernel/machine_kexec.c @@ -189,6 +189,6 @@ machine_kexec(struct kimage *image) /* Jump to the relocation code */ pr_notice("Bye...\n"); kexec_method(first_ind_entry, jump_addr, fdt_addr, - this_hart_id, va_pa_offset); + this_hart_id, kernel_map.va_pa_offset); unreachable(); } diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index 247e33fa5bc7..00088dc6da4b 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -17,7 +17,7 @@ DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); static void __kprobes -post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *); +post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); static void __kprobes arch_prepare_ss_slot(struct kprobe *p) { @@ -43,7 +43,7 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs) p->ainsn.api.handler((u32)p->opcode, (unsigned long)p->addr, regs); - post_kprobe_handler(kcb, regs); + post_kprobe_handler(p, kcb, regs); } int __kprobes arch_prepare_kprobe(struct kprobe *p) @@ -151,21 +151,6 @@ static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb, regs->status = kcb->saved_status; } -static void __kprobes -set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr, struct kprobe *p) -{ - unsigned long offset = GET_INSN_LENGTH(p->opcode); - - kcb->ss_ctx.ss_pending = true; - kcb->ss_ctx.match_addr = addr + offset; -} - -static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb) -{ - kcb->ss_ctx.ss_pending = false; - kcb->ss_ctx.match_addr = 0; -} - static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, int reenter) @@ -184,8 +169,6 @@ static void __kprobes setup_singlestep(struct kprobe *p, /* prepare for single stepping */ slot = (unsigned long)p->ainsn.api.insn; - set_ss_context(kcb, slot, p); /* mark pending ss */ - /* IRQs and single stepping do not mix well. */ kprobes_save_local_irqflag(kcb, regs); @@ -221,13 +204,8 @@ static int __kprobes reenter_kprobe(struct kprobe *p, } static void __kprobes -post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs) +post_kprobe_handler(struct kprobe *cur, struct kprobe_ctlblk *kcb, struct pt_regs *regs) { - struct kprobe *cur = kprobe_running(); - - if (!cur) - return; - /* return addr restore if non-branching insn */ if (cur->ainsn.api.restore != 0) regs->epc = cur->ainsn.api.restore; @@ -342,16 +320,16 @@ bool __kprobes kprobe_single_step_handler(struct pt_regs *regs) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long addr = instruction_pointer(regs); + struct kprobe *cur = kprobe_running(); - if ((kcb->ss_ctx.ss_pending) - && (kcb->ss_ctx.match_addr == instruction_pointer(regs))) { - clear_ss_context(kcb); /* clear pending ss */ - + if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) && + ((unsigned long)&cur->ainsn.api.insn[0] + GET_INSN_LENGTH(cur->opcode) == addr)) { kprobes_restore_local_irqflag(kcb, regs); - - post_kprobe_handler(kcb, regs); + post_kprobe_handler(cur, kcb, regs); return true; } + /* not ours, kprobes should ignore it */ return false; } diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index f9cd57c9c67d..03ac3aa611f5 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -87,7 +87,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { regs->status = SR_PIE; - if (has_fpu) { + if (has_fpu()) { regs->status |= SR_FS_INITIAL; /* * Restore the initial value to the FP register diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 9a1b7a0603b2..18bd0e4bc36c 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -264,10 +263,7 @@ static void __init parse_dtb(void) void __init setup_arch(char **cmdline_p) { parse_dtb(); - init_mm.start_code = (unsigned long) _stext; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_stext, _etext, _edata, _end); *cmdline_p = boot_command_line; @@ -276,7 +272,6 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); efi_init(); - setup_bootmem(); paging_init(); #if IS_ENABLED(CONFIG_BUILTIN_DTB) unflatten_and_copy_device_tree(); @@ -291,15 +286,6 @@ void __init setup_arch(char **cmdline_p) init_resources(); sbi_init(); - if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) { - protect_kernel_text_data(); - protect_kernel_linear_mapping_text_rodata(); - } - -#ifdef CONFIG_SWIOTLB - swiotlb_init(1); -#endif - #ifdef CONFIG_KASAN kasan_init(); #endif @@ -334,11 +320,10 @@ subsys_initcall(topology_init); void free_initmem(void) { - unsigned long init_begin = (unsigned long)__init_begin; - unsigned long init_end = (unsigned long)__init_end; - if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX)) - set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT); + set_kernel_memory(lm_alias(__init_begin), lm_alias(__init_end), + IS_ENABLED(CONFIG_64BIT) ? + set_memory_rw : set_memory_rw_nx); free_initmem_default(POISON_FREE_INITMEM); } diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 65942b3748b4..c2d5ecbe5526 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -90,7 +90,7 @@ static long restore_sigcontext(struct pt_regs *regs, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs)); /* Restore the floating-point state. */ - if (has_fpu) + if (has_fpu()) err |= restore_fp_state(regs, &sc->sc_fpregs); return err; } @@ -143,7 +143,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); /* Save the floating-point state. */ - if (has_fpu) + if (has_fpu()) err |= save_fp_state(regs, &sc->sc_fpregs); return err; } diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 7bc88d8aab97..0a98fd0ddfe9 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -203,3 +203,38 @@ int is_valid_bugaddr(unsigned long pc) void __init trap_init(void) { } + +#ifdef CONFIG_VMAP_STACK +static DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], + overflow_stack)__aligned(16); +/* + * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used + * to get per-cpu overflow stack(get_overflow_stack). + */ +long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)]; +asmlinkage unsigned long get_overflow_stack(void) +{ + return (unsigned long)this_cpu_ptr(overflow_stack) + + OVERFLOW_STACK_SIZE; +} + +asmlinkage void handle_bad_stack(struct pt_regs *regs) +{ + unsigned long tsk_stk = (unsigned long)current->stack; + unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack); + + console_verbose(); + + pr_emerg("Insufficient stack space to handle exception!\n"); + pr_emerg("Task stack: [0x%016lx..0x%016lx]\n", + tsk_stk, tsk_stk + THREAD_SIZE); + pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n", + ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE); + + __show_regs(regs); + panic("Kernel stack overflow"); + + for (;;) + wait_for_interrupt(); +} +#endif diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S index a3ff09c4c3f9..af776555ded9 100644 --- a/arch/riscv/kernel/vmlinux-xip.lds.S +++ b/arch/riscv/kernel/vmlinux-xip.lds.S @@ -12,7 +12,6 @@ #include #include -#include #include #include diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 891742ff75a7..502d0826ecb1 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -117,7 +117,7 @@ SECTIONS . = ALIGN(SECTION_ALIGN); _data = .; - RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) + RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN) .sdata : { __global_pointer$ = . + 0x800; *(.sdata*) diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index fceaeb18cc64..bceb0629e440 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -19,50 +19,161 @@ ENTRY(__asm_copy_from_user) li t6, SR_SUM csrs CSR_STATUS, t6 - add a3, a1, a2 - /* Use word-oriented copy only if low-order bits match */ - andi t0, a0, SZREG-1 - andi t1, a1, SZREG-1 - bne t0, t1, 2f + /* Save for return value */ + mv t5, a2 - addi t0, a1, SZREG-1 - andi t1, a3, ~(SZREG-1) - andi t0, t0, ~(SZREG-1) /* - * a3: terminal address of source region - * t0: lowest XLEN-aligned address in source - * t1: highest XLEN-aligned address in source + * Register allocation for code below: + * a0 - start of uncopied dst + * a1 - start of uncopied src + * a2 - size + * t0 - end of uncopied dst */ - bgeu t0, t1, 2f - bltu a1, t0, 4f + add t0, a0, a2 + bgtu a0, t0, 5f + + /* + * Use byte copy only if too small. + */ + li a3, 8*SZREG /* size must be larger than size in word_copy */ + bltu a2, a3, .Lbyte_copy_tail + + /* + * Copy first bytes until dst is align to word boundary. + * a0 - start of dst + * t1 - start of aligned dst + */ + addi t1, a0, SZREG-1 + andi t1, t1, ~(SZREG-1) + /* dst is already aligned, skip */ + beq a0, t1, .Lskip_first_bytes 1: - fixup REG_L, t2, (a1), 10f - fixup REG_S, t2, (a0), 10f - addi a1, a1, SZREG - addi a0, a0, SZREG - bltu a1, t1, 1b + /* a5 - one byte for copying data */ + fixup lb a5, 0(a1), 10f + addi a1, a1, 1 /* src */ + fixup sb a5, 0(a0), 10f + addi a0, a0, 1 /* dst */ + bltu a0, t1, 1b /* t1 - start of aligned dst */ + +.Lskip_first_bytes: + /* + * Now dst is aligned. + * Use shift-copy if src is misaligned. + * Use word-copy if both src and dst are aligned because + * can not use shift-copy which do not require shifting + */ + /* a1 - start of src */ + andi a3, a1, SZREG-1 + bnez a3, .Lshift_copy + +.Lword_copy: + /* + * Both src and dst are aligned, unrolled word copy + * + * a0 - start of aligned dst + * a1 - start of aligned src + * a3 - a1 & mask:(SZREG-1) + * t0 - end of aligned dst + */ + addi t0, t0, -(8*SZREG-1) /* not to over run */ 2: - bltu a1, a3, 5f + fixup REG_L a4, 0(a1), 10f + fixup REG_L a5, SZREG(a1), 10f + fixup REG_L a6, 2*SZREG(a1), 10f + fixup REG_L a7, 3*SZREG(a1), 10f + fixup REG_L t1, 4*SZREG(a1), 10f + fixup REG_L t2, 5*SZREG(a1), 10f + fixup REG_L t3, 6*SZREG(a1), 10f + fixup REG_L t4, 7*SZREG(a1), 10f + fixup REG_S a4, 0(a0), 10f + fixup REG_S a5, SZREG(a0), 10f + fixup REG_S a6, 2*SZREG(a0), 10f + fixup REG_S a7, 3*SZREG(a0), 10f + fixup REG_S t1, 4*SZREG(a0), 10f + fixup REG_S t2, 5*SZREG(a0), 10f + fixup REG_S t3, 6*SZREG(a0), 10f + fixup REG_S t4, 7*SZREG(a0), 10f + addi a0, a0, 8*SZREG + addi a1, a1, 8*SZREG + bltu a0, t0, 2b + + addi t0, t0, 8*SZREG-1 /* revert to original value */ + j .Lbyte_copy_tail + +.Lshift_copy: + + /* + * Word copy with shifting. + * For misaligned copy we still perform aligned word copy, but + * we need to use the value fetched from the previous iteration and + * do some shifts. + * This is safe because reading less than a word size. + * + * a0 - start of aligned dst + * a1 - start of src + * a3 - a1 & mask:(SZREG-1) + * t0 - end of uncopied dst + * t1 - end of aligned dst + */ + /* calculating aligned word boundary for dst */ + andi t1, t0, ~(SZREG-1) + /* Converting unaligned src to aligned arc */ + andi a1, a1, ~(SZREG-1) + + /* + * Calculate shifts + * t3 - prev shift + * t4 - current shift + */ + slli t3, a3, LGREG + li a5, SZREG*8 + sub t4, a5, t3 + + /* Load the first word to combine with seceond word */ + fixup REG_L a5, 0(a1), 10f 3: + /* Main shifting copy + * + * a0 - start of aligned dst + * a1 - start of aligned src + * t1 - end of aligned dst + */ + + /* At least one iteration will be executed */ + srl a4, a5, t3 + fixup REG_L a5, SZREG(a1), 10f + addi a1, a1, SZREG + sll a2, a5, t4 + or a2, a2, a4 + fixup REG_S a2, 0(a0), 10f + addi a0, a0, SZREG + bltu a0, t1, 3b + + /* Revert src to original unaligned value */ + add a1, a1, a3 + +.Lbyte_copy_tail: + /* + * Byte copy anything left. + * + * a0 - start of remaining dst + * a1 - start of remaining src + * t0 - end of remaining dst + */ + bgeu a0, t0, 5f +4: + fixup lb a5, 0(a1), 10f + addi a1, a1, 1 /* src */ + fixup sb a5, 0(a0), 10f + addi a0, a0, 1 /* dst */ + bltu a0, t0, 4b /* t0 - end of dst */ + +5: /* Disable access to user memory */ csrc CSR_STATUS, t6 - li a0, 0 + li a0, 0 ret -4: /* Edge case: unalignment */ - fixup lbu, t2, (a1), 10f - fixup sb, t2, (a0), 10f - addi a1, a1, 1 - addi a0, a0, 1 - bltu a1, t0, 4b - j 1b -5: /* Edge case: remainder */ - fixup lbu, t2, (a1), 10f - fixup sb, t2, (a0), 10f - addi a1, a1, 1 - addi a0, a0, 1 - bltu a1, a3, 5b - j 3b ENDPROC(__asm_copy_to_user) ENDPROC(__asm_copy_from_user) EXPORT_SYMBOL(__asm_copy_to_user) @@ -117,7 +228,7 @@ EXPORT_SYMBOL(__clear_user) 10: /* Disable access to user memory */ csrs CSR_STATUS, t6 - mv a0, a2 + mv a0, t5 ret 11: csrs CSR_STATUS, t6 diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index 68aa312fc352..ee3459cb6750 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -18,7 +18,7 @@ #ifdef CONFIG_MMU -static DEFINE_STATIC_KEY_FALSE(use_asid_allocator); +DEFINE_STATIC_KEY_FALSE(use_asid_allocator); static unsigned long asid_bits; static unsigned long num_asids; @@ -213,7 +213,7 @@ static inline void set_mm(struct mm_struct *mm, unsigned int cpu) set_mm_noasid(mm); } -static int asids_init(void) +static int __init asids_init(void) { unsigned long old; @@ -243,8 +243,7 @@ static int asids_init(void) if (num_asids > (2 * num_possible_cpus())) { atomic_long_set(¤t_version, num_asids); - context_asid_map = kcalloc(BITS_TO_LONGS(num_asids), - sizeof(*context_asid_map), GFP_KERNEL); + context_asid_map = bitmap_zalloc(num_asids, GFP_KERNEL); if (!context_asid_map) panic("Failed to allocate bitmap for %lu ASIDs\n", num_asids); @@ -280,11 +279,12 @@ static inline void set_mm(struct mm_struct *mm, unsigned int cpu) * cache flush to be performed before execution resumes on each hart. This * actually performs that local instruction cache flush, which implicitly only * refers to the current hart. + * + * The "cpu" argument must be the current local CPU number. */ -static inline void flush_icache_deferred(struct mm_struct *mm) +static inline void flush_icache_deferred(struct mm_struct *mm, unsigned int cpu) { #ifdef CONFIG_SMP - unsigned int cpu = smp_processor_id(); cpumask_t *mask = &mm->context.icache_stale_mask; if (cpumask_test_cpu(cpu, mask)) { @@ -320,5 +320,5 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, set_mm(next, cpu); - flush_icache_deferred(next); + flush_icache_deferred(next, cpu); } diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 096463cc6fff..aa08dd2f8fae 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,15 @@ static inline void no_context(struct pt_regs *regs, unsigned long addr) * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ - msg = (addr < PAGE_SIZE) ? "NULL pointer dereference" : "paging request"; + if (addr < PAGE_SIZE) + msg = "NULL pointer dereference"; + else { + if (kfence_handle_page_fault(addr, regs->cause == EXC_STORE_PAGE_FAULT, regs)) + return; + + msg = "paging request"; + } + die_kernel_fault(msg, addr, regs); } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 4c4c92ce0bb8..269fc648ef3d 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -29,10 +30,14 @@ #include "../kernel/head.h" -unsigned long kernel_virt_addr = KERNEL_LINK_ADDR; -EXPORT_SYMBOL(kernel_virt_addr); +struct kernel_mapping kernel_map __ro_after_init; +EXPORT_SYMBOL(kernel_map); #ifdef CONFIG_XIP_KERNEL -#define kernel_virt_addr (*((unsigned long *)XIP_FIXUP(&kernel_virt_addr))) +#define kernel_map (*(struct kernel_mapping *)XIP_FIXUP(&kernel_map)) +#endif + +#ifdef CONFIG_XIP_KERNEL +extern char _xiprom[], _exiprom[]; #endif unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] @@ -53,7 +58,7 @@ struct pt_alloc_ops { #endif }; -static phys_addr_t dma32_phys_limit __ro_after_init; +static phys_addr_t dma32_phys_limit __initdata; static void __init zone_sizes_init(void) { @@ -67,11 +72,6 @@ static void __init zone_sizes_init(void) free_area_init(max_zone_pfns); } -static void __init setup_zero_page(void) -{ - memset((void *)empty_zero_page, 0, PAGE_SIZE); -} - #if defined(CONFIG_MMU) && defined(CONFIG_DEBUG_VM) static inline void print_mlk(char *name, unsigned long b, unsigned long t) { @@ -113,25 +113,53 @@ void __init mem_init(void) BUG_ON(!mem_map); #endif /* CONFIG_FLATMEM */ +#ifdef CONFIG_SWIOTLB + if (swiotlb_force == SWIOTLB_FORCE || + max_pfn > PFN_DOWN(dma32_phys_limit)) + swiotlb_init(1); + else + swiotlb_force = SWIOTLB_NO_FORCE; +#endif high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); memblock_free_all(); print_vm_layout(); } -void __init setup_bootmem(void) +/* + * The default maximal physical memory size is -PAGE_OFFSET, + * limit the memory size via mem. + */ +static phys_addr_t memory_limit = -PAGE_OFFSET; + +static int __init early_mem(char *p) +{ + u64 size; + + if (!p) + return 1; + + size = memparse(p, &p) & PAGE_MASK; + memory_limit = min_t(u64, size, memory_limit); + + pr_notice("Memory limited to %lldMB\n", (u64)memory_limit >> 20); + + return 0; +} +early_param("mem", early_mem); + +static void __init setup_bootmem(void) { phys_addr_t vmlinux_end = __pa_symbol(&_end); phys_addr_t vmlinux_start = __pa_symbol(&_start); - phys_addr_t dram_end = memblock_end_of_DRAM(); phys_addr_t max_mapped_addr = __pa(~(ulong)0); + phys_addr_t dram_end; #ifdef CONFIG_XIP_KERNEL vmlinux_start = __pa_symbol(&_sdata); #endif - /* The maximal physical memory size is -PAGE_OFFSET. */ - memblock_enforce_memory_limit(-PAGE_OFFSET); + memblock_enforce_memory_limit(memory_limit); /* * Reserve from the start of the kernel to the end of the kernel @@ -146,6 +174,7 @@ void __init setup_bootmem(void) #endif memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); + dram_end = memblock_end_of_DRAM(); /* * memblock allocator is not aware of the fact that last 4K bytes of * the addressable memory can not be mapped because of IS_ERR_VALUE @@ -176,15 +205,8 @@ void __init setup_bootmem(void) memblock_allow_resize(); } -#ifdef CONFIG_XIP_KERNEL - -extern char _xiprom[], _exiprom[]; -extern char _sdata[], _edata[]; - -#endif /* CONFIG_XIP_KERNEL */ - #ifdef CONFIG_MMU -static struct pt_alloc_ops _pt_ops __ro_after_init; +static struct pt_alloc_ops _pt_ops __initdata; #ifdef CONFIG_XIP_KERNEL #define pt_ops (*(struct pt_alloc_ops *)XIP_FIXUP(&_pt_ops)) @@ -192,31 +214,12 @@ static struct pt_alloc_ops _pt_ops __ro_after_init; #define pt_ops _pt_ops #endif -/* Offset between linear mapping virtual address and kernel load address */ -unsigned long va_pa_offset __ro_after_init; -EXPORT_SYMBOL(va_pa_offset); -#ifdef CONFIG_XIP_KERNEL -#define va_pa_offset (*((unsigned long *)XIP_FIXUP(&va_pa_offset))) -#endif -/* Offset between kernel mapping virtual address and kernel load address */ -#ifdef CONFIG_64BIT -unsigned long va_kernel_pa_offset; -EXPORT_SYMBOL(va_kernel_pa_offset); -#endif -#ifdef CONFIG_XIP_KERNEL -#define va_kernel_pa_offset (*((unsigned long *)XIP_FIXUP(&va_kernel_pa_offset))) -#endif -unsigned long va_kernel_xip_pa_offset; -EXPORT_SYMBOL(va_kernel_xip_pa_offset); -#ifdef CONFIG_XIP_KERNEL -#define va_kernel_xip_pa_offset (*((unsigned long *)XIP_FIXUP(&va_kernel_xip_pa_offset))) -#endif unsigned long pfn_base __ro_after_init; EXPORT_SYMBOL(pfn_base); pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; -pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; +static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); @@ -253,7 +256,7 @@ static inline pte_t *__init get_pte_virt_fixmap(phys_addr_t pa) return (pte_t *)set_fixmap_offset(FIX_PTE, pa); } -static inline pte_t *get_pte_virt_late(phys_addr_t pa) +static inline pte_t *__init get_pte_virt_late(phys_addr_t pa) { return (pte_t *) __va(pa); } @@ -272,7 +275,7 @@ static inline phys_addr_t __init alloc_pte_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t alloc_pte_late(uintptr_t va) +static phys_addr_t __init alloc_pte_late(uintptr_t va) { unsigned long vaddr; @@ -296,10 +299,10 @@ static void __init create_pte_mapping(pte_t *ptep, #ifndef __PAGETABLE_PMD_FOLDED -pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss; -pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss; -pmd_t early_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); -pmd_t early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); +static pmd_t trampoline_pmd[PTRS_PER_PMD] __page_aligned_bss; +static pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss; +static pmd_t early_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); +static pmd_t early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); #ifdef CONFIG_XIP_KERNEL #define trampoline_pmd ((pmd_t *)XIP_FIXUP(trampoline_pmd)) @@ -319,14 +322,14 @@ static pmd_t *__init get_pmd_virt_fixmap(phys_addr_t pa) return (pmd_t *)set_fixmap_offset(FIX_PMD, pa); } -static pmd_t *get_pmd_virt_late(phys_addr_t pa) +static pmd_t *__init get_pmd_virt_late(phys_addr_t pa) { return (pmd_t *) __va(pa); } static phys_addr_t __init alloc_pmd_early(uintptr_t va) { - BUG_ON((va - kernel_virt_addr) >> PGDIR_SHIFT); + BUG_ON((va - kernel_map.virt_addr) >> PGDIR_SHIFT); return (uintptr_t)early_pmd; } @@ -336,7 +339,7 @@ static phys_addr_t __init alloc_pmd_fixmap(uintptr_t va) return memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); } -static phys_addr_t alloc_pmd_late(uintptr_t va) +static phys_addr_t __init alloc_pmd_late(uintptr_t va) { unsigned long vaddr; @@ -436,6 +439,43 @@ asmlinkage void __init __copy_data(void) } #endif +#ifdef CONFIG_STRICT_KERNEL_RWX +static __init pgprot_t pgprot_from_va(uintptr_t va) +{ + if (is_va_kernel_text(va)) + return PAGE_KERNEL_READ_EXEC; + + /* + * In 64-bit kernel, the kernel mapping is outside the linear mapping so + * we must protect its linear mapping alias from being executed and + * written. + * And rodata section is marked readonly in mark_rodata_ro. + */ + if (IS_ENABLED(CONFIG_64BIT) && is_va_kernel_lm_alias_text(va)) + return PAGE_KERNEL_READ; + + return PAGE_KERNEL; +} + +void mark_rodata_ro(void) +{ + set_kernel_memory(__start_rodata, _data, set_memory_ro); + if (IS_ENABLED(CONFIG_64BIT)) + set_kernel_memory(lm_alias(__start_rodata), lm_alias(_data), + set_memory_ro); + + debug_checkwx(); +} +#else +static __init pgprot_t pgprot_from_va(uintptr_t va) +{ + if (IS_ENABLED(CONFIG_64BIT) && !is_kernel_mapping(va)) + return PAGE_KERNEL; + + return PAGE_KERNEL_EXEC; +} +#endif /* CONFIG_STRICT_KERNEL_RWX */ + /* * setup_vm() is called from head.S with MMU-off. * @@ -454,45 +494,39 @@ asmlinkage void __init __copy_data(void) #error "setup_vm() is called from head.S before relocate so it should not use absolute addressing." #endif -uintptr_t load_pa, load_sz; #ifdef CONFIG_XIP_KERNEL -#define load_pa (*((uintptr_t *)XIP_FIXUP(&load_pa))) -#define load_sz (*((uintptr_t *)XIP_FIXUP(&load_sz))) -#endif - -#ifdef CONFIG_XIP_KERNEL -uintptr_t xiprom, xiprom_sz; -#define xiprom_sz (*((uintptr_t *)XIP_FIXUP(&xiprom_sz))) -#define xiprom (*((uintptr_t *)XIP_FIXUP(&xiprom))) - -static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size) +static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size, + __always_unused bool early) { uintptr_t va, end_va; /* Map the flash resident part */ - end_va = kernel_virt_addr + xiprom_sz; - for (va = kernel_virt_addr; va < end_va; va += map_size) + end_va = kernel_map.virt_addr + kernel_map.xiprom_sz; + for (va = kernel_map.virt_addr; va < end_va; va += map_size) create_pgd_mapping(pgdir, va, - xiprom + (va - kernel_virt_addr), + kernel_map.xiprom + (va - kernel_map.virt_addr), map_size, PAGE_KERNEL_EXEC); /* Map the data in RAM */ - end_va = kernel_virt_addr + XIP_OFFSET + load_sz; - for (va = kernel_virt_addr + XIP_OFFSET; va < end_va; va += map_size) + end_va = kernel_map.virt_addr + XIP_OFFSET + kernel_map.size; + for (va = kernel_map.virt_addr + XIP_OFFSET; va < end_va; va += map_size) create_pgd_mapping(pgdir, va, - load_pa + (va - (kernel_virt_addr + XIP_OFFSET)), + kernel_map.phys_addr + (va - (kernel_map.virt_addr + XIP_OFFSET)), map_size, PAGE_KERNEL); } #else -static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size) +static void __init create_kernel_page_table(pgd_t *pgdir, uintptr_t map_size, + bool early) { uintptr_t va, end_va; - end_va = kernel_virt_addr + load_sz; - for (va = kernel_virt_addr; va < end_va; va += map_size) + end_va = kernel_map.virt_addr + kernel_map.size; + for (va = kernel_map.virt_addr; va < end_va; va += map_size) create_pgd_mapping(pgdir, va, - load_pa + (va - kernel_virt_addr), - map_size, PAGE_KERNEL_EXEC); + kernel_map.phys_addr + (va - kernel_map.virt_addr), + map_size, + early ? + PAGE_KERNEL_EXEC : pgprot_from_va(va)); } #endif @@ -504,25 +538,27 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) pmd_t fix_bmap_spmd, fix_bmap_epmd; #endif + kernel_map.virt_addr = KERNEL_LINK_ADDR; + #ifdef CONFIG_XIP_KERNEL - xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR; - xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom); + kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR; + kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom); - load_pa = (uintptr_t)CONFIG_PHYS_RAM_BASE; - load_sz = (uintptr_t)(&_end) - (uintptr_t)(&_sdata); + kernel_map.phys_addr = (uintptr_t)CONFIG_PHYS_RAM_BASE; + kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_sdata); - va_kernel_xip_pa_offset = kernel_virt_addr - xiprom; + kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom; #else - load_pa = (uintptr_t)(&_start); - load_sz = (uintptr_t)(&_end) - load_pa; + kernel_map.phys_addr = (uintptr_t)(&_start); + kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr; #endif - va_pa_offset = PAGE_OFFSET - load_pa; + kernel_map.va_pa_offset = PAGE_OFFSET - kernel_map.phys_addr; #ifdef CONFIG_64BIT - va_kernel_pa_offset = kernel_virt_addr - load_pa; + kernel_map.va_kernel_pa_offset = kernel_map.virt_addr - kernel_map.phys_addr; #endif - pfn_base = PFN_DOWN(load_pa); + pfn_base = PFN_DOWN(kernel_map.phys_addr); /* * Enforce boot alignment requirements of RV32 and @@ -532,7 +568,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) /* Sanity check alignment and size */ BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0); - BUG_ON((load_pa % map_size) != 0); + BUG_ON((kernel_map.phys_addr % map_size) != 0); pt_ops.alloc_pte = alloc_pte_early; pt_ops.get_pte_virt = get_pte_virt_early; @@ -549,19 +585,19 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) create_pmd_mapping(fixmap_pmd, FIXADDR_START, (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE); /* Setup trampoline PGD and PMD */ - create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr, + create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr, (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE); #ifdef CONFIG_XIP_KERNEL - create_pmd_mapping(trampoline_pmd, kernel_virt_addr, - xiprom, PMD_SIZE, PAGE_KERNEL_EXEC); + create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr, + kernel_map.xiprom, PMD_SIZE, PAGE_KERNEL_EXEC); #else - create_pmd_mapping(trampoline_pmd, kernel_virt_addr, - load_pa, PMD_SIZE, PAGE_KERNEL_EXEC); + create_pmd_mapping(trampoline_pmd, kernel_map.virt_addr, + kernel_map.phys_addr, PMD_SIZE, PAGE_KERNEL_EXEC); #endif #else /* Setup trampoline PGD */ - create_pgd_mapping(trampoline_pg_dir, kernel_virt_addr, - load_pa, PGDIR_SIZE, PAGE_KERNEL_EXEC); + create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr, + kernel_map.phys_addr, PGDIR_SIZE, PAGE_KERNEL_EXEC); #endif /* @@ -569,7 +605,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) * us to reach paging_init(). We map all memory banks later * in setup_vm_final() below. */ - create_kernel_page_table(early_pg_dir, map_size); + create_kernel_page_table(early_pg_dir, map_size, true); #ifndef __PAGETABLE_PMD_FOLDED /* Setup early PMD for DTB */ @@ -645,22 +681,6 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) #endif } -#if defined(CONFIG_64BIT) && defined(CONFIG_STRICT_KERNEL_RWX) -void protect_kernel_linear_mapping_text_rodata(void) -{ - unsigned long text_start = (unsigned long)lm_alias(_start); - unsigned long init_text_start = (unsigned long)lm_alias(__init_text_begin); - unsigned long rodata_start = (unsigned long)lm_alias(__start_rodata); - unsigned long data_start = (unsigned long)lm_alias(_data); - - set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT); - set_memory_nx(text_start, (init_text_start - text_start) >> PAGE_SHIFT); - - set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); - set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); -} -#endif - static void __init setup_vm_final(void) { uintptr_t va, map_size; @@ -693,21 +713,15 @@ static void __init setup_vm_final(void) map_size = best_map_size(start, end - start); for (pa = start; pa < end; pa += map_size) { va = (uintptr_t)__va(pa); - create_pgd_mapping(swapper_pg_dir, va, pa, - map_size, -#ifdef CONFIG_64BIT - PAGE_KERNEL -#else - PAGE_KERNEL_EXEC -#endif - ); + create_pgd_mapping(swapper_pg_dir, va, pa, map_size, + pgprot_from_va(va)); } } #ifdef CONFIG_64BIT /* Map the kernel */ - create_kernel_page_table(swapper_pg_dir, PMD_SIZE); + create_kernel_page_table(swapper_pg_dir, PMD_SIZE, false); #endif /* Clear fixmap PTE and PMD mappings */ @@ -738,39 +752,6 @@ static inline void setup_vm_final(void) } #endif /* CONFIG_MMU */ -#ifdef CONFIG_STRICT_KERNEL_RWX -void __init protect_kernel_text_data(void) -{ - unsigned long text_start = (unsigned long)_start; - unsigned long init_text_start = (unsigned long)__init_text_begin; - unsigned long init_data_start = (unsigned long)__init_data_begin; - unsigned long rodata_start = (unsigned long)__start_rodata; - unsigned long data_start = (unsigned long)_data; -#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) - unsigned long end_va = kernel_virt_addr + load_sz; -#else - unsigned long end_va = (unsigned long)(__va(PFN_PHYS(max_low_pfn))); -#endif - - set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT); - set_memory_ro(init_text_start, (init_data_start - init_text_start) >> PAGE_SHIFT); - set_memory_nx(init_data_start, (rodata_start - init_data_start) >> PAGE_SHIFT); - /* rodata section is marked readonly in mark_rodata_ro */ - set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); - set_memory_nx(data_start, (end_va - data_start) >> PAGE_SHIFT); -} - -void mark_rodata_ro(void) -{ - unsigned long rodata_start = (unsigned long)__start_rodata; - unsigned long data_start = (unsigned long)_data; - - set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); - - debug_checkwx(); -} -#endif - #ifdef CONFIG_KEXEC_CORE /* * reserve_crashkernel() - reserves memory for crash kernel @@ -858,7 +839,7 @@ static void __init reserve_crashkernel(void) * reserved once we call early_init_fdt_scan_reserved_mem() * later on. */ -static int elfcore_hdr_setup(struct reserved_mem *rmem) +static int __init elfcore_hdr_setup(struct reserved_mem *rmem) { elfcorehdr_addr = rmem->base; elfcorehdr_size = rmem->size; @@ -870,8 +851,8 @@ RESERVEDMEM_OF_DECLARE(elfcorehdr, "linux,elfcorehdr", elfcore_hdr_setup); void __init paging_init(void) { + setup_bootmem(); setup_vm_final(); - setup_zero_page(); } void __init misc_mem_init(void) diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c index 35703d5ef5fd..e7fd0c253c7b 100644 --- a/arch/riscv/mm/physaddr.c +++ b/arch/riscv/mm/physaddr.c @@ -23,7 +23,7 @@ EXPORT_SYMBOL(__virt_to_phys); phys_addr_t __phys_addr_symbol(unsigned long x) { - unsigned long kernel_start = (unsigned long)kernel_virt_addr; + unsigned long kernel_start = kernel_map.virt_addr; unsigned long kernel_end = (unsigned long)_end; /* diff --git a/arch/riscv/mm/ptdump.c b/arch/riscv/mm/ptdump.c index 0536ac84b730..830e7de65e3a 100644 --- a/arch/riscv/mm/ptdump.c +++ b/arch/riscv/mm/ptdump.c @@ -98,8 +98,8 @@ static struct addr_marker address_markers[] = { {0, "vmalloc() end"}, {0, "Linear mapping"}, #ifdef CONFIG_64BIT - {0, "Modules mapping"}, - {0, "Kernel mapping (kernel, BPF)"}, + {0, "Modules/BPF mapping"}, + {0, "Kernel mapping"}, #endif {-1, NULL}, }; @@ -379,7 +379,7 @@ static int __init ptdump_init(void) address_markers[PAGE_OFFSET_NR].start_address = PAGE_OFFSET; #ifdef CONFIG_64BIT address_markers[MODULES_MAPPING_NR].start_address = MODULES_VADDR; - address_markers[KERNEL_MAPPING_NR].start_address = kernel_virt_addr; + address_markers[KERNEL_MAPPING_NR].start_address = kernel_map.virt_addr; #endif kernel_ptd_info.base_addr = KERN_VIRT_START; diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 720b443c4528..64f8201237c2 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -4,36 +4,66 @@ #include #include #include +#include + +static inline void local_flush_tlb_all_asid(unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma x0, %0" + : + : "r" (asid) + : "memory"); +} + +static inline void local_flush_tlb_page_asid(unsigned long addr, + unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma %0, %1" + : + : "r" (addr), "r" (asid) + : "memory"); +} void flush_tlb_all(void) { sbi_remote_sfence_vma(NULL, 0, -1); } -/* - * This function must not be called with cmask being null. - * Kernel may panic if cmask is NULL. - */ -static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start, - unsigned long size) +static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start, + unsigned long size, unsigned long stride) { + struct cpumask *cmask = mm_cpumask(mm); struct cpumask hmask; unsigned int cpuid; + bool broadcast; if (cpumask_empty(cmask)) return; cpuid = get_cpu(); + /* check if the tlbflush needs to be sent to other CPUs */ + broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids; + if (static_branch_unlikely(&use_asid_allocator)) { + unsigned long asid = atomic_long_read(&mm->context.id); - if (cpumask_any_but(cmask, cpuid) >= nr_cpu_ids) { - /* local cpu is the only cpu present in cpumask */ - if (size <= PAGE_SIZE) - local_flush_tlb_page(start); - else - local_flush_tlb_all(); + if (broadcast) { + riscv_cpuid_to_hartid_mask(cmask, &hmask); + sbi_remote_sfence_vma_asid(cpumask_bits(&hmask), + start, size, asid); + } else if (size <= stride) { + local_flush_tlb_page_asid(start, asid); + } else { + local_flush_tlb_all_asid(asid); + } } else { - riscv_cpuid_to_hartid_mask(cmask, &hmask); - sbi_remote_sfence_vma(cpumask_bits(&hmask), start, size); + if (broadcast) { + riscv_cpuid_to_hartid_mask(cmask, &hmask); + sbi_remote_sfence_vma(cpumask_bits(&hmask), + start, size); + } else if (size <= stride) { + local_flush_tlb_page(start); + } else { + local_flush_tlb_all(); + } } put_cpu(); @@ -41,16 +71,23 @@ static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start, void flush_tlb_mm(struct mm_struct *mm) { - __sbi_tlb_flush_range(mm_cpumask(mm), 0, -1); + __sbi_tlb_flush_range(mm, 0, -1, PAGE_SIZE); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), addr, PAGE_SIZE); + __sbi_tlb_flush_range(vma->vm_mm, addr, PAGE_SIZE, PAGE_SIZE); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), start, end - start); + __sbi_tlb_flush_range(vma->vm_mm, start, end - start, PAGE_SIZE); } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + __sbi_tlb_flush_range(vma->vm_mm, start, end - start, PMD_SIZE); +} +#endif diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 07b2328f29e0..a0e2130f0100 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -163,7 +163,6 @@ config S390 select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO select HAVE_IOREMAP_PROT if PCI - select HAVE_IRQ_EXIT_ON_IRQ_STACK select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZ4 @@ -438,6 +437,7 @@ config COMPAT select COMPAT_OLD_SIGACTION select HAVE_UID16 depends on MULTIUSER + depends on !CC_IS_CLANG help Select this option if you want to enable your system kernel to handle system-calls from ELF binaries for 31 bit ESA. This option diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 098abe3a56f3..1e3172877982 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -129,9 +129,6 @@ OBJCOPYFLAGS := -O binary head-y := arch/s390/kernel/head64.o -# See arch/s390/Kbuild for content of core part of the kernel -core-y += arch/s390/ - libs-y += arch/s390/lib/ drivers-y += drivers/s390/ @@ -166,6 +163,19 @@ archheaders: archprepare: $(Q)$(MAKE) $(build)=$(syscalls) kapi $(Q)$(MAKE) $(build)=$(tools) kapi +ifeq ($(KBUILD_EXTMOD),) +# We need to generate vdso-offsets.h before compiling certain files in kernel/. +# In order to do that, we should use the archprepare target, but we can't since +# asm-offsets.h is included in some files used to generate vdso-offsets.h, and +# asm-offsets.h is built in prepare0, for which archprepare is a dependency. +# Therefore we need to generate the header after prepare0 has been made, hence +# this hack. +prepare: vdso_prepare +vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h + $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \ + $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h) +endif # Don't use tabs in echo arguments define archhelp diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index bbe4df6c2f8b..d0cf21641e3a 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -23,6 +23,7 @@ unsigned long __bootdata_preserved(vmemmap_size); unsigned long __bootdata_preserved(MODULES_VADDR); unsigned long __bootdata_preserved(MODULES_END); unsigned long __bootdata(ident_map_size); +int __bootdata(is_full_image) = 1; u64 __bootdata_preserved(stfle_fac_list[16]); u64 __bootdata_preserved(alt_stfle_fac_list[16]); diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index 82b99b916243..f6b0c4f43c99 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -36,6 +36,7 @@ void uv_query_info(void) uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE); uv_info.max_num_sec_conf = uvcb.max_num_sec_conf; uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id; + uv_info.uv_feature_indications = uvcb.uv_feature_indications; } #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 837d1699b109..3afbee21dc1f 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -53,18 +53,20 @@ struct ap_queue_status { */ static inline bool ap_instructions_available(void) { - register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); - register unsigned long reg1 asm ("1") = 0; - register unsigned long reg2 asm ("2") = 0; + unsigned long reg0 = AP_MKQID(0, 0); + unsigned long reg1 = 0; asm volatile( - " .long 0xb2af0000\n" /* PQAP(TAPQ) */ - "0: la %0,1\n" + " lgr 0,%[reg0]\n" /* qid into gr0 */ + " lghi 1,0\n" /* 0 into gr1 */ + " lghi 2,0\n" /* 0 into gr2 */ + " .long 0xb2af0000\n" /* PQAP(TAPQ) */ + "0: la %[reg1],1\n" /* 1 into reg1 */ "1:\n" EX_TABLE(0b, 1b) - : "+d" (reg1), "+d" (reg2) - : "d" (reg0) - : "cc"); + : [reg1] "+&d" (reg1) + : [reg0] "d" (reg0) + : "cc", "0", "1", "2"); return reg1 != 0; } @@ -77,14 +79,18 @@ static inline bool ap_instructions_available(void) */ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) { - register unsigned long reg0 asm ("0") = qid; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2"); + struct ap_queue_status reg1; + unsigned long reg2; - asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ - : "=d" (reg1), "=d" (reg2) - : "d" (reg0) - : "cc"); + asm volatile( + " lgr 0,%[qid]\n" /* qid into gr0 */ + " lghi 2,0\n" /* 0 into gr2 */ + " .long 0xb2af0000\n" /* PQAP(TAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg2],2\n" /* gr2 into reg2 */ + : [reg1] "=&d" (reg1), [reg2] "=&d" (reg2) + : [qid] "d" (qid) + : "cc", "0", "1", "2"); if (info) *info = reg2; return reg1; @@ -115,14 +121,16 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, */ static inline struct ap_queue_status ap_rapq(ap_qid_t qid) { - register unsigned long reg0 asm ("0") = qid | (1UL << 24); - register struct ap_queue_status reg1 asm ("1"); + unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */ + struct ap_queue_status reg1; asm volatile( - ".long 0xb2af0000" /* PQAP(RAPQ) */ - : "=d" (reg1) - : "d" (reg0) - : "cc"); + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " .long 0xb2af0000\n" /* PQAP(RAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1) + : [reg0] "d" (reg0) + : "cc", "0", "1"); return reg1; } @@ -134,14 +142,16 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid) */ static inline struct ap_queue_status ap_zapq(ap_qid_t qid) { - register unsigned long reg0 asm ("0") = qid | (2UL << 24); - register struct ap_queue_status reg1 asm ("1"); + unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */ + struct ap_queue_status reg1; asm volatile( - ".long 0xb2af0000" /* PQAP(ZAPQ) */ - : "=d" (reg1) - : "d" (reg0) - : "cc"); + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " .long 0xb2af0000\n" /* PQAP(ZAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1) + : [reg0] "d" (reg0) + : "cc", "0", "1"); return reg1; } @@ -172,18 +182,20 @@ struct ap_config_info { */ static inline int ap_qci(struct ap_config_info *config) { - register unsigned long reg0 asm ("0") = 4UL << 24; - register unsigned long reg1 asm ("1") = -EOPNOTSUPP; - register struct ap_config_info *reg2 asm ("2") = config; + unsigned long reg0 = 4UL << 24; /* fc 4UL is QCI */ + unsigned long reg1 = -EOPNOTSUPP; + struct ap_config_info *reg2 = config; asm volatile( - ".long 0xb2af0000\n" /* PQAP(QCI) */ - "0: la %0,0\n" + " lgr 0,%[reg0]\n" /* QCI fc into gr0 */ + " lgr 2,%[reg2]\n" /* ptr to config into gr2 */ + " .long 0xb2af0000\n" /* PQAP(QCI) */ + "0: la %[reg1],0\n" /* good case, QCI fc available */ "1:\n" EX_TABLE(0b, 1b) - : "+d" (reg1) - : "d" (reg0), "d" (reg2) - : "cc", "memory"); + : [reg1] "+&d" (reg1) + : [reg0] "d" (reg0), [reg2] "d" (reg2) + : "cc", "memory", "0", "2"); return reg1; } @@ -220,21 +232,25 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, struct ap_qirq_ctrl qirqctrl, void *ind) { - register unsigned long reg0 asm ("0") = qid | (3UL << 24); - register union { + unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */ + union { unsigned long value; struct ap_qirq_ctrl qirqctrl; struct ap_queue_status status; - } reg1 asm ("1"); - register void *reg2 asm ("2") = ind; + } reg1; + void *reg2 = ind; reg1.qirqctrl = qirqctrl; asm volatile( - ".long 0xb2af0000" /* PQAP(AQIC) */ - : "+d" (reg1) - : "d" (reg0), "d" (reg2) - : "cc"); + " lgr 0,%[reg0]\n" /* qid param into gr0 */ + " lgr 1,%[reg1]\n" /* irq ctrl into gr1 */ + " lgr 2,%[reg2]\n" /* ni addr into gr2 */ + " .long 0xb2af0000\n" /* PQAP(AQIC) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "+&d" (reg1) + : [reg0] "d" (reg0), [reg2] "d" (reg2) + : "cc", "0", "1", "2"); return reg1.status; } @@ -268,21 +284,24 @@ union ap_qact_ap_info { static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, union ap_qact_ap_info *apinfo) { - register unsigned long reg0 asm ("0") = qid | (5UL << 24) - | ((ifbit & 0x01) << 22); - register union { + unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22); + union { unsigned long value; struct ap_queue_status status; - } reg1 asm ("1"); - register unsigned long reg2 asm ("2"); + } reg1; + unsigned long reg2; reg1.value = apinfo->val; asm volatile( - ".long 0xb2af0000" /* PQAP(QACT) */ - : "+d" (reg1), "=d" (reg2) - : "d" (reg0) - : "cc"); + " lgr 0,%[reg0]\n" /* qid param into gr0 */ + " lgr 1,%[reg1]\n" /* qact in info into gr1 */ + " .long 0xb2af0000\n" /* PQAP(QACT) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg2],2\n" /* qact out info into reg2 */ + : [reg1] "+&d" (reg1), [reg2] "=&d" (reg2) + : [reg0] "d" (reg0) + : "cc", "0", "1", "2"); apinfo->val = reg2; return reg1.status; } @@ -303,19 +322,24 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) { - register unsigned long reg0 asm ("0") = qid | 0x40000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = (unsigned long) msg; - register unsigned long reg3 asm ("3") = (unsigned long) length; - register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); - register unsigned long reg5 asm ("5") = psmid & 0xffffffff; + unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */ + union register_pair nqap_r1, nqap_r2; + struct ap_queue_status reg1; + + nqap_r1.even = (unsigned int)(psmid >> 32); + nqap_r1.odd = psmid & 0xffffffff; + nqap_r2.even = (unsigned long)msg; + nqap_r2.odd = (unsigned long)length; asm volatile ( - "0: .long 0xb2ad0042\n" /* NQAP */ - " brc 2,0b" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) - : "d" (reg4), "d" (reg5) - : "cc", "memory"); + " lgr 0,%[reg0]\n" /* qid param in gr0 */ + "0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n" + " brc 2,0b\n" /* handle partial completion */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), + [nqap_r2] "+&d" (nqap_r2.pair) + : [nqap_r1] "d" (nqap_r1.pair) + : "cc", "memory", "0", "1"); return reg1; } @@ -325,6 +349,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * @psmid: Pointer to program supplied message identifier * @msg: The message text * @length: The message length + * @reslength: Resitual length on return + * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content * * Returns AP queue status structure. * Condition code 1 on DQAP means the receive has taken place @@ -336,27 +362,65 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * Note that gpr2 is used by the DQAP instruction to keep track of * any 'residual' length, in case the instruction gets interrupted. * Hence it gets zeroed before the instruction. + * If the message does not fit into the buffer, this function will + * return with a truncated message and the reply in the firmware queue + * is not removed. This is indicated to the caller with an + * ap_queue_status response_code value of all bits on (0xFF) and (if + * the reslength ptr is given) the remaining length is stored in + * *reslength and (if the resgr0 ptr is given) the updated gr0 value + * for further processing of this msg entry is stored in *resgr0. The + * caller needs to detect this situation and should invoke ap_dqap + * with a valid resgr0 ptr and a value in there != 0 to indicate that + * *resgr0 is to be used instead of qid to further process this entry. */ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, unsigned long long *psmid, - void *msg, size_t length) + void *msg, size_t length, + size_t *reslength, + unsigned long *resgr0) { - register unsigned long reg0 asm("0") = qid | 0x80000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm("2") = 0UL; - register unsigned long reg4 asm("4") = (unsigned long) msg; - register unsigned long reg5 asm("5") = (unsigned long) length; - register unsigned long reg6 asm("6") = 0UL; - register unsigned long reg7 asm("7") = 0UL; + unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL; + struct ap_queue_status reg1; + unsigned long reg2; + union register_pair rp1, rp2; + rp1.even = 0UL; + rp1.odd = 0UL; + rp2.even = (unsigned long)msg; + rp2.odd = (unsigned long)length; asm volatile( - "0: .long 0xb2ae0064\n" /* DQAP */ - " brc 6,0b\n" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), - "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7) - : : "cc", "memory"); - *psmid = (((unsigned long long) reg6) << 32) + reg7; + " lgr 0,%[reg0]\n" /* qid param into gr0 */ + " lghi 2,0\n" /* 0 into gr2 (res length) */ + "0: ltgr %N[rp2],%N[rp2]\n" /* check buf len */ + " jz 2f\n" /* go out if buf len is 0 */ + "1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n" + " brc 6,0b\n" /* handle partial complete */ + "2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg2],2\n" /* gr2 (res length) into reg2 */ + : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [reg2] "=&d" (reg2), + [rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair) + : + : "cc", "memory", "0", "1", "2"); + + if (reslength) + *reslength = reg2; + if (reg2 != 0 && rp2.odd == 0) { + /* + * Partially complete, status in gr1 is not set. + * Signal the caller that this dqap is only partially received + * with a special status response code 0xFF and *resgr0 updated + */ + reg1.response_code = 0xFF; + if (resgr0) + *resgr0 = reg0; + } else { + *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd; + if (resgr0) + *resgr0 = 0; + } + return reg1; } diff --git a/arch/s390/include/asm/cpu_mcf.h b/arch/s390/include/asm/cpu_mcf.h index 4dcefddb7751..ca0e0e5ddbc4 100644 --- a/arch/s390/include/asm/cpu_mcf.h +++ b/arch/s390/include/asm/cpu_mcf.h @@ -32,39 +32,22 @@ static const u64 cpumf_ctr_ctl[CPUMF_CTR_SET_MAX] = { [CPUMF_CTR_SET_MT_DIAG] = 0x20, }; -static inline void ctr_set_enable(u64 *state, int ctr_set) -{ - *state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT; -} -static inline void ctr_set_disable(u64 *state, int ctr_set) -{ - *state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT); -} -static inline void ctr_set_start(u64 *state, int ctr_set) -{ - *state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT; -} -static inline void ctr_set_stop(u64 *state, int ctr_set) -{ - *state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT); -} - -static inline void ctr_set_multiple_enable(u64 *state, u64 ctrsets) +static inline void ctr_set_enable(u64 *state, u64 ctrsets) { *state |= ctrsets << CPUMF_LCCTL_ENABLE_SHIFT; } -static inline void ctr_set_multiple_disable(u64 *state, u64 ctrsets) +static inline void ctr_set_disable(u64 *state, u64 ctrsets) { *state &= ~(ctrsets << CPUMF_LCCTL_ENABLE_SHIFT); } -static inline void ctr_set_multiple_start(u64 *state, u64 ctrsets) +static inline void ctr_set_start(u64 *state, u64 ctrsets) { *state |= ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT; } -static inline void ctr_set_multiple_stop(u64 *state, u64 ctrsets) +static inline void ctr_set_stop(u64 *state, u64 ctrsets) { *state &= ~(ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT); } @@ -92,8 +75,15 @@ struct cpu_cf_events { struct cpumf_ctr_info info; atomic_t ctr_set[CPUMF_CTR_SET_MAX]; atomic64_t alert; - u64 state; + u64 state; /* For perf_event_open SVC */ + u64 dev_state; /* For /dev/hwctr */ unsigned int flags; + size_t used; /* Bytes used in data */ + size_t usedss; /* Bytes used in start/stop */ + unsigned char start[PAGE_SIZE]; /* Counter set at event add */ + unsigned char stop[PAGE_SIZE]; /* Counter set at event delete */ + unsigned char data[PAGE_SIZE]; /* Counter set at /dev/hwctr */ + unsigned int sets; /* # Counter set saved in memory */ }; DECLARE_PER_CPU(struct cpu_cf_events, cpu_cf_events); @@ -124,4 +114,6 @@ static inline int stccm_avail(void) size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset, struct cpumf_ctr_info *info); +int cfset_online_cpu(unsigned int cpu); +int cfset_offline_cpu(unsigned int cpu); #endif /* _ASM_S390_CPU_MCF_H */ diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index ed5efbb531c4..adc0179fa34e 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -21,8 +21,6 @@ #define CR0_INTERRUPT_KEY_SUBMASK BIT(63 - 57) #define CR0_MEASUREMENT_ALERT_SUBMASK BIT(63 - 58) -#define CR2_GUARDED_STORAGE BIT(63 - 59) - #define CR14_UNUSED_32 BIT(63 - 32) #define CR14_UNUSED_33 BIT(63 - 33) #define CR14_CHANNEL_REPORT_SUBMASK BIT(63 - 35) diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 66d51ad090ab..bd00c94620d3 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -144,10 +144,6 @@ typedef s390_compat_regs compat_elf_gregset_t; #include /* for task_struct */ #include -#include - -extern unsigned int vdso_enabled; - /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -176,7 +172,7 @@ struct arch_elf_state { !current->mm->context.alloc_pgste) { \ set_thread_flag(TIF_PGSTE); \ set_pt_regs_flag(task_pt_regs(current), \ - PIF_SYSCALL_RESTART); \ + PIF_EXECVE_PGSTE_RESTART); \ _state->rc = -EAGAIN; \ } \ _state->rc; \ @@ -268,11 +264,10 @@ do { \ #define STACK_RND_MASK MMAP_RND_MASK /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ -#define ARCH_DLINFO \ -do { \ - if (vdso_enabled) \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long)current->mm->context.vdso_base); \ +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, \ + (unsigned long)current->mm->context.vdso_base); \ } while (0) struct linux_binprm; diff --git a/arch/s390/include/asm/entry-common.h b/arch/s390/include/asm/entry-common.h index baa8005090c3..17aead80aadb 100644 --- a/arch/s390/include/asm/entry-common.h +++ b/arch/s390/include/asm/entry-common.h @@ -14,7 +14,6 @@ #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_GUARDED_STORAGE | _TIF_PER_TRAP) void do_per_trap(struct pt_regs *regs); -void do_syscall(struct pt_regs *regs); #ifdef CONFIG_DEBUG_ENTRY static __always_inline void arch_check_user_regs(struct pt_regs *regs) diff --git a/arch/s390/include/asm/linkage.h b/arch/s390/include/asm/linkage.h index a0a7a2c72bd4..24e8fed150cf 100644 --- a/arch/s390/include/asm/linkage.h +++ b/arch/s390/include/asm/linkage.h @@ -5,7 +5,7 @@ #include #include -#define __ALIGN .align 4, 0x07 +#define __ALIGN .align 16, 0x07 #define __ALIGN_STR __stringify(__ALIGN) /* diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h index 20e51c9ff240..2db45d7e68aa 100644 --- a/arch/s390/include/asm/nmi.h +++ b/arch/s390/include/asm/nmi.h @@ -23,12 +23,16 @@ #define MCCK_CODE_SYSTEM_DAMAGE BIT(63) #define MCCK_CODE_EXT_DAMAGE BIT(63 - 5) #define MCCK_CODE_CP BIT(63 - 9) -#define MCCK_CODE_CPU_TIMER_VALID BIT(63 - 46) +#define MCCK_CODE_STG_ERROR BIT(63 - 16) +#define MCCK_CODE_STG_KEY_ERROR BIT(63 - 18) +#define MCCK_CODE_STG_DEGRAD BIT(63 - 19) #define MCCK_CODE_PSW_MWP_VALID BIT(63 - 20) #define MCCK_CODE_PSW_IA_VALID BIT(63 - 23) +#define MCCK_CODE_STG_FAIL_ADDR BIT(63 - 24) #define MCCK_CODE_CR_VALID BIT(63 - 29) #define MCCK_CODE_GS_VALID BIT(63 - 36) #define MCCK_CODE_FC_VALID BIT(63 - 43) +#define MCCK_CODE_CPU_TIMER_VALID BIT(63 - 46) #ifndef __ASSEMBLY__ diff --git a/arch/s390/include/asm/preempt.h b/arch/s390/include/asm/preempt.h index 23ff51be7e29..d9d5350cc3ec 100644 --- a/arch/s390/include/asm/preempt.h +++ b/arch/s390/include/asm/preempt.h @@ -29,12 +29,6 @@ static inline void preempt_count_set(int pc) old, new) != old); } -#define init_task_preempt_count(p) do { } while (0) - -#define init_idle_preempt_count(p, cpu) do { \ - S390_lowcore.preempt_count = PREEMPT_DISABLED; \ -} while (0) - static inline void set_preempt_need_resched(void) { __atomic_and(~PREEMPT_NEED_RESCHED, &S390_lowcore.preempt_count); @@ -88,12 +82,6 @@ static inline void preempt_count_set(int pc) S390_lowcore.preempt_count = pc; } -#define init_task_preempt_count(p) do { } while (0) - -#define init_idle_preempt_count(p, cpu) do { \ - S390_lowcore.preempt_count = PREEMPT_DISABLED; \ -} while (0) - static inline void set_preempt_need_resched(void) { } @@ -130,6 +118,10 @@ static inline bool should_resched(int preempt_offset) #endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */ +#define init_task_preempt_count(p) do { } while (0) +/* Deferred to CPU bringup time */ +#define init_idle_preempt_count(p, cpu) do { } while (0) + #ifdef CONFIG_PREEMPTION extern void preempt_schedule(void); #define __preempt_schedule() preempt_schedule() diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index c7850d649373..61b22aa990e7 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -11,15 +11,15 @@ #include #include -#define PIF_SYSCALL 0 /* inside a system call */ -#define PIF_SYSCALL_RESTART 1 /* restart the current system call */ -#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */ -#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */ +#define PIF_SYSCALL 0 /* inside a system call */ +#define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */ +#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */ +#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */ -#define _PIF_SYSCALL BIT(PIF_SYSCALL) -#define _PIF_SYSCALL_RESTART BIT(PIF_SYSCALL_RESTART) -#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET) -#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT) +#define _PIF_SYSCALL BIT(PIF_SYSCALL) +#define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART) +#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET) +#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT) #ifndef __ASSEMBLY__ @@ -162,6 +162,14 @@ static inline int test_pt_regs_flag(struct pt_regs *regs, int flag) return !!(regs->flags & (1UL << flag)); } +static inline int test_and_clear_pt_regs_flag(struct pt_regs *regs, int flag) +{ + int ret = test_pt_regs_flag(regs, flag); + + clear_pt_regs_flag(regs, flag); + return ret; +} + /* * These are defined as per linux/ptrace.h, which see. */ diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index a8b75da3c1b8..3a77aa96d092 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -159,6 +159,8 @@ static inline unsigned long kaslr_offset(void) return __kaslr_offset; } +extern int is_full_image; + static inline u32 gen_lpswe(unsigned long addr) { BUILD_BUG_ON(addr > 0xfff); diff --git a/arch/s390/include/asm/softirq_stack.h b/arch/s390/include/asm/softirq_stack.h new file mode 100644 index 000000000000..fd17f25704bd --- /dev/null +++ b/arch/s390/include/asm/softirq_stack.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __ASM_S390_SOFTIRQ_STACK_H +#define __ASM_S390_SOFTIRQ_STACK_H + +#include +#include + +static inline void do_softirq_own_stack(void) +{ + call_on_stack(0, S390_lowcore.async_stack, void, __do_softirq); +} + +#endif /* __ASM_S390_SOFTIRQ_STACK_H */ diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index 76c6034428be..3d8a4b94c620 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -74,23 +74,6 @@ struct stack_frame { ((unsigned long)__builtin_frame_address(0) - \ offsetof(struct stack_frame, back_chain)) -#define CALL_ARGS_0() \ - register unsigned long r2 asm("2") -#define CALL_ARGS_1(arg1) \ - register unsigned long r2 asm("2") = (unsigned long)(arg1) -#define CALL_ARGS_2(arg1, arg2) \ - CALL_ARGS_1(arg1); \ - register unsigned long r3 asm("3") = (unsigned long)(arg2) -#define CALL_ARGS_3(arg1, arg2, arg3) \ - CALL_ARGS_2(arg1, arg2); \ - register unsigned long r4 asm("4") = (unsigned long)(arg3) -#define CALL_ARGS_4(arg1, arg2, arg3, arg4) \ - CALL_ARGS_3(arg1, arg2, arg3); \ - register unsigned long r4 asm("5") = (unsigned long)(arg4) -#define CALL_ARGS_5(arg1, arg2, arg3, arg4, arg5) \ - CALL_ARGS_4(arg1, arg2, arg3, arg4); \ - register unsigned long r4 asm("6") = (unsigned long)(arg5) - /* * To keep this simple mark register 2-6 as being changed (volatile) * by the called function, even though register 6 is saved/nonvolatile. @@ -109,34 +92,113 @@ struct stack_frame { #define CALL_CLOBBER_1 CALL_CLOBBER_2, "3" #define CALL_CLOBBER_0 CALL_CLOBBER_1 -#define CALL_ON_STACK(fn, stack, nr, args...) \ +#define CALL_LARGS_0(...) \ + long dummy = 0 +#define CALL_LARGS_1(t1, a1) \ + long arg1 = (long)(t1)(a1) +#define CALL_LARGS_2(t1, a1, t2, a2) \ + CALL_LARGS_1(t1, a1); \ + long arg2 = (long)(t2)(a2) +#define CALL_LARGS_3(t1, a1, t2, a2, t3, a3) \ + CALL_LARGS_2(t1, a1, t2, a2); \ + long arg3 = (long)(t3)(a3) +#define CALL_LARGS_4(t1, a1, t2, a2, t3, a3, t4, a4) \ + CALL_LARGS_3(t1, a1, t2, a2, t3, a3); \ + long arg4 = (long)(t4)(a4) +#define CALL_LARGS_5(t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \ + CALL_LARGS_4(t1, a1, t2, a2, t3, a3, t4, a4); \ + long arg5 = (long)(t5)(a5) + +#define CALL_REGS_0 \ + register long r2 asm("2") = dummy +#define CALL_REGS_1 \ + register long r2 asm("2") = arg1 +#define CALL_REGS_2 \ + CALL_REGS_1; \ + register long r3 asm("3") = arg2 +#define CALL_REGS_3 \ + CALL_REGS_2; \ + register long r4 asm("4") = arg3 +#define CALL_REGS_4 \ + CALL_REGS_3; \ + register long r5 asm("5") = arg4 +#define CALL_REGS_5 \ + CALL_REGS_4; \ + register long r6 asm("6") = arg5 + +#define CALL_TYPECHECK_0(...) +#define CALL_TYPECHECK_1(t, a, ...) \ + typecheck(t, a) +#define CALL_TYPECHECK_2(t, a, ...) \ + CALL_TYPECHECK_1(__VA_ARGS__); \ + typecheck(t, a) +#define CALL_TYPECHECK_3(t, a, ...) \ + CALL_TYPECHECK_2(__VA_ARGS__); \ + typecheck(t, a) +#define CALL_TYPECHECK_4(t, a, ...) \ + CALL_TYPECHECK_3(__VA_ARGS__); \ + typecheck(t, a) +#define CALL_TYPECHECK_5(t, a, ...) \ + CALL_TYPECHECK_4(__VA_ARGS__); \ + typecheck(t, a) + +#define CALL_PARM_0(...) void +#define CALL_PARM_1(t, a, ...) t +#define CALL_PARM_2(t, a, ...) t, CALL_PARM_1(__VA_ARGS__) +#define CALL_PARM_3(t, a, ...) t, CALL_PARM_2(__VA_ARGS__) +#define CALL_PARM_4(t, a, ...) t, CALL_PARM_3(__VA_ARGS__) +#define CALL_PARM_5(t, a, ...) t, CALL_PARM_4(__VA_ARGS__) +#define CALL_PARM_6(t, a, ...) t, CALL_PARM_5(__VA_ARGS__) + +/* + * Use call_on_stack() to call a function switching to a specified + * stack. Proper sign and zero extension of function arguments is + * done. Usage: + * + * rc = call_on_stack(nr, stack, rettype, fn, t1, a1, t2, a2, ...) + * + * - nr specifies the number of function arguments of fn. + * - stack specifies the stack to be used. + * - fn is the function to be called. + * - rettype is the return type of fn. + * - t1, a1, ... are pairs, where t1 must match the type of the first + * argument of fn, t2 the second, etc. a1 is the corresponding + * first function argument (not name), etc. + */ +#define call_on_stack(nr, stack, rettype, fn, ...) \ ({ \ + rettype (*__fn)(CALL_PARM_##nr(__VA_ARGS__)) = fn; \ unsigned long frame = current_frame_address(); \ - CALL_ARGS_##nr(args); \ + unsigned long __stack = stack; \ unsigned long prev; \ + CALL_LARGS_##nr(__VA_ARGS__); \ + CALL_REGS_##nr; \ \ + CALL_TYPECHECK_##nr(__VA_ARGS__); \ asm volatile( \ - " la %[_prev],0(15)\n" \ + " lgr %[_prev],15\n" \ " lg 15,%[_stack]\n" \ " stg %[_frame],%[_bc](15)\n" \ " brasl 14,%[_fn]\n" \ - " la 15,0(%[_prev])\n" \ - : [_prev] "=&a" (prev), CALL_FMT_##nr \ - : [_stack] "R" (stack), \ + " lgr 15,%[_prev]\n" \ + : [_prev] "=&d" (prev), CALL_FMT_##nr \ + : [_stack] "R" (__stack), \ [_bc] "i" (offsetof(struct stack_frame, back_chain)), \ [_frame] "d" (frame), \ - [_fn] "X" (fn) : CALL_CLOBBER_##nr); \ - r2; \ + [_fn] "X" (__fn) : CALL_CLOBBER_##nr); \ + (rettype)r2; \ }) -#define CALL_ON_STACK_NORETURN(fn, stack) \ +#define call_on_stack_noreturn(fn, stack) \ ({ \ + void (*__fn)(void) = fn; \ + \ asm volatile( \ " la 15,0(%[_stack])\n" \ " xc %[_bc](8,15),%[_bc](15)\n" \ " brasl 14,%[_fn]\n" \ ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \ - [_stack] "a" (stack), [_fn] "X" (fn)); \ + [_stack] "a" (stack), [_fn] "X" (__fn)); \ BUG(); \ }) diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 7b98d4caee77..12c5f006c136 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -73,6 +73,10 @@ enum uv_cmds_inst { BIT_UVC_CMD_UNPIN_PAGE_SHARED = 22, }; +enum uv_feat_ind { + BIT_UV_FEAT_MISC = 0, +}; + struct uv_cb_header { u16 len; u16 cmd; /* Command Code */ @@ -97,7 +101,8 @@ struct uv_cb_qui { u64 max_guest_stor_addr; u8 reserved88[158 - 136]; u16 max_guest_cpu_id; - u8 reserveda0[200 - 160]; + u64 uv_feature_indications; + u8 reserveda0[200 - 168]; } __packed __aligned(8); /* Initialize Ultravisor */ @@ -274,6 +279,7 @@ struct uv_info { unsigned long max_sec_stor_addr; unsigned int max_num_sec_conf; unsigned short max_guest_cpu_id; + unsigned long uv_feature_indications; }; extern struct uv_info uv_info; diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index b45e3dddd2c2..53165aa7813a 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -4,18 +4,31 @@ #include -/* Default link address for the vDSO */ -#define VDSO64_LBASE 0 - -#define __VVAR_PAGES 2 - -#define VDSO_VERSION_STRING LINUX_2.6.29 - #ifndef __ASSEMBLY__ +#include +#ifdef CONFIG_COMPAT +#include +#endif + +#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name)) +#ifdef CONFIG_COMPAT +#define VDSO32_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso32_offset_##name)) +#else +#define VDSO32_SYMBOL(tsk, name) (-1UL) +#endif + extern struct vdso_data *vdso_data; int vdso_getcpu_init(void); #endif /* __ASSEMBLY__ */ + +/* Default link address for the vDSO */ +#define VDSO_LBASE 0 + +#define __VVAR_PAGES 2 + +#define VDSO_VERSION_STRING LINUX_2.6.29 + #endif /* __S390_VDSO_H__ */ diff --git a/arch/s390/include/asm/vdso/gettimeofday.h b/arch/s390/include/asm/vdso/gettimeofday.h index 383c53c3dddd..d6465b22ffe3 100644 --- a/arch/s390/include/asm/vdso/gettimeofday.h +++ b/arch/s390/include/asm/vdso/gettimeofday.h @@ -8,7 +8,6 @@ #include #include -#include #include #define vdso_calc_delta __arch_vdso_calc_delta diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 68ca1834316f..4a44ba5a2d73 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -71,10 +71,10 @@ obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_arch.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf_common.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o -obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_diag.o obj-$(CONFIG_TRACEPOINTS) += trace.o obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) += uv.o # vdso obj-y += vdso64/ +obj-$(CONFIG_COMPAT) += vdso32/ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index f53605a3dfcd..77ff2130cb04 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include int main(void) @@ -108,7 +106,6 @@ int main(void) OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock); OFFSET(__LC_INT_CLOCK, lowcore, int_clock); OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock); - OFFSET(__LC_CLOCK_COMPARATOR, lowcore, clock_comparator); OFFSET(__LC_BOOT_CLOCK, lowcore, boot_clock); OFFSET(__LC_CURRENT, lowcore, current_task); OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack); @@ -145,9 +142,6 @@ int main(void) OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area); OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb); BLANK(); - /* extended machine check save area */ - OFFSET(__MCESA_GS_SAVE_AREA, mcesa, guarded_storage_save_area); - BLANK(); /* gmap/sie offsets */ OFFSET(__GMAP_ASCE, gmap, asce); OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 1d0e17ec93eb..cca142fbb516 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "compat_linux.h" #include "compat_ptrace.h" #include "entry.h" @@ -118,7 +119,6 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) fpregs_load((_s390_fp_regs *) &user_sregs.fpregs, ¤t->thread.fpu); clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ - clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART); return 0; } @@ -304,11 +304,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, restorer = (unsigned long __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; } else { - /* Signal frames without vectors registers are short ! */ - __u16 __user *svc = (void __user *) frame + frame_size - 2; - if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) - return -EFAULT; - restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; + restorer = VDSO32_SYMBOL(current, sigreturn); } /* Set up registers for signal handler */ @@ -371,10 +367,7 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, restorer = (unsigned long __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; } else { - __u16 __user *svc = &frame->svc_insn; - if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc)) - return -EFAULT; - restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; + restorer = VDSO32_SYMBOL(current, rt_sigreturn); } /* Create siginfo on the signal stack */ diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index c2cf79d353cf..fb84e3fc1686 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -33,6 +33,8 @@ #include #include "entry.h" +int __bootdata(is_full_image); + static void __init reset_tod_clock(void) { union tod_clock clk; @@ -279,7 +281,7 @@ static void __init setup_boot_command_line(void) static void __init check_image_bootable(void) { - if (!memcmp(EP_STRING, (void *)EP_OFFSET, strlen(EP_STRING))) + if (is_full_image) return; sclp_early_printk("Linux kernel boot failure: An attempt to boot a vmlinux ELF image failed.\n"); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 3e8c6669373a..5a2f70cbd3a9 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -129,6 +128,24 @@ _LPP_OFFSET = __LC_LPP "jnz .+8; .long 0xb2e8d000", 82 .endm + /* + * The CHKSTG macro jumps to the provided label in case the + * machine check interruption code reports one of unrecoverable + * storage errors: + * - Storage error uncorrected + * - Storage key error uncorrected + * - Storage degradation with Failing-storage-address validity + */ + .macro CHKSTG errlabel + TSTMSK __LC_MCCK_CODE,(MCCK_CODE_STG_ERROR|MCCK_CODE_STG_KEY_ERROR) + jnz \errlabel + TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_DEGRAD + jz oklabel\@ + TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_FAIL_ADDR + jnz \errlabel +oklabel\@: + .endm + #if IS_ENABLED(CONFIG_KVM) /* * The OUTSIDE macro jumps to the provided label in case the value @@ -148,6 +165,13 @@ _LPP_OFFSET = __LC_LPP clgr %r14,%r13 jhe \outside_label .endm + + .macro SIEEXIT + lg %r9,__SF_SIE_CONTROL(%r15) # get control block pointer + ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE + lctlg %c1,%c1,__LC_KERNEL_ASCE # load primary asce + larl %r9,sie_exit # skip forward to sie_exit + .endm #endif GEN_BR_THUNK %r14 @@ -235,7 +259,6 @@ ENTRY(sie64a) # are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable. # Other instructions between sie64a and .Lsie_done should not cause program # interrupts. So lets use 3 nops as a landing pad for all possible rewinds. -# See also .Lcleanup_sie .Lrewind_pad6: nopr 7 .Lrewind_pad4: @@ -341,10 +364,7 @@ ENTRY(pgm_check_handler) #if IS_ENABLED(CONFIG_KVM) # cleanup critical section for program checks in sie64a OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f - lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer - ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE - lctlg %c1,%c1,__LC_KERNEL_ASCE # load primary asce - larl %r9,sie_exit # skip forward to sie_exit + SIEEXIT lghi %r10,_PIF_GUEST_FAULT #endif 1: tmhh %r8,0x4000 # PER bit set in old PSW ? @@ -410,7 +430,8 @@ ENTRY(\name) jnz 1f #if IS_ENABLED(CONFIG_KVM) OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f - brasl %r14,.Lcleanup_sie + BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + SIEEXIT #endif 0: CHECK_STACK __LC_SAVE_AREA_ASYNC aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) @@ -484,8 +505,6 @@ ENTRY(mcck_int_handler) BPOFF la %r1,4095 # validate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer - sckc __LC_CLOCK_COMPARATOR # validate comparator - lam %a0,%a15,__LC_AREGS_SAVE_AREA-4095(%r1) # validate acrs lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs lg %r12,__LC_CURRENT lmg %r8,%r9,__LC_MCK_OLD_PSW @@ -496,41 +515,7 @@ ENTRY(mcck_int_handler) la %r14,4095 lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs ptlb - lg %r11,__LC_MCESAD-4095(%r14) # extended machine check save area - nill %r11,0xfc00 # MCESA_ORIGIN_MASK - TSTMSK __LC_CREGS_SAVE_AREA+16-4095(%r14),CR2_GUARDED_STORAGE - jno 0f - TSTMSK __LC_MCCK_CODE,MCCK_CODE_GS_VALID - jno 0f - .insn rxy,0xe3000000004d,0,__MCESA_GS_SAVE_AREA(%r11) # LGSC -0: l %r14,__LC_FP_CREG_SAVE_AREA-4095(%r14) - TSTMSK __LC_MCCK_CODE,MCCK_CODE_FC_VALID - jo 0f - sr %r14,%r14 -0: sfpc %r14 - TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX - jo 0f - lghi %r14,__LC_FPREGS_SAVE_AREA - ld %f0,0(%r14) - ld %f1,8(%r14) - ld %f2,16(%r14) - ld %f3,24(%r14) - ld %f4,32(%r14) - ld %f5,40(%r14) - ld %f6,48(%r14) - ld %f7,56(%r14) - ld %f8,64(%r14) - ld %f9,72(%r14) - ld %f10,80(%r14) - ld %f11,88(%r14) - ld %f12,96(%r14) - ld %f13,104(%r14) - ld %f14,112(%r14) - ld %f15,120(%r14) - j 1f -0: VLM %v0,%v15,0,%r11 - VLM %v16,%v31,256,%r11 -1: lghi %r14,__LC_CPU_TIMER_SAVE_AREA + lghi %r14,__LC_CPU_TIMER_SAVE_AREA mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) TSTMSK __LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID jo 3f @@ -546,24 +531,29 @@ ENTRY(mcck_int_handler) 3: TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_MWP_VALID jno .Lmcck_panic tmhh %r8,0x0001 # interrupting from user ? - jnz 4f + jnz 6f TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID jno .Lmcck_panic -4: ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off - tmhh %r8,0x0001 # interrupting from user ? - jnz .Lmcck_user #if IS_ENABLED(CONFIG_KVM) - OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack - OUTSIDE %r9,.Lsie_entry,.Lsie_skip,5f + OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f + OUTSIDE %r9,.Lsie_entry,.Lsie_skip,4f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST -5: brasl %r14,.Lcleanup_sie -#endif + j 5f +4: CHKSTG .Lmcck_panic +5: larl %r14,.Lstosm_tmp + stosm 0(%r14),0x04 # turn dat on, keep irqs off + BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + SIEEXIT j .Lmcck_stack -.Lmcck_user: +#endif +6: CHKSTG .Lmcck_panic + larl %r14,.Lstosm_tmp + stosm 0(%r14),0x04 # turn dat on, keep irqs off + tmhh %r8,0x0001 # interrupting from user ? + jz .Lmcck_stack BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP .Lmcck_stack: lg %r15,__LC_MCCK_STACK -.Lmcck_skip: la %r11,STACK_FRAME_OVERHEAD(%r15) stctg %c1,%c1,__PT_CR1(%r11) lctlg %c1,%c1,__LC_KERNEL_ASCE @@ -605,8 +595,33 @@ ENTRY(mcck_int_handler) b __LC_RETURN_MCCK_LPSWE .Lmcck_panic: - lg %r15,__LC_NODAT_STACK - j .Lmcck_skip + /* + * Iterate over all possible CPU addresses in the range 0..0xffff + * and stop each CPU using signal processor. Use compare and swap + * to allow just one CPU-stopper and prevent concurrent CPUs from + * stopping each other while leaving the others running. + */ + lhi %r5,0 + lhi %r6,1 + larl %r7,.Lstop_lock + cs %r5,%r6,0(%r7) # single CPU-stopper only + jnz 4f + larl %r7,.Lthis_cpu + stap 0(%r7) # this CPU address + lh %r4,0(%r7) + nilh %r4,0 + lhi %r0,1 + sll %r0,16 # CPU counter + lhi %r3,0 # next CPU address +0: cr %r3,%r4 + je 2f +1: sigp %r1,%r3,SIGP_STOP # stop next CPU + brc SIGP_CC_BUSY,1b +2: ahi %r3,1 + brct %r0,0b +3: sigp %r1,%r4,SIGP_STOP # stop this CPU + brc SIGP_CC_BUSY,3b +4: j 4b ENDPROC(mcck_int_handler) # @@ -657,15 +672,11 @@ ENTRY(stack_overflow) ENDPROC(stack_overflow) #endif -#if IS_ENABLED(CONFIG_KVM) -.Lcleanup_sie: - BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) - lg %r9,__SF_SIE_CONTROL(%r15) # get control block pointer - ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE - lctlg %c1,%c1,__LC_KERNEL_ASCE - larl %r9,sie_exit # skip forward to sie_exit - BR_EX %r14,%r13 -#endif + .section .data, "aw" + .align 4 +.Lstop_lock: .long 0 +.Lthis_cpu: .short 0 +.Lstosm_tmp: .byte 0 .section .rodata, "a" #define SYSCALL(esame,emu) .quad __s390x_ ## esame .globl sys_call_table diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index c0df4060d28d..234d085257eb 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -110,15 +110,17 @@ static int on_async_stack(void) { unsigned long frame = current_frame_address(); - return !!!((S390_lowcore.async_stack - frame) >> (PAGE_SHIFT + THREAD_SIZE_ORDER)); + return ((S390_lowcore.async_stack ^ frame) & ~(THREAD_SIZE - 1)) == 0; } static void do_irq_async(struct pt_regs *regs, int irq) { - if (on_async_stack()) + if (on_async_stack()) { do_IRQ(regs, irq); - else - CALL_ON_STACK(do_IRQ, S390_lowcore.async_stack, 2, regs, irq); + } else { + call_on_stack(2, S390_lowcore.async_stack, void, do_IRQ, + struct pt_regs *, regs, int, irq); + } } static int irq_pending(struct pt_regs *regs) @@ -265,24 +267,6 @@ unsigned int arch_dynirq_lower_bound(unsigned int from) return from < NR_IRQS_BASE ? NR_IRQS_BASE : from; } -/* - * Switch to the asynchronous interrupt stack for softirq execution. - */ -void do_softirq_own_stack(void) -{ - unsigned long old, new; - - old = current_stack_pointer(); - /* Check against async. stack address range. */ - new = S390_lowcore.async_stack; - if (((new - old) >> (PAGE_SHIFT + THREAD_SIZE_ORDER)) != 0) { - CALL_ON_STACK(__do_softirq, new, 0); - } else { - /* We are already on the async stack. */ - __do_softirq(); - } -} - /* * ext_int_hash[index] is the list head for all external interrupts that hash * to this index. diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 528bb31815c3..52d056a5f89f 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -92,11 +92,6 @@ static void copy_instruction(struct kprobe *p) } NOKPROBE_SYMBOL(copy_instruction); -static inline int is_kernel_addr(void *addr) -{ - return addr < (void *)_end; -} - static int s390_get_insn_slot(struct kprobe *p) { /* @@ -105,7 +100,7 @@ static int s390_get_insn_slot(struct kprobe *p) * field can be patched and executed within the insn slot. */ p->ainsn.insn = NULL; - if (is_kernel_addr(p->addr)) + if (is_kernel((unsigned long)p->addr)) p->ainsn.insn = get_s390_insn_slot(); else if (is_module_addr(p->addr)) p->ainsn.insn = get_insn_slot(); @@ -117,7 +112,7 @@ static void s390_free_insn_slot(struct kprobe *p) { if (!p->ainsn.insn) return; - if (is_kernel_addr(p->addr)) + if (is_kernel((unsigned long)p->addr)) free_s390_insn_slot(p->ainsn.insn, 0); else free_insn_slot(p->ainsn.insn, 0); diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index d91989c7bd6a..1005a6935fbe 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -132,7 +132,8 @@ static bool kdump_csum_valid(struct kimage *image) int rc; preempt_disable(); - rc = CALL_ON_STACK(do_start_kdump, S390_lowcore.nodat_stack, 1, image); + rc = call_on_stack(1, S390_lowcore.nodat_stack, unsigned long, do_start_kdump, + unsigned long, (unsigned long)image); preempt_enable(); return rc == 0; #else diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 11f8c296f60d..20f8e1868853 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -189,12 +189,16 @@ void noinstr s390_handle_mcck(void) * returns 0 if all required registers are available * returns 1 otherwise */ -static int notrace s390_check_registers(union mci mci, int umode) +static int notrace s390_validate_registers(union mci mci, int umode) { + struct mcesa *mcesa; + void *fpt_save_area; union ctlreg2 cr2; int kill_task; + u64 zero; kill_task = 0; + zero = 0; if (!mci.gr) { /* @@ -205,14 +209,6 @@ static int notrace s390_check_registers(union mci mci, int umode) s390_handle_damage(); kill_task = 1; } - /* Check control registers */ - if (!mci.cr) { - /* - * Control registers have unknown contents. - * Can't recover and therefore stopping machine. - */ - s390_handle_damage(); - } if (!mci.fp) { /* * Floating point registers can't be restored. If the @@ -225,35 +221,89 @@ static int notrace s390_check_registers(union mci mci, int umode) if (!test_cpu_flag(CIF_FPU)) kill_task = 1; } + fpt_save_area = &S390_lowcore.floating_pt_save_area; if (!mci.fc) { /* * Floating point control register can't be restored. * If the kernel currently uses the floating pointer * registers and needs the FPC register the system is * stopped. If the process has its floating pointer - * registers loaded it is terminated. + * registers loaded it is terminated. Otherwise the + * FPC is just validated. */ if (S390_lowcore.fpu_flags & KERNEL_FPC) s390_handle_damage(); + asm volatile( + " lfpc %0\n" + : + : "Q" (zero)); if (!test_cpu_flag(CIF_FPU)) kill_task = 1; + } else { + asm volatile( + " lfpc %0\n" + : + : "Q" (S390_lowcore.fpt_creg_save_area)); } - if (MACHINE_HAS_VX) { + mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); + if (!MACHINE_HAS_VX) { + /* Validate floating point registers */ + asm volatile( + " ld 0,0(%0)\n" + " ld 1,8(%0)\n" + " ld 2,16(%0)\n" + " ld 3,24(%0)\n" + " ld 4,32(%0)\n" + " ld 5,40(%0)\n" + " ld 6,48(%0)\n" + " ld 7,56(%0)\n" + " ld 8,64(%0)\n" + " ld 9,72(%0)\n" + " ld 10,80(%0)\n" + " ld 11,88(%0)\n" + " ld 12,96(%0)\n" + " ld 13,104(%0)\n" + " ld 14,112(%0)\n" + " ld 15,120(%0)\n" + : + : "a" (fpt_save_area) + : "memory"); + } else { + /* Validate vector registers */ + union ctlreg0 cr0; + if (!mci.vr) { /* * Vector registers can't be restored. If the kernel * currently uses vector registers the system is * stopped. If the process has its vector registers - * loaded it is terminated. + * loaded it is terminated. Otherwise just validate + * the registers. */ if (S390_lowcore.fpu_flags & KERNEL_VXR) s390_handle_damage(); if (!test_cpu_flag(CIF_FPU)) kill_task = 1; } + cr0.val = S390_lowcore.cregs_save_area[0]; + cr0.afp = cr0.vx = 1; + __ctl_load(cr0.val, 0, 0); + asm volatile( + " la 1,%0\n" + " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ + " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */ + : + : "Q" (*(struct vx_array *)mcesa->vector_save_area) + : "1"); + __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0); } - /* Check if access registers are valid */ + /* Validate access registers */ + asm volatile( + " lam 0,15,0(%0)\n" + : + : "a" (&S390_lowcore.access_regs_save_area) + : "memory"); if (!mci.ar) { /* * Access registers have unknown contents. @@ -261,7 +311,7 @@ static int notrace s390_check_registers(union mci mci, int umode) */ kill_task = 1; } - /* Check guarded storage registers */ + /* Validate guarded storage registers */ cr2.val = S390_lowcore.cregs_save_area[2]; if (cr2.gse) { if (!mci.gs) { @@ -271,31 +321,26 @@ static int notrace s390_check_registers(union mci mci, int umode) * It has to be terminated. */ kill_task = 1; + } else { + load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area); } } - /* Check if old PSW is valid */ - if (!mci.wp) { - /* - * Can't tell if we come from user or kernel mode - * -> stopping machine. - */ - s390_handle_damage(); - } - /* Check for invalid kernel instruction address */ - if (!mci.ia && !umode) { - /* - * The instruction address got lost while running - * in the kernel -> stopping machine. - */ - s390_handle_damage(); - } + /* + * The getcpu vdso syscall reads CPU number from the programmable + * field of the TOD clock. Disregard the TOD programmable register + * validity bit and load the CPU number into the TOD programmable + * field unconditionally. + */ + set_tod_programmable_field(raw_smp_processor_id()); + /* Validate clock comparator register */ + set_clock_comparator(S390_lowcore.clock_comparator); if (!mci.ms || !mci.pm || !mci.ia) kill_task = 1; return kill_task; } -NOKPROBE_SYMBOL(s390_check_registers); +NOKPROBE_SYMBOL(s390_validate_registers); /* * Backup the guest's machine check info to its description block @@ -353,11 +398,6 @@ int notrace s390_do_machine_check(struct pt_regs *regs) mci.val = S390_lowcore.mcck_interruption_code; mcck = this_cpu_ptr(&cpu_mcck); - if (mci.sd) { - /* System damage -> stopping machine */ - s390_handle_damage(); - } - /* * Reinject the instruction processing damages' machine checks * including Delayed Access Exception into the guest @@ -398,7 +438,7 @@ int notrace s390_do_machine_check(struct pt_regs *regs) s390_handle_damage(); } } - if (s390_check_registers(mci, user_mode(regs))) { + if (s390_validate_registers(mci, user_mode(regs))) { /* * Couldn't restore all register contents for the * user space process -> mark task for termination. @@ -428,21 +468,6 @@ int notrace s390_do_machine_check(struct pt_regs *regs) mcck_pending = 1; } - /* - * Reinject storage related machine checks into the guest if they - * happen when the guest is running. - */ - if (!test_cpu_flag(CIF_MCCK_GUEST)) { - if (mci.se) - /* Storage error uncorrected */ - s390_handle_damage(); - if (mci.ke) - /* Storage key-error uncorrected */ - s390_handle_damage(); - if (mci.ds && mci.fa) - /* Storage degradation */ - s390_handle_damage(); - } if (mci.cp) { /* Channel report word pending */ mcck->channel_report = 1; diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 1b7a0525fbed..975a00c8c564 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -2,8 +2,9 @@ /* * Performance event support for s390x - CPU-measurement Counter Facility * - * Copyright IBM Corp. 2012, 2019 + * Copyright IBM Corp. 2012, 2021 * Author(s): Hendrik Brueckner + * Thomas Richter */ #define KMSG_COMPONENT "cpum_cf" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt @@ -14,7 +15,223 @@ #include #include #include +#include + #include +#include +#include + +static unsigned int cfdiag_cpu_speed; /* CPU speed for CF_DIAG trailer */ +static debug_info_t *cf_dbg; + +#define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ + /* interval in seconds */ + +/* Counter sets are stored as data stream in a page sized memory buffer and + * exported to user space via raw data attached to the event sample data. + * Each counter set starts with an eight byte header consisting of: + * - a two byte eye catcher (0xfeef) + * - a one byte counter set number + * - a two byte counter set size (indicates the number of counters in this set) + * - a three byte reserved value (must be zero) to make the header the same + * size as a counter value. + * All counter values are eight byte in size. + * + * All counter sets are followed by a 64 byte trailer. + * The trailer consists of a: + * - flag field indicating valid fields when corresponding bit set + * - the counter facility first and second version number + * - the CPU speed if nonzero + * - the time stamp the counter sets have been collected + * - the time of day (TOD) base value + * - the machine type. + * + * The counter sets are saved when the process is prepared to be executed on a + * CPU and saved again when the process is going to be removed from a CPU. + * The difference of both counter sets are calculated and stored in the event + * sample data area. + */ +struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */ + unsigned int def:16; /* 0-15 Data Entry Format */ + unsigned int set:16; /* 16-31 Counter set identifier */ + unsigned int ctr:16; /* 32-47 Number of stored counters */ + unsigned int res1:16; /* 48-63 Reserved */ +}; + +struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */ + /* 0 - 7 */ + union { + struct { + unsigned int clock_base:1; /* TOD clock base set */ + unsigned int speed:1; /* CPU speed set */ + /* Measurement alerts */ + unsigned int mtda:1; /* Loss of MT ctr. data alert */ + unsigned int caca:1; /* Counter auth. change alert */ + unsigned int lcda:1; /* Loss of counter data alert */ + }; + unsigned long flags; /* 0-63 All indicators */ + }; + /* 8 - 15 */ + unsigned int cfvn:16; /* 64-79 Ctr First Version */ + unsigned int csvn:16; /* 80-95 Ctr Second Version */ + unsigned int cpu_speed:32; /* 96-127 CPU speed */ + /* 16 - 23 */ + unsigned long timestamp; /* 128-191 Timestamp (TOD) */ + /* 24 - 55 */ + union { + struct { + unsigned long progusage1; + unsigned long progusage2; + unsigned long progusage3; + unsigned long tod_base; + }; + unsigned long progusage[4]; + }; + /* 56 - 63 */ + unsigned int mach_type:16; /* Machine type */ + unsigned int res1:16; /* Reserved */ + unsigned int res2:32; /* Reserved */ +}; + +/* Create the trailer data at the end of a page. */ +static void cfdiag_trailer(struct cf_trailer_entry *te) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cpuid cpuid; + + te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */ + te->csvn = cpuhw->info.csvn; + + get_cpu_id(&cpuid); /* Machine type */ + te->mach_type = cpuid.machine; + te->cpu_speed = cfdiag_cpu_speed; + if (te->cpu_speed) + te->speed = 1; + te->clock_base = 1; /* Save clock base */ + te->tod_base = tod_clock_base.tod; + te->timestamp = get_tod_clock_fast(); +} + +/* Read a counter set. The counter set number determines the counter set and + * the CPUM-CF first and second version number determine the number of + * available counters in each counter set. + * Each counter set starts with header containing the counter set number and + * the number of eight byte counters. + * + * The functions returns the number of bytes occupied by this counter set + * including the header. + * If there is no counter in the counter set, this counter set is useless and + * zero is returned on this case. + * + * Note that the counter sets may not be enabled or active and the stcctm + * instruction might return error 3. Depending on error_ok value this is ok, + * for example when called from cpumf_pmu_start() call back function. + */ +static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, + size_t room, bool error_ok) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + size_t ctrset_size, need = 0; + int rc = 3; /* Assume write failure */ + + ctrdata->def = CF_DIAG_CTRSET_DEF; + ctrdata->set = ctrset; + ctrdata->res1 = 0; + ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info); + + if (ctrset_size) { /* Save data */ + need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); + if (need <= room) { + rc = ctr_stcctm(ctrset, ctrset_size, + (u64 *)(ctrdata + 1)); + } + if (rc != 3 || error_ok) + ctrdata->ctr = ctrset_size; + else + need = 0; + } + + debug_sprintf_event(cf_dbg, 3, + "%s ctrset %d ctrset_size %zu cfvn %d csvn %d" + " need %zd rc %d\n", __func__, ctrset, ctrset_size, + cpuhw->info.cfvn, cpuhw->info.csvn, need, rc); + return need; +} + +/* Read out all counter sets and save them in the provided data buffer. + * The last 64 byte host an artificial trailer entry. + */ +static size_t cfdiag_getctr(void *data, size_t sz, unsigned long auth, + bool error_ok) +{ + struct cf_trailer_entry *trailer; + size_t offset = 0, done; + int i; + + memset(data, 0, sz); + sz -= sizeof(*trailer); /* Always room for trailer */ + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + struct cf_ctrset_entry *ctrdata = data + offset; + + if (!(auth & cpumf_ctr_ctl[i])) + continue; /* Counter set not authorized */ + + done = cfdiag_getctrset(ctrdata, i, sz - offset, error_ok); + offset += done; + } + trailer = data + offset; + cfdiag_trailer(trailer); + return offset + sizeof(*trailer); +} + +/* Calculate the difference for each counter in a counter set. */ +static void cfdiag_diffctrset(u64 *pstart, u64 *pstop, int counters) +{ + for (; --counters >= 0; ++pstart, ++pstop) + if (*pstop >= *pstart) + *pstop -= *pstart; + else + *pstop = *pstart - *pstop + 1; +} + +/* Scan the counter sets and calculate the difference of each counter + * in each set. The result is the increment of each counter during the + * period the counter set has been activated. + * + * Return true on success. + */ +static int cfdiag_diffctr(struct cpu_cf_events *cpuhw, unsigned long auth) +{ + struct cf_trailer_entry *trailer_start, *trailer_stop; + struct cf_ctrset_entry *ctrstart, *ctrstop; + size_t offset = 0; + + auth &= (1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1; + do { + ctrstart = (struct cf_ctrset_entry *)(cpuhw->start + offset); + ctrstop = (struct cf_ctrset_entry *)(cpuhw->stop + offset); + + if (memcmp(ctrstop, ctrstart, sizeof(*ctrstop))) { + pr_err_once("cpum_cf_diag counter set compare error " + "in set %i\n", ctrstart->set); + return 0; + } + auth &= ~cpumf_ctr_ctl[ctrstart->set]; + if (ctrstart->def == CF_DIAG_CTRSET_DEF) { + cfdiag_diffctrset((u64 *)(ctrstart + 1), + (u64 *)(ctrstop + 1), ctrstart->ctr); + offset += ctrstart->ctr * sizeof(u64) + + sizeof(*ctrstart); + } + } while (ctrstart->def && auth); + + /* Save time_stamp from start of event in stop's trailer */ + trailer_start = (struct cf_trailer_entry *)(cpuhw->start + offset); + trailer_stop = (struct cf_trailer_entry *)(cpuhw->stop + offset); + trailer_stop->progusage[0] = trailer_start->timestamp; + + return 1; +} static enum cpumf_ctr_set get_counter_set(u64 event) { @@ -34,7 +251,8 @@ static enum cpumf_ctr_set get_counter_set(u64 event) return set; } -static int validate_ctr_version(const struct hw_perf_event *hwc) +static int validate_ctr_version(const struct hw_perf_event *hwc, + enum cpumf_ctr_set set) { struct cpu_cf_events *cpuhw; int err = 0; @@ -43,7 +261,7 @@ static int validate_ctr_version(const struct hw_perf_event *hwc) cpuhw = &get_cpu_var(cpu_cf_events); /* check required version for counter sets */ - switch (hwc->config_base) { + switch (set) { case CPUMF_CTR_SET_BASIC: case CPUMF_CTR_SET_USER: if (cpuhw->info.cfvn < 1) @@ -86,6 +304,8 @@ static int validate_ctr_version(const struct hw_perf_event *hwc) (cpuhw->info.act_ctl & mtdiag_ctl))) err = -EOPNOTSUPP; break; + case CPUMF_CTR_SET_MAX: + err = -EOPNOTSUPP; } put_cpu_var(cpu_cf_events); @@ -95,7 +315,6 @@ static int validate_ctr_version(const struct hw_perf_event *hwc) static int validate_ctr_auth(const struct hw_perf_event *hwc) { struct cpu_cf_events *cpuhw; - u64 ctrs_state; int err = 0; cpuhw = &get_cpu_var(cpu_cf_events); @@ -105,8 +324,7 @@ static int validate_ctr_auth(const struct hw_perf_event *hwc) * return with -ENOENT in order to fall back to other * PMUs that might suffice the event request. */ - ctrs_state = cpumf_ctr_ctl[hwc->config_base]; - if (!(ctrs_state & cpuhw->info.auth_ctl)) + if (!(hwc->config_base & cpuhw->info.auth_ctl)) err = -ENOENT; put_cpu_var(cpu_cf_events); @@ -126,7 +344,7 @@ static void cpumf_pmu_enable(struct pmu *pmu) if (cpuhw->flags & PMU_F_ENABLED) return; - err = lcctl(cpuhw->state); + err = lcctl(cpuhw->state | cpuhw->dev_state); if (err) { pr_err("Enabling the performance measuring unit " "failed with rc=%x\n", err); @@ -151,6 +369,7 @@ static void cpumf_pmu_disable(struct pmu *pmu) return; inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); + inactive |= cpuhw->dev_state; err = lcctl(inactive); if (err) { pr_err("Disabling the performance measuring unit " @@ -199,6 +418,14 @@ static const int cpumf_generic_events_user[] = { [PERF_COUNT_HW_BUS_CYCLES] = -1, }; +static void cpumf_hw_inuse(void) +{ + mutex_lock(&pmc_reserve_mutex); + if (atomic_inc_return(&num_events) == 1) + __kernel_cpumcf_begin(); + mutex_unlock(&pmc_reserve_mutex); +} + static int __hw_perf_event_init(struct perf_event *event, unsigned int type) { struct perf_event_attr *attr = &event->attr; @@ -258,11 +485,11 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) /* * Use the hardware perf event structure to store the * counter number in the 'config' member and the counter - * set number in the 'config_base'. The counter set number - * is then later used to enable/disable the counter(s). + * set number in the 'config_base' as bit mask. + * It is later used to enable/disable the counter(s). */ hwc->config = ev; - hwc->config_base = set; + hwc->config_base = cpumf_ctr_ctl[set]; break; case CPUMF_CTR_SET_MAX: /* The counter could not be associated to a counter set */ @@ -270,22 +497,13 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) } /* Initialize for using the CPU-measurement counter facility */ - if (!atomic_inc_not_zero(&num_events)) { - mutex_lock(&pmc_reserve_mutex); - if (atomic_read(&num_events) == 0 && __kernel_cpumcf_begin()) - err = -EBUSY; - else - atomic_inc(&num_events); - mutex_unlock(&pmc_reserve_mutex); - } - if (err) - return err; + cpumf_hw_inuse(); event->destroy = hw_perf_event_destroy; /* Finally, validate version and authorization of the counter set */ err = validate_ctr_auth(hwc); if (!err) - err = validate_ctr_version(hwc); + err = validate_ctr_version(hwc, set); return err; } @@ -361,6 +579,7 @@ static void cpumf_pmu_start(struct perf_event *event, int flags) { struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct hw_perf_event *hwc = &event->hw; + int i; if (!(hwc->state & PERF_HES_STOPPED)) return; @@ -376,29 +595,92 @@ static void cpumf_pmu_start(struct perf_event *event, int flags) * needs to be synchronized. At this point, the counter set can be in * the inactive or disabled state. */ - hw_perf_event_reset(event); + if (hwc->config == PERF_EVENT_CPUM_CF_DIAG) { + cpuhw->usedss = cfdiag_getctr(cpuhw->start, + sizeof(cpuhw->start), + hwc->config_base, true); + } else { + hw_perf_event_reset(event); + } - /* increment refcount for this counter set */ - atomic_inc(&cpuhw->ctr_set[hwc->config_base]); + /* Increment refcount for counter sets */ + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) + if ((hwc->config_base & cpumf_ctr_ctl[i])) + atomic_inc(&cpuhw->ctr_set[i]); +} + +/* Create perf event sample with the counter sets as raw data. The sample + * is then pushed to the event subsystem and the function checks for + * possible event overflows. If an event overflow occurs, the PMU is + * stopped. + * + * Return non-zero if an event overflow occurred. + */ +static int cfdiag_push_sample(struct perf_event *event, + struct cpu_cf_events *cpuhw) +{ + struct perf_sample_data data; + struct perf_raw_record raw; + struct pt_regs regs; + int overflow; + + /* Setup perf sample */ + perf_sample_data_init(&data, 0, event->hw.last_period); + memset(®s, 0, sizeof(regs)); + memset(&raw, 0, sizeof(raw)); + + if (event->attr.sample_type & PERF_SAMPLE_CPU) + data.cpu_entry.cpu = event->cpu; + if (event->attr.sample_type & PERF_SAMPLE_RAW) { + raw.frag.size = cpuhw->usedss; + raw.frag.data = cpuhw->stop; + raw.size = raw.frag.size; + data.raw = &raw; + } + + overflow = perf_event_overflow(event, &data, ®s); + debug_sprintf_event(cf_dbg, 3, + "%s event %#llx sample_type %#llx raw %d ov %d\n", + __func__, event->hw.config, + event->attr.sample_type, raw.size, overflow); + if (overflow) + event->pmu->stop(event, 0); + + perf_event_update_userpage(event); + return overflow; } static void cpumf_pmu_stop(struct perf_event *event, int flags) { struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct hw_perf_event *hwc = &event->hw; + int i; if (!(hwc->state & PERF_HES_STOPPED)) { /* Decrement reference count for this counter set and if this * is the last used counter in the set, clear activation * control and set the counter set state to inactive. */ - if (!atomic_dec_return(&cpuhw->ctr_set[hwc->config_base])) - ctr_set_stop(&cpuhw->state, hwc->config_base); + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + if (!(hwc->config_base & cpumf_ctr_ctl[i])) + continue; + if (!atomic_dec_return(&cpuhw->ctr_set[i])) + ctr_set_stop(&cpuhw->state, cpumf_ctr_ctl[i]); + } hwc->state |= PERF_HES_STOPPED; } if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { - hw_perf_event_update(event); + if (hwc->config == PERF_EVENT_CPUM_CF_DIAG) { + local64_inc(&event->count); + cpuhw->usedss = cfdiag_getctr(cpuhw->stop, + sizeof(cpuhw->stop), + event->hw.config_base, + false); + if (cfdiag_diffctr(cpuhw, event->hw.config_base)) + cfdiag_push_sample(event, cpuhw); + } else + hw_perf_event_update(event); hwc->state |= PERF_HES_UPTODATE; } } @@ -419,6 +701,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) static void cpumf_pmu_del(struct perf_event *event, int flags) { struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + int i; cpumf_pmu_stop(event, PERF_EF_UPDATE); @@ -430,8 +713,9 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) * clear enable control and resets all counters in a set. Therefore, * cpumf_pmu_start() always has to reenable a counter set. */ - if (!atomic_read(&cpuhw->ctr_set[event->hw.config_base])) - ctr_set_disable(&cpuhw->state, event->hw.config_base); + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) + if (!atomic_read(&cpuhw->ctr_set[i])) + ctr_set_disable(&cpuhw->state, cpumf_ctr_ctl[i]); } /* Performance monitoring unit for s390x */ @@ -448,6 +732,7 @@ static struct pmu cpumf_pmu = { .read = cpumf_pmu_read, }; +static int cfset_init(void); static int __init cpumf_pmu_init(void) { int rc; @@ -455,10 +740,689 @@ static int __init cpumf_pmu_init(void) if (!kernel_cpumcf_avail()) return -ENODEV; + /* Setup s390dbf facility */ + cf_dbg = debug_register(KMSG_COMPONENT, 2, 1, 128); + if (!cf_dbg) { + pr_err("Registration of s390dbf(cpum_cf) failed\n"); + return -ENOMEM; + }; + debug_register_view(cf_dbg, &debug_sprintf_view); + cpumf_pmu.attr_groups = cpumf_cf_event_group(); rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", -1); - if (rc) + if (rc) { + debug_unregister_view(cf_dbg, &debug_sprintf_view); + debug_unregister(cf_dbg); pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc); + } else if (stccm_avail()) { /* Setup counter set device */ + cfset_init(); + } return rc; } -subsys_initcall(cpumf_pmu_init); + +/* Support for the CPU Measurement Facility counter set extraction using + * device /dev/hwctr. This allows user space programs to extract complete + * counter set via normal file operations. + */ + +static atomic_t cfset_opencnt = ATOMIC_INIT(0); /* Excl. access */ +static DEFINE_MUTEX(cfset_ctrset_mutex);/* Synchronize access to hardware */ +struct cfset_call_on_cpu_parm { /* Parm struct for smp_call_on_cpu */ + unsigned int sets; /* Counter set bit mask */ + atomic_t cpus_ack; /* # CPUs successfully executed func */ +}; + +static struct cfset_request { /* CPUs and counter set bit mask */ + unsigned long ctrset; /* Bit mask of counter set to read */ + cpumask_t mask; /* CPU mask to read from */ +} cfset_request; + +static void cfset_ctrset_clear(void) +{ + cpumask_clear(&cfset_request.mask); + cfset_request.ctrset = 0; +} + +/* The /dev/hwctr device access uses PMU_F_IN_USE to mark the device access + * path is currently used. + * The cpu_cf_events::dev_state is used to denote counter sets in use by this + * interface. It is always or'ed in. If this interface is not active, its + * value is zero and no additional counter sets will be included. + * + * The cpu_cf_events::state is used by the perf_event_open SVC and remains + * unchanged. + * + * perf_pmu_enable() and perf_pmu_enable() and its call backs + * cpumf_pmu_enable() and cpumf_pmu_disable() are called by the + * performance measurement subsystem to enable per process + * CPU Measurement counter facility. + * The XXX_enable() and XXX_disable functions are used to turn off + * x86 performance monitoring interrupt (PMI) during scheduling. + * s390 uses these calls to temporarily stop and resume the active CPU + * counters sets during scheduling. + * + * We do allow concurrent access of perf_event_open() SVC and /dev/hwctr + * device access. The perf_event_open() SVC interface makes a lot of effort + * to only run the counters while the calling process is actively scheduled + * to run. + * When /dev/hwctr interface is also used at the same time, the counter sets + * will keep running, even when the process is scheduled off a CPU. + * However this is not a problem and does not lead to wrong counter values + * for the perf_event_open() SVC. The current counter value will be recorded + * during schedule-in. At schedule-out time the current counter value is + * extracted again and the delta is calculated and added to the event. + */ +/* Stop all counter sets via ioctl interface */ +static void cfset_ioctl_off(void *parm) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cfset_call_on_cpu_parm *p = parm; + int rc; + + cpuhw->dev_state = 0; + for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc) + if ((p->sets & cpumf_ctr_ctl[rc])) + atomic_dec(&cpuhw->ctr_set[rc]); + rc = lcctl(cpuhw->state); /* Keep perf_event_open counter sets */ + if (rc) + pr_err("Counter set stop %#llx of /dev/%s failed rc=%i\n", + cpuhw->state, S390_HWCTR_DEVICE, rc); + cpuhw->flags &= ~PMU_F_IN_USE; + debug_sprintf_event(cf_dbg, 4, "%s rc %d state %#llx dev_state %#llx\n", + __func__, rc, cpuhw->state, cpuhw->dev_state); +} + +/* Start counter sets on particular CPU */ +static void cfset_ioctl_on(void *parm) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cfset_call_on_cpu_parm *p = parm; + int rc; + + cpuhw->flags |= PMU_F_IN_USE; + ctr_set_enable(&cpuhw->dev_state, p->sets); + ctr_set_start(&cpuhw->dev_state, p->sets); + for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc) + if ((p->sets & cpumf_ctr_ctl[rc])) + atomic_inc(&cpuhw->ctr_set[rc]); + rc = lcctl(cpuhw->dev_state | cpuhw->state); /* Start counter sets */ + if (!rc) + atomic_inc(&p->cpus_ack); + else + pr_err("Counter set start %#llx of /dev/%s failed rc=%i\n", + cpuhw->dev_state | cpuhw->state, S390_HWCTR_DEVICE, rc); + debug_sprintf_event(cf_dbg, 4, "%s rc %d state %#llx dev_state %#llx\n", + __func__, rc, cpuhw->state, cpuhw->dev_state); +} + +static void cfset_release_cpu(void *p) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + int rc; + + debug_sprintf_event(cf_dbg, 4, "%s state %#llx dev_state %#llx\n", + __func__, cpuhw->state, cpuhw->dev_state); + rc = lcctl(cpuhw->state); /* Keep perf_event_open counter sets */ + if (rc) + pr_err("Counter set release %#llx of /dev/%s failed rc=%i\n", + cpuhw->state, S390_HWCTR_DEVICE, rc); + cpuhw->dev_state = 0; +} + +/* Release function is also called when application gets terminated without + * doing a proper ioctl(..., S390_HWCTR_STOP, ...) command. + */ +static int cfset_release(struct inode *inode, struct file *file) +{ + on_each_cpu(cfset_release_cpu, NULL, 1); + hw_perf_event_destroy(NULL); + cfset_ctrset_clear(); + atomic_set(&cfset_opencnt, 0); + return 0; +} + +static int cfset_open(struct inode *inode, struct file *file) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* Only one user space program can open /dev/hwctr */ + if (atomic_xchg(&cfset_opencnt, 1)) + return -EBUSY; + + cpumf_hw_inuse(); + file->private_data = NULL; + /* nonseekable_open() never fails */ + return nonseekable_open(inode, file); +} + +static int cfset_all_stop(void) +{ + struct cfset_call_on_cpu_parm p = { + .sets = cfset_request.ctrset, + }; + cpumask_var_t mask; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; + cpumask_and(mask, &cfset_request.mask, cpu_online_mask); + on_each_cpu_mask(mask, cfset_ioctl_off, &p, 1); + free_cpumask_var(mask); + return 0; +} + +static int cfset_all_start(void) +{ + struct cfset_call_on_cpu_parm p = { + .sets = cfset_request.ctrset, + .cpus_ack = ATOMIC_INIT(0), + }; + cpumask_var_t mask; + int rc = 0; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; + cpumask_and(mask, &cfset_request.mask, cpu_online_mask); + on_each_cpu_mask(mask, cfset_ioctl_on, &p, 1); + if (atomic_read(&p.cpus_ack) != cpumask_weight(mask)) { + on_each_cpu_mask(mask, cfset_ioctl_off, &p, 1); + rc = -EIO; + debug_sprintf_event(cf_dbg, 4, "%s CPUs missing", __func__); + } + free_cpumask_var(mask); + return rc; +} + + +/* Return the maximum required space for all possible CPUs in case one + * CPU will be onlined during the START, READ, STOP cycles. + * To find out the size of the counter sets, any one CPU will do. They + * all have the same counter sets. + */ +static size_t cfset_needspace(unsigned int sets) +{ + struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events); + size_t bytes = 0; + int i; + + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + if (!(sets & cpumf_ctr_ctl[i])) + continue; + bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) + + sizeof(((struct s390_ctrset_setdata *)0)->set) + + sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); + } + bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids * + (bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) + + sizeof(((struct s390_ctrset_cpudata *)0)->no_sets)); + put_cpu_ptr(&cpu_cf_events); + return bytes; +} + +static int cfset_all_copy(unsigned long arg, cpumask_t *mask) +{ + struct s390_ctrset_read __user *ctrset_read; + unsigned int cpu, cpus, rc; + void __user *uptr; + + ctrset_read = (struct s390_ctrset_read __user *)arg; + uptr = ctrset_read->data; + for_each_cpu(cpu, mask) { + struct cpu_cf_events *cpuhw = per_cpu_ptr(&cpu_cf_events, cpu); + struct s390_ctrset_cpudata __user *ctrset_cpudata; + + ctrset_cpudata = uptr; + rc = put_user(cpu, &ctrset_cpudata->cpu_nr); + rc |= put_user(cpuhw->sets, &ctrset_cpudata->no_sets); + rc |= copy_to_user(ctrset_cpudata->data, cpuhw->data, + cpuhw->used); + if (rc) + return -EFAULT; + uptr += sizeof(struct s390_ctrset_cpudata) + cpuhw->used; + cond_resched(); + } + cpus = cpumask_weight(mask); + if (put_user(cpus, &ctrset_read->no_cpus)) + return -EFAULT; + debug_sprintf_event(cf_dbg, 4, "%s copied %ld\n", __func__, + uptr - (void __user *)ctrset_read->data); + return 0; +} + +static size_t cfset_cpuset_read(struct s390_ctrset_setdata *p, int ctrset, + int ctrset_size, size_t room) +{ + size_t need = 0; + int rc = -1; + + need = sizeof(*p) + sizeof(u64) * ctrset_size; + if (need <= room) { + p->set = cpumf_ctr_ctl[ctrset]; + p->no_cnts = ctrset_size; + rc = ctr_stcctm(ctrset, ctrset_size, (u64 *)p->cv); + if (rc == 3) /* Nothing stored */ + need = 0; + } + return need; +} + +/* Read all counter sets. */ +static void cfset_cpu_read(void *parm) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cfset_call_on_cpu_parm *p = parm; + int set, set_size; + size_t space; + + /* No data saved yet */ + cpuhw->used = 0; + cpuhw->sets = 0; + memset(cpuhw->data, 0, sizeof(cpuhw->data)); + + /* Scan the counter sets */ + for (set = CPUMF_CTR_SET_BASIC; set < CPUMF_CTR_SET_MAX; ++set) { + struct s390_ctrset_setdata *sp = (void *)cpuhw->data + + cpuhw->used; + + if (!(p->sets & cpumf_ctr_ctl[set])) + continue; /* Counter set not in list */ + set_size = cpum_cf_ctrset_size(set, &cpuhw->info); + space = sizeof(cpuhw->data) - cpuhw->used; + space = cfset_cpuset_read(sp, set, set_size, space); + if (space) { + cpuhw->used += space; + cpuhw->sets += 1; + } + } + debug_sprintf_event(cf_dbg, 4, "%s sets %d used %zd\n", __func__, + cpuhw->sets, cpuhw->used); +} + +static int cfset_all_read(unsigned long arg) +{ + struct cfset_call_on_cpu_parm p; + cpumask_var_t mask; + int rc; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; + + p.sets = cfset_request.ctrset; + cpumask_and(mask, &cfset_request.mask, cpu_online_mask); + on_each_cpu_mask(mask, cfset_cpu_read, &p, 1); + rc = cfset_all_copy(arg, mask); + free_cpumask_var(mask); + return rc; +} + +static long cfset_ioctl_read(unsigned long arg) +{ + struct s390_ctrset_read read; + int ret = 0; + + if (copy_from_user(&read, (char __user *)arg, sizeof(read))) + return -EFAULT; + ret = cfset_all_read(arg); + return ret; +} + +static long cfset_ioctl_stop(void) +{ + int ret = ENXIO; + + if (cfset_request.ctrset) { + ret = cfset_all_stop(); + cfset_ctrset_clear(); + } + return ret; +} + +static long cfset_ioctl_start(unsigned long arg) +{ + struct s390_ctrset_start __user *ustart; + struct s390_ctrset_start start; + void __user *umask; + unsigned int len; + int ret = 0; + size_t need; + + if (cfset_request.ctrset) + return -EBUSY; + ustart = (struct s390_ctrset_start __user *)arg; + if (copy_from_user(&start, ustart, sizeof(start))) + return -EFAULT; + if (start.version != S390_HWCTR_START_VERSION) + return -EINVAL; + if (start.counter_sets & ~(cpumf_ctr_ctl[CPUMF_CTR_SET_BASIC] | + cpumf_ctr_ctl[CPUMF_CTR_SET_USER] | + cpumf_ctr_ctl[CPUMF_CTR_SET_CRYPTO] | + cpumf_ctr_ctl[CPUMF_CTR_SET_EXT] | + cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG])) + return -EINVAL; /* Invalid counter set */ + if (!start.counter_sets) + return -EINVAL; /* No counter set at all? */ + cpumask_clear(&cfset_request.mask); + len = min_t(u64, start.cpumask_len, cpumask_size()); + umask = (void __user *)start.cpumask; + if (copy_from_user(&cfset_request.mask, umask, len)) + return -EFAULT; + if (cpumask_empty(&cfset_request.mask)) + return -EINVAL; + need = cfset_needspace(start.counter_sets); + if (put_user(need, &ustart->data_bytes)) + ret = -EFAULT; + if (ret) + goto out; + cfset_request.ctrset = start.counter_sets; + ret = cfset_all_start(); +out: + if (ret) + cfset_ctrset_clear(); + debug_sprintf_event(cf_dbg, 4, "%s sets %#lx need %ld ret %d\n", + __func__, cfset_request.ctrset, need, ret); + return ret; +} + +/* Entry point to the /dev/hwctr device interface. + * The ioctl system call supports three subcommands: + * S390_HWCTR_START: Start the specified counter sets on a CPU list. The + * counter set keeps running until explicitly stopped. Returns the number + * of bytes needed to store the counter values. If another S390_HWCTR_START + * ioctl subcommand is called without a previous S390_HWCTR_STOP stop + * command, -EBUSY is returned. + * S390_HWCTR_READ: Read the counter set values from specified CPU list given + * with the S390_HWCTR_START command. + * S390_HWCTR_STOP: Stops the counter sets on the CPU list given with the + * previous S390_HWCTR_START subcommand. + */ +static long cfset_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret; + + get_online_cpus(); + mutex_lock(&cfset_ctrset_mutex); + switch (cmd) { + case S390_HWCTR_START: + ret = cfset_ioctl_start(arg); + break; + case S390_HWCTR_STOP: + ret = cfset_ioctl_stop(); + break; + case S390_HWCTR_READ: + ret = cfset_ioctl_read(arg); + break; + default: + ret = -ENOTTY; + break; + } + mutex_unlock(&cfset_ctrset_mutex); + put_online_cpus(); + return ret; +} + +static const struct file_operations cfset_fops = { + .owner = THIS_MODULE, + .open = cfset_open, + .release = cfset_release, + .unlocked_ioctl = cfset_ioctl, + .compat_ioctl = cfset_ioctl, + .llseek = no_llseek +}; + +static struct miscdevice cfset_dev = { + .name = S390_HWCTR_DEVICE, + .minor = MISC_DYNAMIC_MINOR, + .fops = &cfset_fops, +}; + +int cfset_online_cpu(unsigned int cpu) +{ + struct cfset_call_on_cpu_parm p; + + mutex_lock(&cfset_ctrset_mutex); + if (cfset_request.ctrset) { + p.sets = cfset_request.ctrset; + cfset_ioctl_on(&p); + cpumask_set_cpu(cpu, &cfset_request.mask); + } + mutex_unlock(&cfset_ctrset_mutex); + return 0; +} + +int cfset_offline_cpu(unsigned int cpu) +{ + struct cfset_call_on_cpu_parm p; + + mutex_lock(&cfset_ctrset_mutex); + if (cfset_request.ctrset) { + p.sets = cfset_request.ctrset; + cfset_ioctl_off(&p); + cpumask_clear_cpu(cpu, &cfset_request.mask); + } + mutex_unlock(&cfset_ctrset_mutex); + return 0; +} + +static void cfdiag_read(struct perf_event *event) +{ + debug_sprintf_event(cf_dbg, 3, "%s event %#llx count %ld\n", __func__, + event->attr.config, local64_read(&event->count)); +} + +static int get_authctrsets(void) +{ + struct cpu_cf_events *cpuhw; + unsigned long auth = 0; + enum cpumf_ctr_set i; + + cpuhw = &get_cpu_var(cpu_cf_events); + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) + auth |= cpumf_ctr_ctl[i]; + } + put_cpu_var(cpu_cf_events); + return auth; +} + +/* Setup the event. Test for authorized counter sets and only include counter + * sets which are authorized at the time of the setup. Including unauthorized + * counter sets result in specification exception (and panic). + */ +static int cfdiag_event_init2(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + int err = 0; + + /* Set sample_period to indicate sampling */ + event->hw.config = attr->config; + event->hw.sample_period = attr->sample_period; + local64_set(&event->hw.period_left, event->hw.sample_period); + local64_set(&event->count, 0); + event->hw.last_period = event->hw.sample_period; + + /* Add all authorized counter sets to config_base. The + * the hardware init function is either called per-cpu or just once + * for all CPUS (event->cpu == -1). This depends on the whether + * counting is started for all CPUs or on a per workload base where + * the perf event moves from one CPU to another CPU. + * Checking the authorization on any CPU is fine as the hardware + * applies the same authorization settings to all CPUs. + */ + event->hw.config_base = get_authctrsets(); + + /* No authorized counter sets, nothing to count/sample */ + if (!event->hw.config_base) + err = -EINVAL; + + debug_sprintf_event(cf_dbg, 5, "%s err %d config_base %#lx\n", + __func__, err, event->hw.config_base); + return err; +} + +static int cfdiag_event_init(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + int err = -ENOENT; + + if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG || + event->attr.type != event->pmu->type) + goto out; + + /* Raw events are used to access counters directly, + * hence do not permit excludes. + * This event is useless without PERF_SAMPLE_RAW to return counter set + * values as raw data. + */ + if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv || + !(attr->sample_type & (PERF_SAMPLE_CPU | PERF_SAMPLE_RAW))) { + err = -EOPNOTSUPP; + goto out; + } + + /* Initialize for using the CPU-measurement counter facility */ + cpumf_hw_inuse(); + event->destroy = hw_perf_event_destroy; + + err = cfdiag_event_init2(event); + if (unlikely(err)) + event->destroy(event); +out: + return err; +} + +/* Create cf_diag/events/CF_DIAG event sysfs file. This counter is used + * to collect the complete counter sets for a scheduled process. Target + * are complete counter sets attached as raw data to the artificial event. + * This results in complete counter sets available when a process is + * scheduled. Contains the delta of every counter while the process was + * running. + */ +CPUMF_EVENT_ATTR(CF_DIAG, CF_DIAG, PERF_EVENT_CPUM_CF_DIAG); + +static struct attribute *cfdiag_events_attr[] = { + CPUMF_EVENT_PTR(CF_DIAG, CF_DIAG), + NULL, +}; + +PMU_FORMAT_ATTR(event, "config:0-63"); + +static struct attribute *cfdiag_format_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group cfdiag_events_group = { + .name = "events", + .attrs = cfdiag_events_attr, +}; +static struct attribute_group cfdiag_format_group = { + .name = "format", + .attrs = cfdiag_format_attr, +}; +static const struct attribute_group *cfdiag_attr_groups[] = { + &cfdiag_events_group, + &cfdiag_format_group, + NULL, +}; + +/* Performance monitoring unit for event CF_DIAG. Since this event + * is also started and stopped via the perf_event_open() system call, use + * the same event enable/disable call back functions. They do not + * have a pointer to the perf_event strcture as first parameter. + * + * The functions XXX_add, XXX_del, XXX_start and XXX_stop are also common. + * Reuse them and distinguish the event (always first parameter) via + * 'config' member. + */ +static struct pmu cf_diag = { + .task_ctx_nr = perf_sw_context, + .event_init = cfdiag_event_init, + .pmu_enable = cpumf_pmu_enable, + .pmu_disable = cpumf_pmu_disable, + .add = cpumf_pmu_add, + .del = cpumf_pmu_del, + .start = cpumf_pmu_start, + .stop = cpumf_pmu_stop, + .read = cfdiag_read, + + .attr_groups = cfdiag_attr_groups +}; + +/* Calculate memory needed to store all counter sets together with header and + * trailer data. This is independent of the counter set authorization which + * can vary depending on the configuration. + */ +static size_t cfdiag_maxsize(struct cpumf_ctr_info *info) +{ + size_t max_size = sizeof(struct cf_trailer_entry); + enum cpumf_ctr_set i; + + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + size_t size = cpum_cf_ctrset_size(i, info); + + if (size) + max_size += size * sizeof(u64) + + sizeof(struct cf_ctrset_entry); + } + return max_size; +} + +/* Get the CPU speed, try sampling facility first and CPU attributes second. */ +static void cfdiag_get_cpu_speed(void) +{ + if (cpum_sf_avail()) { /* Sampling facility first */ + struct hws_qsi_info_block si; + + memset(&si, 0, sizeof(si)); + if (!qsi(&si)) { + cfdiag_cpu_speed = si.cpu_speed; + return; + } + } + + /* Fallback: CPU speed extract static part. Used in case + * CPU Measurement Sampling Facility is turned off. + */ + if (test_facility(34)) { + unsigned long mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0); + + if (mhz != -1UL) + cfdiag_cpu_speed = mhz & 0xffffffff; + } +} + +static int cfset_init(void) +{ + struct cpumf_ctr_info info; + size_t need; + int rc; + + if (qctri(&info)) + return -ENODEV; + + cfdiag_get_cpu_speed(); + /* Make sure the counter set data fits into predefined buffer. */ + need = cfdiag_maxsize(&info); + if (need > sizeof(((struct cpu_cf_events *)0)->start)) { + pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", + need); + return -ENOMEM; + } + + rc = misc_register(&cfset_dev); + if (rc) { + pr_err("Registration of /dev/%s failed rc=%i\n", + cfset_dev.name, rc); + goto out; + } + + rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", -1); + if (rc) { + misc_deregister(&cfset_dev); + pr_err("Registration of PMU(cpum_cf_diag) failed with rc=%i\n", + rc); + } +out: + return rc; +} + +device_initcall(cpumf_pmu_init); diff --git a/arch/s390/kernel/perf_cpum_cf_common.c b/arch/s390/kernel/perf_cpum_cf_common.c index 2300fbaac556..30f0242de4a5 100644 --- a/arch/s390/kernel/perf_cpum_cf_common.c +++ b/arch/s390/kernel/perf_cpum_cf_common.c @@ -29,7 +29,11 @@ DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events) = { }, .alert = ATOMIC64_INIT(0), .state = 0, + .dev_state = 0, .flags = 0, + .used = 0, + .usedss = 0, + .sets = 0 }; /* Indicator whether the CPU-Measurement Counter Facility Support is ready */ static bool cpum_cf_initalized; @@ -96,25 +100,10 @@ bool kernel_cpumcf_avail(void) } EXPORT_SYMBOL(kernel_cpumcf_avail); - -/* Reserve/release functions for sharing perf hardware */ -static DEFINE_SPINLOCK(cpumcf_owner_lock); -static void *cpumcf_owner; - /* Initialize the CPU-measurement counter facility */ int __kernel_cpumcf_begin(void) { int flags = PMC_INIT; - int err = 0; - - spin_lock(&cpumcf_owner_lock); - if (cpumcf_owner) - err = -EBUSY; - else - cpumcf_owner = __builtin_return_address(0); - spin_unlock(&cpumcf_owner_lock); - if (err) - return err; on_each_cpu(cpum_cf_setup_cpu, &flags, 1); irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); @@ -144,10 +133,6 @@ void __kernel_cpumcf_end(void) on_each_cpu(cpum_cf_setup_cpu, &flags, 1); irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); - - spin_lock(&cpumcf_owner_lock); - cpumcf_owner = NULL; - spin_unlock(&cpumcf_owner_lock); } EXPORT_SYMBOL(__kernel_cpumcf_end); @@ -161,11 +146,13 @@ static int cpum_cf_setup(unsigned int cpu, int flags) static int cpum_cf_online_cpu(unsigned int cpu) { - return cpum_cf_setup(cpu, PMC_INIT); + cpum_cf_setup(cpu, PMC_INIT); + return cfset_online_cpu(cpu); } static int cpum_cf_offline_cpu(unsigned int cpu) { + cfset_offline_cpu(cpu); return cpum_cf_setup(cpu, PMC_RELEASE); } diff --git a/arch/s390/kernel/perf_cpum_cf_diag.c b/arch/s390/kernel/perf_cpum_cf_diag.c deleted file mode 100644 index 08c985c1097c..000000000000 --- a/arch/s390/kernel/perf_cpum_cf_diag.c +++ /dev/null @@ -1,1148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Performance event support for s390x - CPU-measurement Counter Sets - * - * Copyright IBM Corp. 2019, 2021 - * Author(s): Hendrik Brueckner - * Thomas Richer - */ -#define KMSG_COMPONENT "cpum_cf_diag" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ - /* interval in seconds */ -static unsigned int cf_diag_cpu_speed; -static debug_info_t *cf_diag_dbg; - -struct cf_diag_csd { /* Counter set data per CPU */ - size_t used; /* Bytes used in data/start */ - unsigned char start[PAGE_SIZE]; /* Counter set at event start */ - unsigned char data[PAGE_SIZE]; /* Counter set at event delete */ - unsigned int sets; /* # Counter set saved in data */ -}; -static DEFINE_PER_CPU(struct cf_diag_csd, cf_diag_csd); - -/* Counter sets are stored as data stream in a page sized memory buffer and - * exported to user space via raw data attached to the event sample data. - * Each counter set starts with an eight byte header consisting of: - * - a two byte eye catcher (0xfeef) - * - a one byte counter set number - * - a two byte counter set size (indicates the number of counters in this set) - * - a three byte reserved value (must be zero) to make the header the same - * size as a counter value. - * All counter values are eight byte in size. - * - * All counter sets are followed by a 64 byte trailer. - * The trailer consists of a: - * - flag field indicating valid fields when corresponding bit set - * - the counter facility first and second version number - * - the CPU speed if nonzero - * - the time stamp the counter sets have been collected - * - the time of day (TOD) base value - * - the machine type. - * - * The counter sets are saved when the process is prepared to be executed on a - * CPU and saved again when the process is going to be removed from a CPU. - * The difference of both counter sets are calculated and stored in the event - * sample data area. - */ - -struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */ - unsigned int def:16; /* 0-15 Data Entry Format */ - unsigned int set:16; /* 16-31 Counter set identifier */ - unsigned int ctr:16; /* 32-47 Number of stored counters */ - unsigned int res1:16; /* 48-63 Reserved */ -}; - -struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */ - /* 0 - 7 */ - union { - struct { - unsigned int clock_base:1; /* TOD clock base set */ - unsigned int speed:1; /* CPU speed set */ - /* Measurement alerts */ - unsigned int mtda:1; /* Loss of MT ctr. data alert */ - unsigned int caca:1; /* Counter auth. change alert */ - unsigned int lcda:1; /* Loss of counter data alert */ - }; - unsigned long flags; /* 0-63 All indicators */ - }; - /* 8 - 15 */ - unsigned int cfvn:16; /* 64-79 Ctr First Version */ - unsigned int csvn:16; /* 80-95 Ctr Second Version */ - unsigned int cpu_speed:32; /* 96-127 CPU speed */ - /* 16 - 23 */ - unsigned long timestamp; /* 128-191 Timestamp (TOD) */ - /* 24 - 55 */ - union { - struct { - unsigned long progusage1; - unsigned long progusage2; - unsigned long progusage3; - unsigned long tod_base; - }; - unsigned long progusage[4]; - }; - /* 56 - 63 */ - unsigned int mach_type:16; /* Machine type */ - unsigned int res1:16; /* Reserved */ - unsigned int res2:32; /* Reserved */ -}; - -/* Create the trailer data at the end of a page. */ -static void cf_diag_trailer(struct cf_trailer_entry *te) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cpuid cpuid; - - te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */ - te->csvn = cpuhw->info.csvn; - - get_cpu_id(&cpuid); /* Machine type */ - te->mach_type = cpuid.machine; - te->cpu_speed = cf_diag_cpu_speed; - if (te->cpu_speed) - te->speed = 1; - te->clock_base = 1; /* Save clock base */ - te->tod_base = tod_clock_base.tod; - te->timestamp = get_tod_clock_fast(); -} - -/* - * Change the CPUMF state to active. - * Enable and activate the CPU-counter sets according - * to the per-cpu control state. - */ -static void cf_diag_enable(struct pmu *pmu) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - int err; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s pmu %p cpu %d flags %#x state %#llx\n", - __func__, pmu, smp_processor_id(), cpuhw->flags, - cpuhw->state); - if (cpuhw->flags & PMU_F_ENABLED) - return; - - err = lcctl(cpuhw->state); - if (err) { - pr_err("Enabling the performance measuring unit " - "failed with rc=%x\n", err); - return; - } - cpuhw->flags |= PMU_F_ENABLED; -} - -/* - * Change the CPUMF state to inactive. - * Disable and enable (inactive) the CPU-counter sets according - * to the per-cpu control state. - */ -static void cf_diag_disable(struct pmu *pmu) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - u64 inactive; - int err; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s pmu %p cpu %d flags %#x state %#llx\n", - __func__, pmu, smp_processor_id(), cpuhw->flags, - cpuhw->state); - if (!(cpuhw->flags & PMU_F_ENABLED)) - return; - - inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); - err = lcctl(inactive); - if (err) { - pr_err("Disabling the performance measuring unit " - "failed with rc=%x\n", err); - return; - } - cpuhw->flags &= ~PMU_F_ENABLED; -} - -/* Number of perf events counting hardware events */ -static atomic_t cf_diag_events = ATOMIC_INIT(0); -/* Used to avoid races in calling reserve/release_cpumf_hardware */ -static DEFINE_MUTEX(cf_diag_reserve_mutex); - -/* Release the PMU if event is the last perf event */ -static void cf_diag_perf_event_destroy(struct perf_event *event) -{ - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d cf_diag_events %d\n", - __func__, event, smp_processor_id(), - atomic_read(&cf_diag_events)); - if (atomic_dec_return(&cf_diag_events) == 0) - __kernel_cpumcf_end(); -} - -static int get_authctrsets(void) -{ - struct cpu_cf_events *cpuhw; - unsigned long auth = 0; - enum cpumf_ctr_set i; - - cpuhw = &get_cpu_var(cpu_cf_events); - for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) - auth |= cpumf_ctr_ctl[i]; - } - put_cpu_var(cpu_cf_events); - return auth; -} - -/* Setup the event. Test for authorized counter sets and only include counter - * sets which are authorized at the time of the setup. Including unauthorized - * counter sets result in specification exception (and panic). - */ -static int __hw_perf_event_init(struct perf_event *event) -{ - struct perf_event_attr *attr = &event->attr; - int err = 0; - - debug_sprintf_event(cf_diag_dbg, 5, "%s event %p cpu %d\n", __func__, - event, event->cpu); - - event->hw.config = attr->config; - - /* Add all authorized counter sets to config_base. The - * the hardware init function is either called per-cpu or just once - * for all CPUS (event->cpu == -1). This depends on the whether - * counting is started for all CPUs or on a per workload base where - * the perf event moves from one CPU to another CPU. - * Checking the authorization on any CPU is fine as the hardware - * applies the same authorization settings to all CPUs. - */ - event->hw.config_base = get_authctrsets(); - - /* No authorized counter sets, nothing to count/sample */ - if (!event->hw.config_base) { - err = -EINVAL; - goto out; - } - - /* Set sample_period to indicate sampling */ - event->hw.sample_period = attr->sample_period; - local64_set(&event->hw.period_left, event->hw.sample_period); - event->hw.last_period = event->hw.sample_period; -out: - debug_sprintf_event(cf_diag_dbg, 5, "%s err %d config_base %#lx\n", - __func__, err, event->hw.config_base); - return err; -} - -/* Return 0 if the CPU-measurement counter facility is currently free - * and an error otherwise. - */ -static int cf_diag_perf_event_inuse(void) -{ - int err = 0; - - if (!atomic_inc_not_zero(&cf_diag_events)) { - mutex_lock(&cf_diag_reserve_mutex); - if (atomic_read(&cf_diag_events) == 0 && - __kernel_cpumcf_begin()) - err = -EBUSY; - else - err = atomic_inc_return(&cf_diag_events); - mutex_unlock(&cf_diag_reserve_mutex); - } - return err; -} - -static int cf_diag_event_init(struct perf_event *event) -{ - struct perf_event_attr *attr = &event->attr; - int err = -ENOENT; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d config %#llx type:%u " - "sample_type %#llx cf_diag_events %d\n", __func__, - event, event->cpu, attr->config, event->pmu->type, - attr->sample_type, atomic_read(&cf_diag_events)); - - if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG || - event->attr.type != event->pmu->type) - goto out; - - /* Raw events are used to access counters directly, - * hence do not permit excludes. - * This event is usesless without PERF_SAMPLE_RAW to return counter set - * values as raw data. - */ - if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv || - !(attr->sample_type & (PERF_SAMPLE_CPU | PERF_SAMPLE_RAW))) { - err = -EOPNOTSUPP; - goto out; - } - - /* Initialize for using the CPU-measurement counter facility */ - err = cf_diag_perf_event_inuse(); - if (err < 0) - goto out; - event->destroy = cf_diag_perf_event_destroy; - - err = __hw_perf_event_init(event); - if (unlikely(err)) - event->destroy(event); -out: - debug_sprintf_event(cf_diag_dbg, 5, "%s err %d\n", __func__, err); - return err; -} - -static void cf_diag_read(struct perf_event *event) -{ - debug_sprintf_event(cf_diag_dbg, 5, "%s event %p\n", __func__, event); -} - -/* Calculate memory needed to store all counter sets together with header and - * trailer data. This is independend of the counter set authorization which - * can vary depending on the configuration. - */ -static size_t cf_diag_ctrset_maxsize(struct cpumf_ctr_info *info) -{ - size_t max_size = sizeof(struct cf_trailer_entry); - enum cpumf_ctr_set i; - - for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - size_t size = cpum_cf_ctrset_size(i, info); - - if (size) - max_size += size * sizeof(u64) + - sizeof(struct cf_ctrset_entry); - } - debug_sprintf_event(cf_diag_dbg, 5, "%s max_size %zu\n", __func__, - max_size); - - return max_size; -} - -/* Read a counter set. The counter set number determines which counter set and - * the CPUM-CF first and second version number determine the number of - * available counters in this counter set. - * Each counter set starts with header containing the counter set number and - * the number of 8 byte counters. - * - * The functions returns the number of bytes occupied by this counter set - * including the header. - * If there is no counter in the counter set, this counter set is useless and - * zero is returned on this case. - */ -static size_t cf_diag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, - size_t room) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - size_t ctrset_size, need = 0; - int rc = 3; /* Assume write failure */ - - ctrdata->def = CF_DIAG_CTRSET_DEF; - ctrdata->set = ctrset; - ctrdata->res1 = 0; - ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info); - - if (ctrset_size) { /* Save data */ - need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); - if (need <= room) - rc = ctr_stcctm(ctrset, ctrset_size, - (u64 *)(ctrdata + 1)); - if (rc != 3) - ctrdata->ctr = ctrset_size; - else - need = 0; - } - - debug_sprintf_event(cf_diag_dbg, 6, - "%s ctrset %d ctrset_size %zu cfvn %d csvn %d" - " need %zd rc %d\n", - __func__, ctrset, ctrset_size, cpuhw->info.cfvn, - cpuhw->info.csvn, need, rc); - return need; -} - -/* Read out all counter sets and save them in the provided data buffer. - * The last 64 byte host an artificial trailer entry. - */ -static size_t cf_diag_getctr(void *data, size_t sz, unsigned long auth) -{ - struct cf_trailer_entry *trailer; - size_t offset = 0, done; - int i; - - memset(data, 0, sz); - sz -= sizeof(*trailer); /* Always room for trailer */ - for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - struct cf_ctrset_entry *ctrdata = data + offset; - - if (!(auth & cpumf_ctr_ctl[i])) - continue; /* Counter set not authorized */ - - done = cf_diag_getctrset(ctrdata, i, sz - offset); - offset += done; - debug_sprintf_event(cf_diag_dbg, 6, - "%s ctrset %d offset %zu done %zu\n", - __func__, i, offset, done); - } - trailer = data + offset; - cf_diag_trailer(trailer); - return offset + sizeof(*trailer); -} - -/* Calculate the difference for each counter in a counter set. */ -static void cf_diag_diffctrset(u64 *pstart, u64 *pstop, int counters) -{ - for (; --counters >= 0; ++pstart, ++pstop) - if (*pstop >= *pstart) - *pstop -= *pstart; - else - *pstop = *pstart - *pstop; -} - -/* Scan the counter sets and calculate the difference of each counter - * in each set. The result is the increment of each counter during the - * period the counter set has been activated. - * - * Return true on success. - */ -static int cf_diag_diffctr(struct cf_diag_csd *csd, unsigned long auth) -{ - struct cf_trailer_entry *trailer_start, *trailer_stop; - struct cf_ctrset_entry *ctrstart, *ctrstop; - size_t offset = 0; - - auth &= (1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1; - do { - ctrstart = (struct cf_ctrset_entry *)(csd->start + offset); - ctrstop = (struct cf_ctrset_entry *)(csd->data + offset); - - if (memcmp(ctrstop, ctrstart, sizeof(*ctrstop))) { - pr_err("cpum_cf_diag counter set compare error " - "in set %i\n", ctrstart->set); - return 0; - } - auth &= ~cpumf_ctr_ctl[ctrstart->set]; - if (ctrstart->def == CF_DIAG_CTRSET_DEF) { - cf_diag_diffctrset((u64 *)(ctrstart + 1), - (u64 *)(ctrstop + 1), ctrstart->ctr); - offset += ctrstart->ctr * sizeof(u64) + - sizeof(*ctrstart); - } - debug_sprintf_event(cf_diag_dbg, 6, - "%s set %d ctr %d offset %zu auth %lx\n", - __func__, ctrstart->set, ctrstart->ctr, - offset, auth); - } while (ctrstart->def && auth); - - /* Save time_stamp from start of event in stop's trailer */ - trailer_start = (struct cf_trailer_entry *)(csd->start + offset); - trailer_stop = (struct cf_trailer_entry *)(csd->data + offset); - trailer_stop->progusage[0] = trailer_start->timestamp; - - return 1; -} - -/* Create perf event sample with the counter sets as raw data. The sample - * is then pushed to the event subsystem and the function checks for - * possible event overflows. If an event overflow occurs, the PMU is - * stopped. - * - * Return non-zero if an event overflow occurred. - */ -static int cf_diag_push_sample(struct perf_event *event, - struct cf_diag_csd *csd) -{ - struct perf_sample_data data; - struct perf_raw_record raw; - struct pt_regs regs; - int overflow; - - /* Setup perf sample */ - perf_sample_data_init(&data, 0, event->hw.last_period); - memset(®s, 0, sizeof(regs)); - memset(&raw, 0, sizeof(raw)); - - if (event->attr.sample_type & PERF_SAMPLE_CPU) - data.cpu_entry.cpu = event->cpu; - if (event->attr.sample_type & PERF_SAMPLE_RAW) { - raw.frag.size = csd->used; - raw.frag.data = csd->data; - raw.size = csd->used; - data.raw = &raw; - } - - overflow = perf_event_overflow(event, &data, ®s); - debug_sprintf_event(cf_diag_dbg, 6, - "%s event %p cpu %d sample_type %#llx raw %d " - "ov %d\n", __func__, event, event->cpu, - event->attr.sample_type, raw.size, overflow); - if (overflow) - event->pmu->stop(event, 0); - - perf_event_update_userpage(event); - return overflow; -} - -static void cf_diag_start(struct perf_event *event, int flags) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cf_diag_csd *csd = this_cpu_ptr(&cf_diag_csd); - struct hw_perf_event *hwc = &event->hw; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d flags %#x hwc-state %#x\n", - __func__, event, event->cpu, flags, hwc->state); - if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) - return; - - /* (Re-)enable and activate all counter sets */ - lcctl(0); /* Reset counter sets */ - hwc->state = 0; - ctr_set_multiple_enable(&cpuhw->state, hwc->config_base); - lcctl(cpuhw->state); /* Enable counter sets */ - csd->used = cf_diag_getctr(csd->start, sizeof(csd->start), - event->hw.config_base); - ctr_set_multiple_start(&cpuhw->state, hwc->config_base); - /* Function cf_diag_enable() starts the counter sets. */ -} - -static void cf_diag_stop(struct perf_event *event, int flags) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cf_diag_csd *csd = this_cpu_ptr(&cf_diag_csd); - struct hw_perf_event *hwc = &event->hw; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d flags %#x hwc-state %#x\n", - __func__, event, event->cpu, flags, hwc->state); - - /* Deactivate all counter sets */ - ctr_set_multiple_stop(&cpuhw->state, hwc->config_base); - local64_inc(&event->count); - csd->used = cf_diag_getctr(csd->data, sizeof(csd->data), - event->hw.config_base); - if (cf_diag_diffctr(csd, event->hw.config_base)) - cf_diag_push_sample(event, csd); - hwc->state |= PERF_HES_STOPPED; -} - -static int cf_diag_add(struct perf_event *event, int flags) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - int err = 0; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d flags %#x cpuhw %p\n", - __func__, event, event->cpu, flags, cpuhw); - - if (cpuhw->flags & PMU_F_IN_USE) { - err = -EAGAIN; - goto out; - } - - event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; - - cpuhw->flags |= PMU_F_IN_USE; - if (flags & PERF_EF_START) - cf_diag_start(event, PERF_EF_RELOAD); -out: - debug_sprintf_event(cf_diag_dbg, 5, "%s err %d\n", __func__, err); - return err; -} - -static void cf_diag_del(struct perf_event *event, int flags) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - - debug_sprintf_event(cf_diag_dbg, 5, - "%s event %p cpu %d flags %#x\n", - __func__, event, event->cpu, flags); - - cf_diag_stop(event, PERF_EF_UPDATE); - ctr_set_multiple_stop(&cpuhw->state, event->hw.config_base); - ctr_set_multiple_disable(&cpuhw->state, event->hw.config_base); - cpuhw->flags &= ~PMU_F_IN_USE; -} - -/* Default counter set events and format attribute groups */ - -CPUMF_EVENT_ATTR(CF_DIAG, CF_DIAG, PERF_EVENT_CPUM_CF_DIAG); - -static struct attribute *cf_diag_events_attr[] = { - CPUMF_EVENT_PTR(CF_DIAG, CF_DIAG), - NULL, -}; - -PMU_FORMAT_ATTR(event, "config:0-63"); - -static struct attribute *cf_diag_format_attr[] = { - &format_attr_event.attr, - NULL, -}; - -static struct attribute_group cf_diag_events_group = { - .name = "events", - .attrs = cf_diag_events_attr, -}; -static struct attribute_group cf_diag_format_group = { - .name = "format", - .attrs = cf_diag_format_attr, -}; -static const struct attribute_group *cf_diag_attr_groups[] = { - &cf_diag_events_group, - &cf_diag_format_group, - NULL, -}; - -/* Performance monitoring unit for s390x */ -static struct pmu cf_diag = { - .task_ctx_nr = perf_sw_context, - .pmu_enable = cf_diag_enable, - .pmu_disable = cf_diag_disable, - .event_init = cf_diag_event_init, - .add = cf_diag_add, - .del = cf_diag_del, - .start = cf_diag_start, - .stop = cf_diag_stop, - .read = cf_diag_read, - - .attr_groups = cf_diag_attr_groups -}; - -/* Get the CPU speed, try sampling facility first and CPU attributes second. */ -static void cf_diag_get_cpu_speed(void) -{ - if (cpum_sf_avail()) { /* Sampling facility first */ - struct hws_qsi_info_block si; - - memset(&si, 0, sizeof(si)); - if (!qsi(&si)) { - cf_diag_cpu_speed = si.cpu_speed; - return; - } - } - - if (test_facility(34)) { /* CPU speed extract static part */ - unsigned long mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0); - - if (mhz != -1UL) - cf_diag_cpu_speed = mhz & 0xffffffff; - } -} - -/* Code to create device and file I/O operations */ -static atomic_t ctrset_opencnt = ATOMIC_INIT(0); /* Excl. access */ - -static int cf_diag_open(struct inode *inode, struct file *file) -{ - int err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (atomic_xchg(&ctrset_opencnt, 1)) - return -EBUSY; - - /* Avoid concurrent access with perf_event_open() system call */ - mutex_lock(&cf_diag_reserve_mutex); - if (atomic_read(&cf_diag_events) || __kernel_cpumcf_begin()) - err = -EBUSY; - mutex_unlock(&cf_diag_reserve_mutex); - if (err) { - atomic_set(&ctrset_opencnt, 0); - return err; - } - file->private_data = NULL; - debug_sprintf_event(cf_diag_dbg, 2, "%s\n", __func__); - /* nonseekable_open() never fails */ - return nonseekable_open(inode, file); -} - -/* Variables for ioctl() interface support */ -static DEFINE_MUTEX(cf_diag_ctrset_mutex); -static struct cf_diag_ctrset { - unsigned long ctrset; /* Bit mask of counter set to read */ - cpumask_t mask; /* CPU mask to read from */ -} cf_diag_ctrset; - -static void cf_diag_ctrset_clear(void) -{ - cpumask_clear(&cf_diag_ctrset.mask); - cf_diag_ctrset.ctrset = 0; -} - -static void cf_diag_release_cpu(void *p) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - - debug_sprintf_event(cf_diag_dbg, 3, "%s cpu %d\n", __func__, - smp_processor_id()); - lcctl(0); /* Reset counter sets */ - cpuhw->state = 0; /* Save state in CPU hardware state */ -} - -/* Release function is also called when application gets terminated without - * doing a proper ioctl(..., S390_HWCTR_STOP, ...) command. - * Since only one application is allowed to open the device, simple stop all - * CPU counter sets. - */ -static int cf_diag_release(struct inode *inode, struct file *file) -{ - on_each_cpu(cf_diag_release_cpu, NULL, 1); - cf_diag_ctrset_clear(); - atomic_set(&ctrset_opencnt, 0); - __kernel_cpumcf_end(); - debug_sprintf_event(cf_diag_dbg, 2, "%s\n", __func__); - return 0; -} - -struct cf_diag_call_on_cpu_parm { /* Parm struct for smp_call_on_cpu */ - unsigned int sets; /* Counter set bit mask */ - atomic_t cpus_ack; /* # CPUs successfully executed func */ -}; - -static int cf_diag_all_copy(unsigned long arg, cpumask_t *mask) -{ - struct s390_ctrset_read __user *ctrset_read; - unsigned int cpu, cpus, rc; - void __user *uptr; - - ctrset_read = (struct s390_ctrset_read __user *)arg; - uptr = ctrset_read->data; - for_each_cpu(cpu, mask) { - struct cf_diag_csd *csd = per_cpu_ptr(&cf_diag_csd, cpu); - struct s390_ctrset_cpudata __user *ctrset_cpudata; - - ctrset_cpudata = uptr; - debug_sprintf_event(cf_diag_dbg, 5, "%s cpu %d used %zd\n", - __func__, cpu, csd->used); - rc = put_user(cpu, &ctrset_cpudata->cpu_nr); - rc |= put_user(csd->sets, &ctrset_cpudata->no_sets); - rc |= copy_to_user(ctrset_cpudata->data, csd->data, csd->used); - if (rc) - return -EFAULT; - uptr += sizeof(struct s390_ctrset_cpudata) + csd->used; - cond_resched(); - } - cpus = cpumask_weight(mask); - if (put_user(cpus, &ctrset_read->no_cpus)) - return -EFAULT; - debug_sprintf_event(cf_diag_dbg, 5, "%s copied %ld\n", - __func__, uptr - (void __user *)ctrset_read->data); - return 0; -} - -static size_t cf_diag_cpuset_read(struct s390_ctrset_setdata *p, int ctrset, - int ctrset_size, size_t room) -{ - size_t need = 0; - int rc = -1; - - need = sizeof(*p) + sizeof(u64) * ctrset_size; - debug_sprintf_event(cf_diag_dbg, 5, - "%s room %zd need %zd set %#x set_size %d\n", - __func__, room, need, ctrset, ctrset_size); - if (need <= room) { - p->set = cpumf_ctr_ctl[ctrset]; - p->no_cnts = ctrset_size; - rc = ctr_stcctm(ctrset, ctrset_size, (u64 *)p->cv); - if (rc == 3) /* Nothing stored */ - need = 0; - } - debug_sprintf_event(cf_diag_dbg, 5, "%s need %zd rc %d\n", __func__, - need, rc); - return need; -} - -/* Read all counter sets. Since the perf_event_open() system call with - * event cpum_cf_diag/.../ is blocked when this interface is active, reuse - * the perf_event_open() data buffer to store the counter sets. - */ -static void cf_diag_cpu_read(void *parm) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cf_diag_csd *csd = this_cpu_ptr(&cf_diag_csd); - struct cf_diag_call_on_cpu_parm *p = parm; - int set, set_size; - size_t space; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s new %#x flags %#x state %#llx\n", - __func__, p->sets, cpuhw->flags, - cpuhw->state); - /* No data saved yet */ - csd->used = 0; - csd->sets = 0; - memset(csd->data, 0, sizeof(csd->data)); - - /* Scan the counter sets */ - for (set = CPUMF_CTR_SET_BASIC; set < CPUMF_CTR_SET_MAX; ++set) { - struct s390_ctrset_setdata *sp = (void *)csd->data + csd->used; - - if (!(p->sets & cpumf_ctr_ctl[set])) - continue; /* Counter set not in list */ - set_size = cpum_cf_ctrset_size(set, &cpuhw->info); - space = sizeof(csd->data) - csd->used; - space = cf_diag_cpuset_read(sp, set, set_size, space); - if (space) { - csd->used += space; - csd->sets += 1; - } - debug_sprintf_event(cf_diag_dbg, 5, "%s sp %px space %zd\n", - __func__, sp, space); - } - debug_sprintf_event(cf_diag_dbg, 5, "%s sets %d used %zd\n", __func__, - csd->sets, csd->used); -} - -static int cf_diag_all_read(unsigned long arg) -{ - struct cf_diag_call_on_cpu_parm p; - cpumask_var_t mask; - int rc; - - debug_sprintf_event(cf_diag_dbg, 5, "%s\n", __func__); - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - p.sets = cf_diag_ctrset.ctrset; - cpumask_and(mask, &cf_diag_ctrset.mask, cpu_online_mask); - on_each_cpu_mask(mask, cf_diag_cpu_read, &p, 1); - rc = cf_diag_all_copy(arg, mask); - free_cpumask_var(mask); - debug_sprintf_event(cf_diag_dbg, 5, "%s rc %d\n", __func__, rc); - return rc; -} - -/* Stop all counter sets via ioctl interface */ -static void cf_diag_ioctl_off(void *parm) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cf_diag_call_on_cpu_parm *p = parm; - int rc; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s new %#x flags %#x state %#llx\n", - __func__, p->sets, cpuhw->flags, - cpuhw->state); - - ctr_set_multiple_disable(&cpuhw->state, p->sets); - ctr_set_multiple_stop(&cpuhw->state, p->sets); - rc = lcctl(cpuhw->state); /* Stop counter sets */ - if (!cpuhw->state) - cpuhw->flags &= ~PMU_F_IN_USE; - debug_sprintf_event(cf_diag_dbg, 5, - "%s rc %d flags %#x state %#llx\n", __func__, - rc, cpuhw->flags, cpuhw->state); -} - -/* Start counter sets on particular CPU */ -static void cf_diag_ioctl_on(void *parm) -{ - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); - struct cf_diag_call_on_cpu_parm *p = parm; - int rc; - - debug_sprintf_event(cf_diag_dbg, 5, - "%s new %#x flags %#x state %#llx\n", - __func__, p->sets, cpuhw->flags, - cpuhw->state); - - if (!(cpuhw->flags & PMU_F_IN_USE)) - cpuhw->state = 0; - cpuhw->flags |= PMU_F_IN_USE; - rc = lcctl(cpuhw->state); /* Reset unused counter sets */ - ctr_set_multiple_enable(&cpuhw->state, p->sets); - ctr_set_multiple_start(&cpuhw->state, p->sets); - rc |= lcctl(cpuhw->state); /* Start counter sets */ - if (!rc) - atomic_inc(&p->cpus_ack); - debug_sprintf_event(cf_diag_dbg, 5, "%s rc %d state %#llx\n", - __func__, rc, cpuhw->state); -} - -static int cf_diag_all_stop(void) -{ - struct cf_diag_call_on_cpu_parm p = { - .sets = cf_diag_ctrset.ctrset, - }; - cpumask_var_t mask; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - cpumask_and(mask, &cf_diag_ctrset.mask, cpu_online_mask); - on_each_cpu_mask(mask, cf_diag_ioctl_off, &p, 1); - free_cpumask_var(mask); - return 0; -} - -static int cf_diag_all_start(void) -{ - struct cf_diag_call_on_cpu_parm p = { - .sets = cf_diag_ctrset.ctrset, - .cpus_ack = ATOMIC_INIT(0), - }; - cpumask_var_t mask; - int rc = 0; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - cpumask_and(mask, &cf_diag_ctrset.mask, cpu_online_mask); - on_each_cpu_mask(mask, cf_diag_ioctl_on, &p, 1); - if (atomic_read(&p.cpus_ack) != cpumask_weight(mask)) { - on_each_cpu_mask(mask, cf_diag_ioctl_off, &p, 1); - rc = -EIO; - } - free_cpumask_var(mask); - return rc; -} - -/* Return the maximum required space for all possible CPUs in case one - * CPU will be onlined during the START, READ, STOP cycles. - * To find out the size of the counter sets, any one CPU will do. They - * all have the same counter sets. - */ -static size_t cf_diag_needspace(unsigned int sets) -{ - struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events); - size_t bytes = 0; - int i; - - for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - if (!(sets & cpumf_ctr_ctl[i])) - continue; - bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) + - sizeof(((struct s390_ctrset_setdata *)0)->set) + - sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); - } - bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids * - (bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) + - sizeof(((struct s390_ctrset_cpudata *)0)->no_sets)); - debug_sprintf_event(cf_diag_dbg, 5, "%s bytes %ld\n", __func__, - bytes); - put_cpu_ptr(&cpu_cf_events); - return bytes; -} - -static long cf_diag_ioctl_read(unsigned long arg) -{ - struct s390_ctrset_read read; - int ret = 0; - - debug_sprintf_event(cf_diag_dbg, 5, "%s\n", __func__); - if (copy_from_user(&read, (char __user *)arg, sizeof(read))) - return -EFAULT; - ret = cf_diag_all_read(arg); - debug_sprintf_event(cf_diag_dbg, 5, "%s ret %d\n", __func__, ret); - return ret; -} - -static long cf_diag_ioctl_stop(void) -{ - int ret; - - debug_sprintf_event(cf_diag_dbg, 5, "%s\n", __func__); - ret = cf_diag_all_stop(); - cf_diag_ctrset_clear(); - debug_sprintf_event(cf_diag_dbg, 5, "%s ret %d\n", __func__, ret); - return ret; -} - -static long cf_diag_ioctl_start(unsigned long arg) -{ - struct s390_ctrset_start __user *ustart; - struct s390_ctrset_start start; - void __user *umask; - unsigned int len; - int ret = 0; - size_t need; - - if (cf_diag_ctrset.ctrset) - return -EBUSY; - ustart = (struct s390_ctrset_start __user *)arg; - if (copy_from_user(&start, ustart, sizeof(start))) - return -EFAULT; - if (start.version != S390_HWCTR_START_VERSION) - return -EINVAL; - if (start.counter_sets & ~(cpumf_ctr_ctl[CPUMF_CTR_SET_BASIC] | - cpumf_ctr_ctl[CPUMF_CTR_SET_USER] | - cpumf_ctr_ctl[CPUMF_CTR_SET_CRYPTO] | - cpumf_ctr_ctl[CPUMF_CTR_SET_EXT] | - cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG])) - return -EINVAL; /* Invalid counter set */ - if (!start.counter_sets) - return -EINVAL; /* No counter set at all? */ - cpumask_clear(&cf_diag_ctrset.mask); - len = min_t(u64, start.cpumask_len, cpumask_size()); - umask = (void __user *)start.cpumask; - if (copy_from_user(&cf_diag_ctrset.mask, umask, len)) - return -EFAULT; - if (cpumask_empty(&cf_diag_ctrset.mask)) - return -EINVAL; - need = cf_diag_needspace(start.counter_sets); - if (put_user(need, &ustart->data_bytes)) - ret = -EFAULT; - if (ret) - goto out; - cf_diag_ctrset.ctrset = start.counter_sets; - ret = cf_diag_all_start(); -out: - if (ret) - cf_diag_ctrset_clear(); - debug_sprintf_event(cf_diag_dbg, 2, "%s sets %#lx need %ld ret %d\n", - __func__, cf_diag_ctrset.ctrset, need, ret); - return ret; -} - -static long cf_diag_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret; - - debug_sprintf_event(cf_diag_dbg, 2, "%s cmd %#x arg %lx\n", __func__, - cmd, arg); - get_online_cpus(); - mutex_lock(&cf_diag_ctrset_mutex); - switch (cmd) { - case S390_HWCTR_START: - ret = cf_diag_ioctl_start(arg); - break; - case S390_HWCTR_STOP: - ret = cf_diag_ioctl_stop(); - break; - case S390_HWCTR_READ: - ret = cf_diag_ioctl_read(arg); - break; - default: - ret = -ENOTTY; - break; - } - mutex_unlock(&cf_diag_ctrset_mutex); - put_online_cpus(); - debug_sprintf_event(cf_diag_dbg, 2, "%s ret %d\n", __func__, ret); - return ret; -} - -static const struct file_operations cf_diag_fops = { - .owner = THIS_MODULE, - .open = cf_diag_open, - .release = cf_diag_release, - .unlocked_ioctl = cf_diag_ioctl, - .compat_ioctl = cf_diag_ioctl, - .llseek = no_llseek -}; - -static struct miscdevice cf_diag_dev = { - .name = S390_HWCTR_DEVICE, - .minor = MISC_DYNAMIC_MINOR, - .fops = &cf_diag_fops, -}; - -static int cf_diag_online_cpu(unsigned int cpu) -{ - struct cf_diag_call_on_cpu_parm p; - - mutex_lock(&cf_diag_ctrset_mutex); - if (!cf_diag_ctrset.ctrset) - goto out; - p.sets = cf_diag_ctrset.ctrset; - cf_diag_ioctl_on(&p); -out: - mutex_unlock(&cf_diag_ctrset_mutex); - return 0; -} - -static int cf_diag_offline_cpu(unsigned int cpu) -{ - struct cf_diag_call_on_cpu_parm p; - - mutex_lock(&cf_diag_ctrset_mutex); - if (!cf_diag_ctrset.ctrset) - goto out; - p.sets = cf_diag_ctrset.ctrset; - cf_diag_ioctl_off(&p); -out: - mutex_unlock(&cf_diag_ctrset_mutex); - return 0; -} - -/* Initialize the counter set PMU to generate complete counter set data as - * event raw data. This relies on the CPU Measurement Counter Facility device - * already being loaded and initialized. - */ -static int __init cf_diag_init(void) -{ - struct cpumf_ctr_info info; - size_t need; - int rc; - - if (!kernel_cpumcf_avail() || !stccm_avail() || qctri(&info)) - return -ENODEV; - cf_diag_get_cpu_speed(); - - /* Make sure the counter set data fits into predefined buffer. */ - need = cf_diag_ctrset_maxsize(&info); - if (need > sizeof(((struct cf_diag_csd *)0)->start)) { - pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", - need); - return -ENOMEM; - } - - rc = misc_register(&cf_diag_dev); - if (rc) { - pr_err("Registration of /dev/" S390_HWCTR_DEVICE - "failed rc=%d\n", rc); - goto out; - } - - /* Setup s390dbf facility */ - cf_diag_dbg = debug_register(KMSG_COMPONENT, 2, 1, 128); - if (!cf_diag_dbg) { - pr_err("Registration of s390dbf(cpum_cf_diag) failed\n"); - rc = -ENOMEM; - goto out_dbf; - } - debug_register_view(cf_diag_dbg, &debug_sprintf_view); - - rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", -1); - if (rc) { - pr_err("Registration of PMU(cpum_cf_diag) failed with rc=%i\n", - rc); - goto out_perf; - } - rc = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_S390_CFD_ONLINE, - "perf/s390/cfd:online", - cf_diag_online_cpu, cf_diag_offline_cpu); - if (!rc) - goto out; - - pr_err("Registration of CPUHP_AP_PERF_S390_CFD_ONLINE failed rc=%i\n", - rc); - perf_pmu_unregister(&cf_diag); -out_perf: - debug_unregister_view(cf_diag_dbg, &debug_sprintf_view); - debug_unregister(cf_diag_dbg); -out_dbf: - misc_deregister(&cf_diag_dev); -out: - return rc; -} -device_initcall(cf_diag_init); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7ae5dde9c54d..350e94d0cac2 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -166,6 +166,12 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, p->thread.acrs[1] = (unsigned int)tls; } } + /* + * s390 stores the svc return address in arch_data when calling + * sigreturn()/restart_syscall() via vdso. 1 means no valid address + * stored. + */ + p->restart_block.arch_data = 1; return 0; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index b58ee83f30e3..ff0f9e838916 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -354,7 +354,7 @@ void __init arch_call_rest_init(void) set_task_stack_end_magic(current); stack += STACK_INIT_OFFSET; S390_lowcore.kernel_stack = stack; - CALL_ON_STACK_NORETURN(rest_init, stack); + call_on_stack_noreturn(rest_init, stack); } static void __init setup_lowcore_dat_off(void) @@ -442,6 +442,7 @@ static void __init setup_lowcore_dat_off(void) lc->br_r1_trampoline = 0x07f1; /* br %r1 */ lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW); lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW); + lc->preempt_count = PREEMPT_DISABLED; set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; @@ -1028,10 +1029,7 @@ void __init setup_arch(char **cmdline_p) ROOT_DEV = Root_RAM0; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_text, _etext, _edata, _end); if (IS_ENABLED(CONFIG_EXPOLINE_AUTO)) nospec_auto_detect(); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 080e7aed181f..78ef53b29958 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "entry.h" /* @@ -171,7 +172,6 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) fpregs_load(&user_sregs.fpregs, ¤t->thread.fpu); clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ - clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART); return 0; } @@ -334,15 +334,10 @@ static int setup_frame(int sig, struct k_sigaction *ka, /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & SA_RESTORER) { + if (ka->sa.sa_flags & SA_RESTORER) restorer = (unsigned long) ka->sa.sa_restorer; - } else { - /* Signal frame without vector registers are short ! */ - __u16 __user *svc = (void __user *) frame + frame_size - 2; - if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) - return -EFAULT; - restorer = (unsigned long) svc; - } + else + restorer = VDSO64_SYMBOL(current, sigreturn); /* Set up registers for signal handler */ regs->gprs[14] = restorer; @@ -397,14 +392,10 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ksig->ka.sa.sa_flags & SA_RESTORER) { + if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = (unsigned long) ksig->ka.sa.sa_restorer; - } else { - __u16 __user *svc = &frame->svc_insn; - if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc)) - return -EFAULT; - restorer = (unsigned long) svc; - } + else + restorer = VDSO64_SYMBOL(current, rt_sigreturn); /* Create siginfo on the signal stack */ if (copy_siginfo_to_user(&frame->info, &ksig->info)) @@ -501,7 +492,7 @@ void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) } /* No longer in a system call */ clear_pt_regs_flag(regs, PIF_SYSCALL); - clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART); + rseq_signal_deliver(&ksig, regs); if (is_compat_task()) handle_signal32(&ksig, oldset, regs); @@ -517,14 +508,20 @@ void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) switch (regs->gprs[2]) { case -ERESTART_RESTARTBLOCK: /* Restart with sys_restart_syscall */ - regs->int_code = __NR_restart_syscall; - fallthrough; + regs->gprs[2] = regs->orig_gpr2; + current->restart_block.arch_data = regs->psw.addr; + if (is_compat_task()) + regs->psw.addr = VDSO32_SYMBOL(current, restart_syscall); + else + regs->psw.addr = VDSO64_SYMBOL(current, restart_syscall); + if (test_thread_flag(TIF_SINGLE_STEP)) + clear_thread_flag(TIF_PER_TRAP); + break; case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - /* Restart system call with magic TIF bit. */ regs->gprs[2] = regs->orig_gpr2; - set_pt_regs_flag(regs, PIF_SYSCALL_RESTART); + regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); if (test_thread_flag(TIF_SINGLE_STEP)) clear_thread_flag(TIF_PER_TRAP); break; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index ff42d3aa0f00..8984711f72ed 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -210,6 +210,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->br_r1_trampoline = 0x07f1; /* br %r1 */ lc->return_lpswe = gen_lpswe(__LC_RETURN_PSW); lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW); + lc->preempt_count = PREEMPT_DISABLED; if (nmi_alloc_per_cpu(lc)) goto out; lowcore_ptr[cpu] = lc; @@ -300,24 +301,28 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) pcpu_sigp_retry(pcpu, SIGP_RESTART, 0); } +typedef void (pcpu_delegate_fn)(void *); + /* * Call function via PSW restart on pcpu and stop the current cpu. */ -static void __pcpu_delegate(void (*func)(void*), void *data) +static void __pcpu_delegate(pcpu_delegate_fn *func, void *data) { func(data); /* should not return */ } static void __no_sanitize_address pcpu_delegate(struct pcpu *pcpu, - void (*func)(void *), + pcpu_delegate_fn *func, void *data, unsigned long stack) { struct lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; unsigned long source_cpu = stap(); __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT); - if (pcpu->address == source_cpu) - CALL_ON_STACK(__pcpu_delegate, stack, 2, func, data); + if (pcpu->address == source_cpu) { + call_on_stack(2, stack, void, __pcpu_delegate, + pcpu_delegate_fn *, func, void *, data); + } /* Stop target cpu (if func returns this stops the current cpu). */ pcpu_sigp_retry(pcpu, SIGP_STOP, 0); /* Restart func on the target cpu and stop the current cpu. */ @@ -898,7 +903,7 @@ static void __no_sanitize_address smp_start_secondary(void *cpuvoid) S390_lowcore.restart_source = -1UL; __ctl_load(S390_lowcore.cregs_save_area, 0, 15); __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT); - CALL_ON_STACK_NORETURN(smp_init_secondary, S390_lowcore.kernel_stack); + call_on_stack_noreturn(smp_init_secondary, S390_lowcore.kernel_stack); } /* Upping and downing of CPUs */ diff --git a/arch/s390/kernel/syscall.c b/arch/s390/kernel/syscall.c index 76f7916cc30f..8fe2d23b64f4 100644 --- a/arch/s390/kernel/syscall.c +++ b/arch/s390/kernel/syscall.c @@ -108,7 +108,7 @@ SYSCALL_DEFINE0(ni_syscall) return -ENOSYS; } -void do_syscall(struct pt_regs *regs) +static void do_syscall(struct pt_regs *regs) { unsigned long nr; @@ -121,6 +121,10 @@ void do_syscall(struct pt_regs *regs) regs->gprs[2] = nr; + if (nr == __NR_restart_syscall && !(current->restart_block.arch_data & 1)) { + regs->psw.addr = current->restart_block.arch_data; + current->restart_block.arch_data = 1; + } nr = syscall_enter_from_user_mode_work(regs, nr); /* @@ -130,13 +134,16 @@ void do_syscall(struct pt_regs *regs) * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here * and if set, the syscall will be skipped. */ - if (!test_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)) { - regs->gprs[2] = -ENOSYS; - if (likely(nr < NR_syscalls)) - regs->gprs[2] = current->thread.sys_call_table[nr](regs); - } else { - clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET); - } + + if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET))) + goto out; + regs->gprs[2] = -ENOSYS; + if (likely(nr >= NR_syscalls)) + goto out; + do { + regs->gprs[2] = current->thread.sys_call_table[nr](regs); + } while (test_and_clear_pt_regs_flag(regs, PIF_EXECVE_PGSTE_RESTART)); +out: syscall_exit_to_user_mode_work(regs); } @@ -154,13 +161,8 @@ void noinstr __do_syscall(struct pt_regs *regs, int per_trap) if (per_trap) set_thread_flag(TIF_PER_TRAP); - for (;;) { - regs->flags = 0; - set_pt_regs_flag(regs, PIF_SYSCALL); - do_syscall(regs); - if (!test_pt_regs_flag(regs, PIF_SYSCALL_RESTART)) - break; - local_irq_enable(); - } + regs->flags = 0; + set_pt_regs_flag(regs, PIF_SYSCALL); + do_syscall(regs); exit_to_user_mode(); } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 019c5748b607..76947275fe8b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -277,6 +277,8 @@ static void __init test_monitor_call(void) { int val = 1; + if (!IS_ENABLED(CONFIG_BUG)) + return; asm volatile( " mc 0,0\n" "0: xgr %0,%0\n" @@ -299,10 +301,9 @@ static void (*pgm_check_table[128])(struct pt_regs *regs); void noinstr __do_pgm_check(struct pt_regs *regs) { unsigned long last_break = S390_lowcore.breaking_event_addr; - unsigned int trapnr, syscall_redirect = 0; + unsigned int trapnr; irqentry_state_t state; - add_random_kstack_offset(); regs->int_code = *(u32 *)&S390_lowcore.pgm_ilc; regs->int_parm_long = S390_lowcore.trans_exc_code; @@ -344,18 +345,9 @@ void noinstr __do_pgm_check(struct pt_regs *regs) trapnr = regs->int_code & PGM_INT_CODE_MASK; if (trapnr) pgm_check_table[trapnr](regs); - syscall_redirect = user_mode(regs) && test_pt_regs_flag(regs, PIF_SYSCALL); out: local_irq_disable(); irqentry_exit(regs, state); - - if (syscall_redirect) { - enter_from_user_mode(regs); - local_irq_enable(); - regs->orig_gpr2 = regs->gprs[2]; - do_syscall(regs); - exit_to_user_mode(); - } } /* diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 6be2167943bb..aeb0a15bcbb7 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -358,6 +358,15 @@ static ssize_t uv_query_facilities(struct kobject *kobj, static struct kobj_attribute uv_query_facilities_attr = __ATTR(facilities, 0444, uv_query_facilities, NULL); +static ssize_t uv_query_feature_indications(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%lx\n", uv_info.uv_feature_indications); +} + +static struct kobj_attribute uv_query_feature_indications_attr = + __ATTR(feature_indications, 0444, uv_query_feature_indications, NULL); + static ssize_t uv_query_max_guest_cpus(struct kobject *kobj, struct kobj_attribute *attr, char *page) { @@ -390,6 +399,7 @@ static struct kobj_attribute uv_query_max_guest_addr_attr = static struct attribute *uv_query_attrs[] = { &uv_query_facilities_attr.attr, + &uv_query_feature_indications_attr.attr, &uv_query_max_guest_cpus_attr.attr, &uv_query_max_guest_vms_attr.attr, &uv_query_max_guest_addr_attr.attr, diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 8c4e07d533c8..99694260cac9 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -20,7 +20,7 @@ #include extern char vdso64_start[], vdso64_end[]; -static unsigned int vdso_pages; +extern char vdso32_start[], vdso32_end[]; static struct vm_special_mapping vvar_mapping; @@ -37,18 +37,6 @@ enum vvar_pages { VVAR_NR_PAGES, }; -unsigned int __read_mostly vdso_enabled = 1; - -static int __init vdso_setup(char *str) -{ - bool enabled; - - if (!kstrtobool(str, &enabled)) - vdso_enabled = enabled; - return 1; -} -__setup("vdso=", vdso_setup); - #ifdef CONFIG_TIME_NS struct vdso_data *arch_get_vdso_data(void *vvar_page) { @@ -155,7 +143,12 @@ static struct vm_special_mapping vvar_mapping = { .fault = vvar_fault, }; -static struct vm_special_mapping vdso_mapping = { +static struct vm_special_mapping vdso64_mapping = { + .name = "[vdso]", + .mremap = vdso_mremap, +}; + +static struct vm_special_mapping vdso32_mapping = { .name = "[vdso]", .mremap = vdso_mremap, }; @@ -171,16 +164,22 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { unsigned long vdso_text_len, vdso_mapping_len; unsigned long vvar_start, vdso_text_start; + struct vm_special_mapping *vdso_mapping; struct mm_struct *mm = current->mm; struct vm_area_struct *vma; int rc; BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES); - if (!vdso_enabled || is_compat_task()) - return 0; if (mmap_write_lock_killable(mm)) return -EINTR; - vdso_text_len = vdso_pages << PAGE_SHIFT; + + if (is_compat_task()) { + vdso_text_len = vdso32_end - vdso32_start; + vdso_mapping = &vdso32_mapping; + } else { + vdso_text_len = vdso64_end - vdso64_start; + vdso_mapping = &vdso64_mapping; + } vdso_mapping_len = vdso_text_len + VVAR_NR_PAGES * PAGE_SIZE; vvar_start = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); rc = vvar_start; @@ -198,7 +197,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vma = _install_special_mapping(mm, vdso_text_start, vdso_text_len, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &vdso_mapping); + vdso_mapping); if (IS_ERR(vma)) { do_munmap(mm, vvar_start, PAGE_SIZE, NULL); rc = PTR_ERR(vma); @@ -211,21 +210,25 @@ out: return rc; } -static int __init vdso_init(void) +static struct page ** __init vdso_setup_pages(void *start, void *end) { - struct page **pages; + int pages = (end - start) >> PAGE_SHIFT; + struct page **pagelist; int i; - vdso_pages = (vdso64_end - vdso64_start) >> PAGE_SHIFT; - pages = kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL); - if (!pages) { - vdso_enabled = 0; - return -ENOMEM; - } - for (i = 0; i < vdso_pages; i++) - pages[i] = virt_to_page(vdso64_start + i * PAGE_SIZE); - pages[vdso_pages] = NULL; - vdso_mapping.pages = pages; + pagelist = kcalloc(pages + 1, sizeof(struct page *), GFP_KERNEL); + if (!pagelist) + panic("%s: Cannot allocate page list for VDSO", __func__); + for (i = 0; i < pages; i++) + pagelist[i] = virt_to_page(start + i * PAGE_SIZE); + return pagelist; +} + +static int __init vdso_init(void) +{ + vdso64_mapping.pages = vdso_setup_pages(vdso64_start, vdso64_end); + if (IS_ENABLED(CONFIG_COMPAT)) + vdso32_mapping.pages = vdso_setup_pages(vdso32_start, vdso32_end); return 0; } arch_initcall(vdso_init); diff --git a/arch/s390/kernel/vdso32/.gitignore b/arch/s390/kernel/vdso32/.gitignore new file mode 100644 index 000000000000..5167384843b9 --- /dev/null +++ b/arch/s390/kernel/vdso32/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +vdso32.lds diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile new file mode 100644 index 000000000000..b2349a3f4fa3 --- /dev/null +++ b/arch/s390/kernel/vdso32/Makefile @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0 +# List of files in the vdso + +KCOV_INSTRUMENT := n +ARCH_REL_TYPE_ABS := R_390_COPY|R_390_GLOB_DAT|R_390_JMP_SLOT|R_390_RELATIVE +ARCH_REL_TYPE_ABS += R_390_GOT|R_390_PLT + +include $(srctree)/lib/vdso/Makefile +obj-vdso32 = vdso_user_wrapper-32.o note-32.o + +# Build rules + +targets := $(obj-vdso32) vdso32.so vdso32.so.dbg +obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) + +KBUILD_AFLAGS += -DBUILD_VDSO +KBUILD_CFLAGS += -DBUILD_VDSO -DDISABLE_BRANCH_PROFILING + +KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) +KBUILD_AFLAGS_32 += -m31 -s + +KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) +KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin + +LDFLAGS_vdso32.so.dbg += -fPIC -shared -nostdlib -soname=linux-vdso32.so.1 \ + --hash-style=both --build-id=sha1 -melf_s390 -T + +$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) +$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) + +obj-y += vdso32_wrapper.o +CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) + +# Disable gcov profiling, ubsan and kasan for VDSO code +GCOV_PROFILE := n +UBSAN_SANITIZE := n +KASAN_SANITIZE := n + +# Force dependency (incbin is bad) +$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so + +$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) FORCE + $(call if_changed,ld) + +# strip rule for the .so file +$(obj)/%.so: OBJCOPYFLAGS := -S +$(obj)/%.so: $(obj)/%.so.dbg FORCE + $(call if_changed,objcopy) + +$(obj-vdso32): %-32.o: %.S FORCE + $(call if_changed_dep,vdso32as) + +# actual build commands +quiet_cmd_vdso32as = VDSO32A $@ + cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $< +quiet_cmd_vdso32cc = VDSO32C $@ + cmd_vdso32cc = $(CC) $(c_flags) -c -o $@ $< + +# install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + +vdso32.so: $(obj)/vdso32.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso32.so + +# Generate VDSO offsets using helper script +gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh +quiet_cmd_vdsosym = VDSOSYM $@ + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ + +include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE + $(call if_changed,vdsosym) diff --git a/arch/s390/kernel/vdso32/gen_vdso_offsets.sh b/arch/s390/kernel/vdso32/gen_vdso_offsets.sh new file mode 100755 index 000000000000..9c4f951e227d --- /dev/null +++ b/arch/s390/kernel/vdso32/gen_vdso_offsets.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +# +# Match symbols in the DSO that look like VDSO_*; produce a header file +# of constant offsets into the shared object. +# +# Doing this inside the Makefile will break the $(filter-out) function, +# causing Kbuild to rebuild the vdso-offsets header file every time. +# +# Inspired by arm64 version. +# + +LC_ALL=C +sed -n 's/\([0-9a-f]*\) . __kernel_compat_\(.*\)/\#define vdso32_offset_\2\t0x\1/p' diff --git a/arch/s390/kernel/vdso32/note.S b/arch/s390/kernel/vdso32/note.S new file mode 100644 index 000000000000..db19d0680a0a --- /dev/null +++ b/arch/s390/kernel/vdso32/note.S @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include +#include +#include + +ELFNOTE_START(Linux, 0, "a") + .long LINUX_VERSION_CODE +ELFNOTE_END diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S new file mode 100644 index 000000000000..bff50b6acd6d --- /dev/null +++ b/arch/s390/kernel/vdso32/vdso32.lds.S @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This is the infamous ld script for the 64 bits vdso + * library + */ + +#include +#include + +OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") +OUTPUT_ARCH(s390:31-bit) +ENTRY(_start) + +SECTIONS +{ + PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE); +#ifdef CONFIG_TIME_NS + PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); +#endif + . = VDSO_LBASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + .note : { *(.note.*) } :text :note + + . = ALIGN(16); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } :text + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); + + /* + * Other stuff is appended to the text segment: + */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + + .dynamic : { *(.dynamic) } :text :dynamic + + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } + + .rela.dyn ALIGN(8) : { *(.rela.dyn) } + .got ALIGN(8) : { *(.got .toc) } + + _end = .; + PROVIDE(end = .); + + /* + * Stabs debugging sections are here too. + */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* + * DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the + * beginning of the section so we begin them at 0. + */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + + /DISCARD/ : { + *(.note.GNU-stack) + *(.branch_lt) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + } +} + +/* + * Very old versions of ld do not recognize this name token; use the constant. + */ +#define PT_GNU_EH_FRAME 0x6474e550 + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ + eh_frame_hdr PT_GNU_EH_FRAME; +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + VDSO_VERSION_STRING { + global: + /* + * Has to be there for the kernel to find + */ + __kernel_compat_restart_syscall; + __kernel_compat_rt_sigreturn; + __kernel_compat_sigreturn; + local: *; + }; +} diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S new file mode 100644 index 000000000000..de2fb930471a --- /dev/null +++ b/arch/s390/kernel/vdso32/vdso32_wrapper.S @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include +#include + + __PAGE_ALIGNED_DATA + + .globl vdso32_start, vdso32_end + .balign PAGE_SIZE +vdso32_start: + .incbin "arch/s390/kernel/vdso32/vdso32.so" + .balign PAGE_SIZE +vdso32_end: + + .previous diff --git a/arch/s390/kernel/vdso32/vdso_user_wrapper.S b/arch/s390/kernel/vdso32/vdso_user_wrapper.S new file mode 100644 index 000000000000..3f42f27f978c --- /dev/null +++ b/arch/s390/kernel/vdso32/vdso_user_wrapper.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include + +.macro vdso_syscall func,syscall + .globl __kernel_compat_\func + .type __kernel_compat_\func,@function + .align 8 +__kernel_compat_\func: + CFI_STARTPROC + svc \syscall + /* Make sure we notice when a syscall returns, which shouldn't happen */ + .word 0 + CFI_ENDPROC + .size __kernel_compat_\func,.-__kernel_compat_\func +.endm + +vdso_syscall restart_syscall,__NR_restart_syscall +vdso_syscall sigreturn,__NR_sigreturn +vdso_syscall rt_sigreturn,__NR_rt_sigreturn diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile index a6e0fb6b91d6..2a2092ce19f1 100644 --- a/arch/s390/kernel/vdso64/Makefile +++ b/arch/s390/kernel/vdso64/Makefile @@ -74,3 +74,11 @@ vdso64.so: $(obj)/vdso64.so.dbg $(call cmd,vdso_install) vdso_install: vdso64.so + +# Generate VDSO offsets using helper script +gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh +quiet_cmd_vdsosym = VDSOSYM $@ + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ + +include/generated/vdso64-offsets.h: $(obj)/vdso64.so.dbg FORCE + $(call if_changed,vdsosym) diff --git a/arch/s390/kernel/vdso64/gen_vdso_offsets.sh b/arch/s390/kernel/vdso64/gen_vdso_offsets.sh new file mode 100755 index 000000000000..37f05cb38dad --- /dev/null +++ b/arch/s390/kernel/vdso64/gen_vdso_offsets.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +# +# Match symbols in the DSO that look like VDSO_*; produce a header file +# of constant offsets into the shared object. +# +# Doing this inside the Makefile will break the $(filter-out) function, +# causing Kbuild to rebuild the vdso-offsets header file every time. +# +# Inspired by arm64 version. +# + +LC_ALL=C +sed -n 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso64_offset_\2\t0x\1/p' diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S index 518f1ea405f4..d4fb336d747b 100644 --- a/arch/s390/kernel/vdso64/vdso64.lds.S +++ b/arch/s390/kernel/vdso64/vdso64.lds.S @@ -17,7 +17,7 @@ SECTIONS #ifdef CONFIG_TIME_NS PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); #endif - . = VDSO64_LBASE + SIZEOF_HEADERS; + . = VDSO_LBASE + SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } @@ -137,6 +137,9 @@ VERSION __kernel_clock_gettime; __kernel_clock_getres; __kernel_getcpu; + __kernel_restart_syscall; + __kernel_rt_sigreturn; + __kernel_sigreturn; local: *; }; } diff --git a/arch/s390/kernel/vdso64/vdso_user_wrapper.S b/arch/s390/kernel/vdso64/vdso_user_wrapper.S index f773505c7e63..97f0c0a669a5 100644 --- a/arch/s390/kernel/vdso64/vdso_user_wrapper.S +++ b/arch/s390/kernel/vdso64/vdso_user_wrapper.S @@ -37,3 +37,20 @@ vdso_func gettimeofday vdso_func clock_getres vdso_func clock_gettime vdso_func getcpu + +.macro vdso_syscall func,syscall + .globl __kernel_\func + .type __kernel_\func,@function + .align 8 +__kernel_\func: + CFI_STARTPROC + svc \syscall + /* Make sure we notice when a syscall returns, which shouldn't happen */ + .word 0 + CFI_ENDPROC + .size __kernel_\func,.-__kernel_\func +.endm + +vdso_syscall restart_syscall,__NR_restart_syscall +vdso_syscall sigreturn,__NR_sigreturn +vdso_syscall rt_sigreturn,__NR_rt_sigreturn diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index ec5b76bde4d8..cfcdf76d6a95 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -162,7 +162,7 @@ char *strcat(char *dest, const char *src) " jo 0b\n" "1: mvst %[dummy],%[src]\n" " jo 1b\n" - : [dummy] "=&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src) + : [dummy] "+&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src) : : "cc", "memory", "0"); return ret; diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index 2f32802f79ce..ecf327d743a0 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -120,7 +120,7 @@ static struct unwindme *unwindme; #define UWM_REGS 0x2 /* Pass regs to test_unwind(). */ #define UWM_SP 0x4 /* Pass sp to test_unwind(). */ #define UWM_CALLER 0x8 /* Unwind starting from caller. */ -#define UWM_SWITCH_STACK 0x10 /* Use CALL_ON_STACK. */ +#define UWM_SWITCH_STACK 0x10 /* Use call_on_stack. */ #define UWM_IRQ 0x20 /* Unwind from irq context. */ #define UWM_PGM 0x40 /* Unwind from program check handler. */ @@ -211,7 +211,8 @@ static noinline int unwindme_func2(struct unwindme *u) if (u->flags & UWM_SWITCH_STACK) { local_irq_save(flags); local_mcck_disable(); - rc = CALL_ON_STACK(unwindme_func3, S390_lowcore.nodat_stack, 1, u); + rc = call_on_stack(1, S390_lowcore.nodat_stack, + int, unwindme_func3, struct unwindme *, u); local_mcck_enable(); local_irq_restore(flags); return rc; diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index 67606d932825..7ec8b1fa0f08 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -224,7 +224,7 @@ static inline unsigned long copy_in_user_mvcos(void __user *to, const void __use EX_TABLE(0b,3b) : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2) : [spec] "d" (0x810081UL) - : "cc", "memory"); + : "cc", "memory", "0"); return size; } diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 8ae3dc5783fd..e33c43b38afe 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -285,26 +285,6 @@ static noinline void do_sigbus(struct pt_regs *regs) (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK)); } -static noinline int signal_return(struct pt_regs *regs) -{ - u16 instruction; - int rc; - - rc = __get_user(instruction, (u16 __user *) regs->psw.addr); - if (rc) - return rc; - if (instruction == 0x0a77) { - set_pt_regs_flag(regs, PIF_SYSCALL); - regs->int_code = 0x00040077; - return 0; - } else if (instruction == 0x0aad) { - set_pt_regs_flag(regs, PIF_SYSCALL); - regs->int_code = 0x000400ad; - return 0; - } - return -EACCES; -} - static noinline void do_fault_error(struct pt_regs *regs, int access, vm_fault_t fault) { @@ -312,9 +292,6 @@ static noinline void do_fault_error(struct pt_regs *regs, int access, switch (fault) { case VM_FAULT_BADACCESS: - if (access == VM_EXEC && signal_return(regs) == 0) - break; - fallthrough; case VM_FAULT_BADMAP: /* Bad memory access. Check if it is kernel or user space. */ if (user_mode(regs)) { @@ -792,6 +769,32 @@ void do_secure_storage_access(struct pt_regs *regs) struct page *page; int rc; + /* + * bit 61 tells us if the address is valid, if it's not we + * have a major problem and should stop the kernel or send a + * SIGSEGV to the process. Unfortunately bit 61 is not + * reliable without the misc UV feature so we need to check + * for that as well. + */ + if (test_bit_inv(BIT_UV_FEAT_MISC, &uv_info.uv_feature_indications) && + !test_bit_inv(61, ®s->int_parm_long)) { + /* + * When this happens, userspace did something that it + * was not supposed to do, e.g. branching into secure + * memory. Trigger a segmentation fault. + */ + if (user_mode(regs)) { + send_sig(SIGSEGV, current, 0); + return; + } + + /* + * The kernel should never run into this case and we + * have no way out of this situation. + */ + panic("Unexpected PGM 0x3d with TEID bit 61=0"); + } + switch (get_fault_type(regs)) { case USER_FAULT: mm = current->mm; diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 1f1f906344ff..a0f54bd5e98a 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -125,12 +125,18 @@ static unsigned long __no_sanitize_address _memcpy_real(unsigned long dest, */ int memcpy_real(void *dest, void *src, size_t count) { + unsigned long _dest = (unsigned long)dest; + unsigned long _src = (unsigned long)src; + unsigned long _count = (unsigned long)count; int rc; if (S390_lowcore.nodat_stack != 0) { preempt_disable(); - rc = CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack, 3, - dest, src, count); + rc = call_on_stack(3, S390_lowcore.nodat_stack, + unsigned long, _memcpy_real, + unsigned long, _dest, + unsigned long, _src, + unsigned long, _count); preempt_enable(); return rc; } @@ -139,8 +145,7 @@ int memcpy_real(void *dest, void *src, size_t count) * not set up yet. Just call _memcpy_real on the early boot * stack */ - return _memcpy_real((unsigned long) dest,(unsigned long) src, - (unsigned long) count); + return _memcpy_real(_dest, _src, _count); } /* diff --git a/arch/sh/Kbuild b/arch/sh/Kbuild new file mode 100644 index 000000000000..48c2a091a072 --- /dev/null +++ b/arch/sh/Kbuild @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += kernel/ mm/ boards/ +obj-$(CONFIG_SH_FPU_EMU) += math-emu/ +obj-$(CONFIG_USE_BUILTIN_DTB) += boot/dts/ diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 44bcb80e791a..88ddb6f1c75b 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -116,11 +116,6 @@ export ld-bfd head-y := arch/sh/kernel/head_32.o -core-y += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/ -core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ - -core-$(CONFIG_USE_BUILTIN_DTB) += arch/sh/boot/dts/ - # Mach groups machdir-$(CONFIG_SOLUTION_ENGINE) += mach-se machdir-$(CONFIG_SH_HP6XX) += mach-hp6xx diff --git a/arch/sh/include/asm/pgtable-3level.h b/arch/sh/include/asm/pgtable-3level.h index 82d74472dfcd..56bf35c2f29c 100644 --- a/arch/sh/include/asm/pgtable-3level.h +++ b/arch/sh/include/asm/pgtable-3level.h @@ -32,9 +32,9 @@ typedef struct { unsigned long long pmd; } pmd_t; #define pmd_val(x) ((x).pmd) #define __pmd(x) ((pmd_t) { (x) } ) -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { - return pud_val(pud); + return (pmd_t *)pud_val(pud); } /* only used by the stubbed out hugetlb gup code, should never be called */ diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 4144be650d41..1fcb6659822a 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -294,10 +294,7 @@ void __init setup_arch(char **cmdline_p) if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + setup_initial_init_mm(_text, _etext, _edata, _end); code_resource.start = virt_to_phys(_text); code_resource.end = virt_to_phys(_etext)-1; diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index bee99e65fe23..4e65245bc755 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -58,9 +58,6 @@ endif head-y := arch/sparc/kernel/head_$(BITS).o -# See arch/sparc/Kbuild for the core part of the kernel -core-y += arch/sparc/ - libs-y += arch/sparc/prom/ libs-y += arch/sparc/lib/ diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index 8c39a9981187..12d00a42c0a3 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h @@ -201,7 +201,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr, #define arch_cmpxchg64_local(ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - cmpxchg_local((ptr), (o), (n)); \ + arch_cmpxchg_local((ptr), (o), (n)); \ }) #define arch_cmpxchg64(ptr, o, n) arch_cmpxchg64_local((ptr), (o), (n)) diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index ebaf374b55ab..ffccfe3b22ed 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -151,13 +151,13 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) return (unsigned long)__nocache_va(v << 4); } -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { if (srmmu_device_memory(pud_val(pud))) { - return ~0; + return (pmd_t *)~0; } else { unsigned long v = pud_val(pud) & SRMMU_PTD_PMASK; - return (unsigned long)__nocache_va(v << 4); + return (pmd_t *)__nocache_va(v << 4); } } diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index e0ee48ec3903..4679e45c8348 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -841,23 +841,23 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) return ((unsigned long) __va(pfn << PAGE_SHIFT)); } -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { pte_t pte = __pte(pud_val(pud)); unsigned long pfn; pfn = pte_pfn(pte); - return ((unsigned long) __va(pfn << PAGE_SHIFT)); + return ((pmd_t *) __va(pfn << PAGE_SHIFT)); } #define pmd_page(pmd) virt_to_page((void *)pmd_page_vaddr(pmd)) -#define pud_page(pud) virt_to_page((void *)pud_page_vaddr(pud)) +#define pud_page(pud) virt_to_page((void *)pud_pgtable(pud)) #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) #define pud_present(pud) (pud_val(pud) != 0U) #define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) -#define p4d_page_vaddr(p4d) \ - ((unsigned long) __va(p4d_val(p4d))) +#define p4d_pgtable(p4d) \ + ((pud_t *) __va(p4d_val(p4d))) #define p4d_present(p4d) (p4d_val(p4d) != 0U) #define p4d_clear(p4dp) (p4d_val(*(p4dp)) = 0UL) diff --git a/arch/sparc/kernel/syscalls/Makefile b/arch/sparc/kernel/syscalls/Makefile index 0f2ea5bcb0d7..d63f18dd058d 100644 --- a/arch/sparc/kernel/syscalls/Makefile +++ b/arch/sparc/kernel/syscalls/Makefile @@ -10,25 +10,15 @@ syshdr := $(srctree)/scripts/syscallhdr.sh systbl := $(srctree)/scripts/syscalltbl.sh quiet_cmd_syshdr = SYSHDR $@ - cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr --abis $(abis) $< $@ + cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr --abis common,$* $< $@ quiet_cmd_systbl = SYSTBL $@ - cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis $(abis) $< $@ + cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis common,$* $< $@ -$(uapi)/unistd_32.h: abis := common,32 -$(uapi)/unistd_32.h: $(syscall) $(syshdr) FORCE +$(uapi)/unistd_%.h: $(syscall) $(syshdr) FORCE $(call if_changed,syshdr) -$(uapi)/unistd_64.h: abis := common,64 -$(uapi)/unistd_64.h: $(syscall) $(syshdr) FORCE - $(call if_changed,syshdr) - -$(kapi)/syscall_table_32.h: abis := common,32 -$(kapi)/syscall_table_32.h: $(syscall) $(systbl) FORCE - $(call if_changed,systbl) - -$(kapi)/syscall_table_64.h: abis := common,64 -$(kapi)/syscall_table_64.h: $(syscall) $(systbl) FORCE +$(kapi)/syscall_table_%.h: $(syscall) $(systbl) FORCE $(call if_changed,systbl) uapisyshdr-y += unistd_32.h unistd_64.h diff --git a/arch/um/Kbuild b/arch/um/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/um/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 57cfd9a1c082..0561b73cfd9a 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -15,7 +15,7 @@ config UML select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_BUGVERBOSE - select NO_DMA + select NO_DMA if !UML_DMA_EMULATION select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES select HAVE_GCC_PLUGINS @@ -26,7 +26,22 @@ config MMU bool default y +config UML_DMA_EMULATION + bool + config NO_IOMEM + bool "disable IOMEM" if EXPERT + depends on !INDIRECT_IOMEM + default y + +config UML_IOMEM_EMULATION + bool + select INDIRECT_IOMEM + select GENERIC_PCI_IOMAP + select GENERIC_IOMAP + select NO_GENERIC_PCI_IOPORT_MAP + +config NO_IOPORT_MAP def_bool y config ISA @@ -61,6 +76,9 @@ config NR_CPUS range 1 1 default 1 +config ARCH_HAS_CACHE_LINE_SIZE + def_bool y + source "arch/$(HEADER_ARCH)/um/Kconfig" config MAY_HAVE_RUNTIME_DEPS @@ -91,6 +109,19 @@ config LD_SCRIPT_DYN depends on !LD_SCRIPT_STATIC select MODULE_REL_CRCS if MODVERSIONS +config LD_SCRIPT_DYN_RPATH + bool "set rpath in the binary" if EXPERT + default y + depends on LD_SCRIPT_DYN + help + Add /lib (and /lib64 for 64-bit) to the linux binary's rpath + explicitly. + + You may need to turn this off if compiling for nix systems + that have their libraries in random /nix directories and + might otherwise unexpected use libraries from /lib or /lib64 + instead of the desired ones. + config HOSTFS tristate "Host filesystem" help diff --git a/arch/um/Makefile b/arch/um/Makefile index 1cea46ff9bb7..12a7acef0357 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -118,7 +118,8 @@ archprepare: $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static -LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie) +LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) +LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ -fno-stack-protector $(call cc-option, -fno-stack-protector-all) diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig index 03ba34b61115..f145842c40b9 100644 --- a/arch/um/drivers/Kconfig +++ b/arch/um/drivers/Kconfig @@ -357,3 +357,23 @@ config UML_RTC rtcwake, especially in time-travel mode. This driver enables that by providing a fake RTC clock that causes a wakeup at the right time. + +config UML_PCI_OVER_VIRTIO + bool "Enable PCI over VIRTIO device simulation" + # in theory, just VIRTIO is enough, but that causes recursion + depends on VIRTIO_UML + select FORCE_PCI + select UML_IOMEM_EMULATION + select UML_DMA_EMULATION + select PCI_MSI + select PCI_MSI_IRQ_DOMAIN + select PCI_LOCKLESS_CONFIG + +config UML_PCI_OVER_VIRTIO_DEVICE_ID + int "set the virtio device ID for PCI emulation" + default -1 + depends on UML_PCI_OVER_VIRTIO + help + There's no official device ID assigned (yet), set the one you + wish to use for experimentation here. The default of -1 is + not valid and will cause the driver to fail at probe. diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index dcc64a02f81f..803666e85414 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-$(CONFIG_UML_RANDOM) += random.o obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o obj-$(CONFIG_UML_RTC) += rtc.o +obj-$(CONFIG_UML_PCI_OVER_VIRTIO) += virt-pci.o # pcap_user.o must be added explicitly. USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index d8845d4aac6a..6040817c036f 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -256,7 +256,8 @@ static int winch_tramp(int fd, struct tty_port *port, int *fd_out, goto out_close; } - if (os_set_fd_block(*fd_out, 0)) { + err = os_set_fd_block(*fd_out, 0); + if (err) { printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " "non-blocking.\n"); goto out_close; diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 482a19c5105c..7334019c9e60 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -145,7 +145,8 @@ static int slip_open(void *data) } sfd = err; - if (set_up_tty(sfd)) + err = set_up_tty(sfd); + if (err) goto out_close2; pri->slave = sfd; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 8e0b43cf089f..e497185dd393 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -125,9 +125,7 @@ static const struct block_device_operations ubd_blops = { }; /* Protected by ubd_lock */ -static int fake_major = UBD_MAJOR; static struct gendisk *ubd_gendisk[MAX_DEV]; -static struct gendisk *fake_gendisk[MAX_DEV]; #ifdef CONFIG_BLK_DEV_UBD_SYNC #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ @@ -197,54 +195,19 @@ struct ubd { /* Protected by ubd_lock */ static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD }; -/* Only changed by fake_ide_setup which is a setup */ -static int fake_ide = 0; -static struct proc_dir_entry *proc_ide_root = NULL; -static struct proc_dir_entry *proc_ide = NULL; - static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd); -static void make_proc_ide(void) -{ - proc_ide_root = proc_mkdir("ide", NULL); - proc_ide = proc_mkdir("ide0", proc_ide_root); -} - -static int fake_ide_media_proc_show(struct seq_file *m, void *v) -{ - seq_puts(m, "disk\n"); - return 0; -} - -static void make_ide_entries(const char *dev_name) -{ - struct proc_dir_entry *dir, *ent; - char name[64]; - - if(proc_ide_root == NULL) make_proc_ide(); - - dir = proc_mkdir(dev_name, proc_ide); - if(!dir) return; - - ent = proc_create_single("media", S_IRUGO, dir, - fake_ide_media_proc_show); - if(!ent) return; - snprintf(name, sizeof(name), "ide0/%s", dev_name); - proc_symlink(dev_name, proc_ide_root, name); -} - static int fake_ide_setup(char *str) { - fake_ide = 1; + pr_warn("The fake_ide option has been removed\n"); return 1; } - __setup("fake_ide", fake_ide_setup); __uml_help(fake_ide_setup, "fake_ide\n" -" Create ide0 entries that map onto ubd devices.\n\n" +" Obsolete stub.\n\n" ); static int parse_unit(char **ptr) @@ -280,36 +243,14 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out) if(index_out) *index_out = -1; n = *str; if(n == '='){ - char *end; - int major; - str++; if(!strcmp(str, "sync")){ global_openflags = of_sync(global_openflags); return err; } - err = -EINVAL; - major = simple_strtoul(str, &end, 0); - if((*end != '\0') || (end == str)){ - *error_out = "Didn't parse major number"; - return err; - } - - mutex_lock(&ubd_lock); - if (fake_major != UBD_MAJOR) { - *error_out = "Can't assign a fake major twice"; - goto out1; - } - - fake_major = major; - - printk(KERN_INFO "Setting extra ubd major number to %d\n", - major); - err = 0; - out1: - mutex_unlock(&ubd_lock); - return err; + pr_warn("fake major not supported any more\n"); + return 0; } n = parse_unit(&str); @@ -874,7 +815,6 @@ static void ubd_device_release(struct device *dev) { struct ubd *ubd_dev = dev_get_drvdata(dev); - blk_cleanup_queue(ubd_dev->queue); blk_mq_free_tag_set(&ubd_dev->tag_set); *ubd_dev = ((struct ubd) DEFAULT_UBD); } @@ -914,41 +854,25 @@ static const struct attribute_group *ubd_attr_groups[] = { NULL, }; -static int ubd_disk_register(int major, u64 size, int unit, - struct gendisk **disk_out) +static void ubd_disk_register(int major, u64 size, int unit, + struct gendisk *disk) { - struct device *parent = NULL; - struct gendisk *disk; - - disk = alloc_disk(1 << UBD_SHIFT); - if(disk == NULL) - return -ENOMEM; - disk->major = major; disk->first_minor = unit << UBD_SHIFT; + disk->minors = 1 << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if (major == UBD_MAJOR) - sprintf(disk->disk_name, "ubd%c", 'a' + unit); - else - sprintf(disk->disk_name, "ubd_fake%d", unit); + sprintf(disk->disk_name, "ubd%c", 'a' + unit); - /* sysfs register (not for ide fake devices) */ - if (major == UBD_MAJOR) { - ubd_devs[unit].pdev.id = unit; - ubd_devs[unit].pdev.name = DRIVER_NAME; - ubd_devs[unit].pdev.dev.release = ubd_device_release; - dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]); - platform_device_register(&ubd_devs[unit].pdev); - parent = &ubd_devs[unit].pdev.dev; - } + ubd_devs[unit].pdev.id = unit; + ubd_devs[unit].pdev.name = DRIVER_NAME; + ubd_devs[unit].pdev.dev.release = ubd_device_release; + dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]); + platform_device_register(&ubd_devs[unit].pdev); disk->private_data = &ubd_devs[unit]; disk->queue = ubd_devs[unit].queue; - device_add_disk(parent, disk, ubd_attr_groups); - - *disk_out = disk; - return 0; + device_add_disk(&ubd_devs[unit].pdev.dev, disk, ubd_attr_groups); } #define ROUND_BLOCK(n) ((n + (SECTOR_SIZE - 1)) & (-SECTOR_SIZE)) @@ -960,6 +884,7 @@ static const struct blk_mq_ops ubd_mq_ops = { static int ubd_add(int n, char **error_out) { struct ubd *ubd_dev = &ubd_devs[n]; + struct gendisk *disk; int err = 0; if(ubd_dev->file == NULL) @@ -984,43 +909,24 @@ static int ubd_add(int n, char **error_out) if (err) goto out; - ubd_dev->queue = blk_mq_init_queue(&ubd_dev->tag_set); - if (IS_ERR(ubd_dev->queue)) { - err = PTR_ERR(ubd_dev->queue); + disk = blk_mq_alloc_disk(&ubd_dev->tag_set, ubd_dev); + if (IS_ERR(disk)) { + err = PTR_ERR(disk); goto out_cleanup_tags; } + ubd_dev->queue = disk->queue; - ubd_dev->queue->queuedata = ubd_dev; blk_queue_write_cache(ubd_dev->queue, true, false); - blk_queue_max_segments(ubd_dev->queue, MAX_SG); blk_queue_segment_boundary(ubd_dev->queue, PAGE_SIZE - 1); - err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); - if(err){ - *error_out = "Failed to register device"; - goto out_cleanup_tags; - } - - if (fake_major != UBD_MAJOR) - ubd_disk_register(fake_major, ubd_dev->size, n, - &fake_gendisk[n]); - - /* - * Perhaps this should also be under the "if (fake_major)" above - * using the fake_disk->disk_name - */ - if (fake_ide) - make_ide_entries(ubd_gendisk[n]->disk_name); - - err = 0; -out: - return err; + ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, disk); + ubd_gendisk[n] = disk; + return 0; out_cleanup_tags: blk_mq_free_tag_set(&ubd_dev->tag_set); - if (!(IS_ERR(ubd_dev->queue))) - blk_cleanup_queue(ubd_dev->queue); - goto out; +out: + return err; } static int ubd_config(char *str, char **error_out) @@ -1123,13 +1029,7 @@ static int ubd_remove(int n, char **error_out) ubd_gendisk[n] = NULL; if(disk != NULL){ del_gendisk(disk); - put_disk(disk); - } - - if(fake_gendisk[n] != NULL){ - del_gendisk(fake_gendisk[n]); - put_disk(fake_gendisk[n]); - fake_gendisk[n] = NULL; + blk_cleanup_disk(disk); } err = 0; @@ -1188,14 +1088,6 @@ static int __init ubd_init(void) if (register_blkdev(UBD_MAJOR, "ubd")) return -1; - if (fake_major != UBD_MAJOR) { - char name[sizeof("ubd_nnn\0")]; - - snprintf(name, sizeof(name), "ubd_%d", fake_major); - if (register_blkdev(fake_major, "ubd")) - return -1; - } - irq_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE, sizeof(struct io_thread_req *), GFP_KERNEL @@ -1242,8 +1134,7 @@ static int __init ubd_driver_init(void){ * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), - &thread_fd); + io_pid = start_io_thread(stack + PAGE_SIZE, &thread_fd); if(io_pid < 0){ printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c new file mode 100644 index 000000000000..0b802834f40a --- /dev/null +++ b/arch/um/drivers/virt-pci.c @@ -0,0 +1,895 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Intel Corporation + * Author: Johannes Berg + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DEVICES 8 +#define MAX_MSI_VECTORS 32 +#define CFG_SPACE_SIZE 4096 + +/* for MSI-X we have a 32-bit payload */ +#define MAX_IRQ_MSG_SIZE (sizeof(struct virtio_pcidev_msg) + sizeof(u32)) +#define NUM_IRQ_MSGS 10 + +#define HANDLE_NO_FREE(ptr) ((void *)((unsigned long)(ptr) | 1)) +#define HANDLE_IS_NO_FREE(ptr) ((unsigned long)(ptr) & 1) + +struct um_pci_device { + struct virtio_device *vdev; + + /* for now just standard BARs */ + u8 resptr[PCI_STD_NUM_BARS]; + + struct virtqueue *cmd_vq, *irq_vq; + +#define UM_PCI_STAT_WAITING 0 + unsigned long status; + + int irq; +}; + +struct um_pci_device_reg { + struct um_pci_device *dev; + void __iomem *iomem; +}; + +static struct pci_host_bridge *bridge; +static DEFINE_MUTEX(um_pci_mtx); +static struct um_pci_device_reg um_pci_devices[MAX_DEVICES]; +static struct fwnode_handle *um_pci_fwnode; +static struct irq_domain *um_pci_inner_domain; +static struct irq_domain *um_pci_msi_domain; +static unsigned long um_pci_msi_used[BITS_TO_LONGS(MAX_MSI_VECTORS)]; + +#define UM_VIRT_PCI_MAXDELAY 40000 + +static int um_pci_send_cmd(struct um_pci_device *dev, + struct virtio_pcidev_msg *cmd, + unsigned int cmd_size, + const void *extra, unsigned int extra_size, + void *out, unsigned int out_size) +{ + struct scatterlist out_sg, extra_sg, in_sg; + struct scatterlist *sgs_list[] = { + [0] = &out_sg, + [1] = extra ? &extra_sg : &in_sg, + [2] = extra ? &in_sg : NULL, + }; + int delay_count = 0; + int ret, len; + bool posted; + + if (WARN_ON(cmd_size < sizeof(*cmd))) + return -EINVAL; + + switch (cmd->op) { + case VIRTIO_PCIDEV_OP_CFG_WRITE: + case VIRTIO_PCIDEV_OP_MMIO_WRITE: + case VIRTIO_PCIDEV_OP_MMIO_MEMSET: + /* in PCI, writes are posted, so don't wait */ + posted = !out; + WARN_ON(!posted); + break; + default: + posted = false; + break; + } + + if (posted) { + u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC); + + if (ncmd) { + memcpy(ncmd, cmd, cmd_size); + if (extra) + memcpy(ncmd + cmd_size, extra, extra_size); + cmd = (void *)ncmd; + cmd_size += extra_size; + extra = NULL; + extra_size = 0; + } else { + /* try without allocating memory */ + posted = false; + } + } + + sg_init_one(&out_sg, cmd, cmd_size); + if (extra) + sg_init_one(&extra_sg, extra, extra_size); + if (out) + sg_init_one(&in_sg, out, out_size); + + /* add to internal virtio queue */ + ret = virtqueue_add_sgs(dev->cmd_vq, sgs_list, + extra ? 2 : 1, + out ? 1 : 0, + posted ? cmd : HANDLE_NO_FREE(cmd), + GFP_ATOMIC); + if (ret) + return ret; + + if (posted) { + virtqueue_kick(dev->cmd_vq); + return 0; + } + + /* kick and poll for getting a response on the queue */ + set_bit(UM_PCI_STAT_WAITING, &dev->status); + virtqueue_kick(dev->cmd_vq); + + while (1) { + void *completed = virtqueue_get_buf(dev->cmd_vq, &len); + + if (completed == HANDLE_NO_FREE(cmd)) + break; + + if (completed && !HANDLE_IS_NO_FREE(completed)) + kfree(completed); + + if (WARN_ONCE(virtqueue_is_broken(dev->cmd_vq) || + ++delay_count > UM_VIRT_PCI_MAXDELAY, + "um virt-pci delay: %d", delay_count)) { + ret = -EIO; + break; + } + udelay(1); + } + clear_bit(UM_PCI_STAT_WAITING, &dev->status); + + return ret; +} + +static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset, + int size) +{ + struct um_pci_device_reg *reg = priv; + struct um_pci_device *dev = reg->dev; + struct virtio_pcidev_msg hdr = { + .op = VIRTIO_PCIDEV_OP_CFG_READ, + .size = size, + .addr = offset, + }; + /* maximum size - we may only use parts of it */ + u8 data[8]; + + if (!dev) + return ~0ULL; + + memset(data, 0xff, sizeof(data)); + + switch (size) { + case 1: + case 2: + case 4: +#ifdef CONFIG_64BIT + case 8: +#endif + break; + default: + WARN(1, "invalid config space read size %d\n", size); + return ~0ULL; + } + + if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, + data, sizeof(data))) + return ~0ULL; + + switch (size) { + case 1: + return data[0]; + case 2: + return le16_to_cpup((void *)data); + case 4: + return le32_to_cpup((void *)data); +#ifdef CONFIG_64BIT + case 8: + return le64_to_cpup((void *)data); +#endif + default: + return ~0ULL; + } +} + +static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size, + unsigned long val) +{ + struct um_pci_device_reg *reg = priv; + struct um_pci_device *dev = reg->dev; + struct { + struct virtio_pcidev_msg hdr; + /* maximum size - we may only use parts of it */ + u8 data[8]; + } msg = { + .hdr = { + .op = VIRTIO_PCIDEV_OP_CFG_WRITE, + .size = size, + .addr = offset, + }, + }; + + if (!dev) + return; + + switch (size) { + case 1: + msg.data[0] = (u8)val; + break; + case 2: + put_unaligned_le16(val, (void *)msg.data); + break; + case 4: + put_unaligned_le32(val, (void *)msg.data); + break; +#ifdef CONFIG_64BIT + case 8: + put_unaligned_le64(val, (void *)msg.data); + break; +#endif + default: + WARN(1, "invalid config space write size %d\n", size); + return; + } + + WARN_ON(um_pci_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0)); +} + +static const struct logic_iomem_ops um_pci_device_cfgspace_ops = { + .read = um_pci_cfgspace_read, + .write = um_pci_cfgspace_write, +}; + +static void um_pci_bar_copy_from(void *priv, void *buffer, + unsigned int offset, int size) +{ + u8 *resptr = priv; + struct um_pci_device *dev = container_of(resptr - *resptr, + struct um_pci_device, + resptr[0]); + struct virtio_pcidev_msg hdr = { + .op = VIRTIO_PCIDEV_OP_MMIO_READ, + .bar = *resptr, + .size = size, + .addr = offset, + }; + + memset(buffer, 0xff, size); + + um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, buffer, size); +} + +static unsigned long um_pci_bar_read(void *priv, unsigned int offset, + int size) +{ + /* maximum size - we may only use parts of it */ + u8 data[8]; + + switch (size) { + case 1: + case 2: + case 4: +#ifdef CONFIG_64BIT + case 8: +#endif + break; + default: + WARN(1, "invalid config space read size %d\n", size); + return ~0ULL; + } + + um_pci_bar_copy_from(priv, data, offset, size); + + switch (size) { + case 1: + return data[0]; + case 2: + return le16_to_cpup((void *)data); + case 4: + return le32_to_cpup((void *)data); +#ifdef CONFIG_64BIT + case 8: + return le64_to_cpup((void *)data); +#endif + default: + return ~0ULL; + } +} + +static void um_pci_bar_copy_to(void *priv, unsigned int offset, + const void *buffer, int size) +{ + u8 *resptr = priv; + struct um_pci_device *dev = container_of(resptr - *resptr, + struct um_pci_device, + resptr[0]); + struct virtio_pcidev_msg hdr = { + .op = VIRTIO_PCIDEV_OP_MMIO_WRITE, + .bar = *resptr, + .size = size, + .addr = offset, + }; + + um_pci_send_cmd(dev, &hdr, sizeof(hdr), buffer, size, NULL, 0); +} + +static void um_pci_bar_write(void *priv, unsigned int offset, int size, + unsigned long val) +{ + /* maximum size - we may only use parts of it */ + u8 data[8]; + + switch (size) { + case 1: + data[0] = (u8)val; + break; + case 2: + put_unaligned_le16(val, (void *)data); + break; + case 4: + put_unaligned_le32(val, (void *)data); + break; +#ifdef CONFIG_64BIT + case 8: + put_unaligned_le64(val, (void *)data); + break; +#endif + default: + WARN(1, "invalid config space write size %d\n", size); + return; + } + + um_pci_bar_copy_to(priv, offset, data, size); +} + +static void um_pci_bar_set(void *priv, unsigned int offset, u8 value, int size) +{ + u8 *resptr = priv; + struct um_pci_device *dev = container_of(resptr - *resptr, + struct um_pci_device, + resptr[0]); + struct { + struct virtio_pcidev_msg hdr; + u8 data; + } msg = { + .hdr = { + .op = VIRTIO_PCIDEV_OP_CFG_WRITE, + .bar = *resptr, + .size = size, + .addr = offset, + }, + .data = value, + }; + + um_pci_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0); +} + +static const struct logic_iomem_ops um_pci_device_bar_ops = { + .read = um_pci_bar_read, + .write = um_pci_bar_write, + .set = um_pci_bar_set, + .copy_from = um_pci_bar_copy_from, + .copy_to = um_pci_bar_copy_to, +}; + +static void __iomem *um_pci_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct um_pci_device_reg *dev; + unsigned int busn = bus->number; + + if (busn > 0) + return NULL; + + /* not allowing functions for now ... */ + if (devfn % 8) + return NULL; + + if (devfn / 8 >= ARRAY_SIZE(um_pci_devices)) + return NULL; + + dev = &um_pci_devices[devfn / 8]; + if (!dev) + return NULL; + + return (void __iomem *)((unsigned long)dev->iomem + where); +} + +static struct pci_ops um_pci_ops = { + .map_bus = um_pci_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + +static void um_pci_rescan(void) +{ + pci_lock_rescan_remove(); + pci_rescan_bus(bridge->bus); + pci_unlock_rescan_remove(); +} + +static void um_pci_irq_vq_addbuf(struct virtqueue *vq, void *buf, bool kick) +{ + struct scatterlist sg[1]; + + sg_init_one(sg, buf, MAX_IRQ_MSG_SIZE); + if (virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC)) + kfree(buf); + else if (kick) + virtqueue_kick(vq); +} + +static void um_pci_handle_irq_message(struct virtqueue *vq, + struct virtio_pcidev_msg *msg) +{ + struct virtio_device *vdev = vq->vdev; + struct um_pci_device *dev = vdev->priv; + + /* we should properly chain interrupts, but on ARCH=um we don't care */ + + switch (msg->op) { + case VIRTIO_PCIDEV_OP_INT: + generic_handle_irq(dev->irq); + break; + case VIRTIO_PCIDEV_OP_MSI: + /* our MSI message is just the interrupt number */ + if (msg->size == sizeof(u32)) + generic_handle_irq(le32_to_cpup((void *)msg->data)); + else + generic_handle_irq(le16_to_cpup((void *)msg->data)); + break; + case VIRTIO_PCIDEV_OP_PME: + /* nothing to do - we already woke up due to the message */ + break; + default: + dev_err(&vdev->dev, "unexpected virt-pci message %d\n", msg->op); + break; + } +} + +static void um_pci_cmd_vq_cb(struct virtqueue *vq) +{ + struct virtio_device *vdev = vq->vdev; + struct um_pci_device *dev = vdev->priv; + void *cmd; + int len; + + if (test_bit(UM_PCI_STAT_WAITING, &dev->status)) + return; + + while ((cmd = virtqueue_get_buf(vq, &len))) { + if (WARN_ON(HANDLE_IS_NO_FREE(cmd))) + continue; + kfree(cmd); + } +} + +static void um_pci_irq_vq_cb(struct virtqueue *vq) +{ + struct virtio_pcidev_msg *msg; + int len; + + while ((msg = virtqueue_get_buf(vq, &len))) { + if (len >= sizeof(*msg)) + um_pci_handle_irq_message(vq, msg); + + /* recycle the message buffer */ + um_pci_irq_vq_addbuf(vq, msg, true); + } +} + +static int um_pci_init_vqs(struct um_pci_device *dev) +{ + struct virtqueue *vqs[2]; + static const char *const names[2] = { "cmd", "irq" }; + vq_callback_t *cbs[2] = { um_pci_cmd_vq_cb, um_pci_irq_vq_cb }; + int err, i; + + err = virtio_find_vqs(dev->vdev, 2, vqs, cbs, names, NULL); + if (err) + return err; + + dev->cmd_vq = vqs[0]; + dev->irq_vq = vqs[1]; + + for (i = 0; i < NUM_IRQ_MSGS; i++) { + void *msg = kzalloc(MAX_IRQ_MSG_SIZE, GFP_KERNEL); + + if (msg) + um_pci_irq_vq_addbuf(dev->irq_vq, msg, false); + } + + virtqueue_kick(dev->irq_vq); + + return 0; +} + +static int um_pci_virtio_probe(struct virtio_device *vdev) +{ + struct um_pci_device *dev; + int i, free = -1; + int err = -ENOSPC; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->vdev = vdev; + vdev->priv = dev; + + mutex_lock(&um_pci_mtx); + for (i = 0; i < MAX_DEVICES; i++) { + if (um_pci_devices[i].dev) + continue; + free = i; + break; + } + + if (free < 0) + goto error; + + err = um_pci_init_vqs(dev); + if (err) + goto error; + + dev->irq = irq_alloc_desc(numa_node_id()); + if (dev->irq < 0) { + err = dev->irq; + goto error; + } + um_pci_devices[free].dev = dev; + vdev->priv = dev; + + mutex_unlock(&um_pci_mtx); + + device_set_wakeup_enable(&vdev->dev, true); + + /* + * In order to do suspend-resume properly, don't allow VQs + * to be suspended. + */ + virtio_uml_set_no_vq_suspend(vdev, true); + + um_pci_rescan(); + return 0; +error: + mutex_unlock(&um_pci_mtx); + kfree(dev); + return err; +} + +static void um_pci_virtio_remove(struct virtio_device *vdev) +{ + struct um_pci_device *dev = vdev->priv; + int i; + + /* Stop all virtqueues */ + vdev->config->reset(vdev); + vdev->config->del_vqs(vdev); + + device_set_wakeup_enable(&vdev->dev, false); + + mutex_lock(&um_pci_mtx); + for (i = 0; i < MAX_DEVICES; i++) { + if (um_pci_devices[i].dev != dev) + continue; + um_pci_devices[i].dev = NULL; + irq_free_desc(dev->irq); + } + mutex_unlock(&um_pci_mtx); + + um_pci_rescan(); + + kfree(dev); +} + +static struct virtio_device_id id_table[] = { + { CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; +MODULE_DEVICE_TABLE(virtio, id_table); + +static struct virtio_driver um_pci_virtio_driver = { + .driver.name = "virtio-pci", + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = um_pci_virtio_probe, + .remove = um_pci_virtio_remove, +}; + +static struct resource virt_cfgspace_resource = { + .name = "PCI config space", + .start = 0xf0000000 - MAX_DEVICES * CFG_SPACE_SIZE, + .end = 0xf0000000 - 1, + .flags = IORESOURCE_MEM, +}; + +static long um_pci_map_cfgspace(unsigned long offset, size_t size, + const struct logic_iomem_ops **ops, + void **priv) +{ + if (WARN_ON(size > CFG_SPACE_SIZE || offset % CFG_SPACE_SIZE)) + return -EINVAL; + + if (offset / CFG_SPACE_SIZE < MAX_DEVICES) { + *ops = &um_pci_device_cfgspace_ops; + *priv = &um_pci_devices[offset / CFG_SPACE_SIZE]; + return 0; + } + + WARN(1, "cannot map offset 0x%lx/0x%zx\n", offset, size); + return -ENOENT; +} + +static const struct logic_iomem_region_ops um_pci_cfgspace_ops = { + .map = um_pci_map_cfgspace, +}; + +static struct resource virt_iomem_resource = { + .name = "PCI iomem", + .start = 0xf0000000, + .end = 0xffffffff, + .flags = IORESOURCE_MEM, +}; + +struct um_pci_map_iomem_data { + unsigned long offset; + size_t size; + const struct logic_iomem_ops **ops; + void **priv; + long ret; +}; + +static int um_pci_map_iomem_walk(struct pci_dev *pdev, void *_data) +{ + struct um_pci_map_iomem_data *data = _data; + struct um_pci_device_reg *reg = &um_pci_devices[pdev->devfn / 8]; + struct um_pci_device *dev; + int i; + + if (!reg->dev) + return 0; + + for (i = 0; i < ARRAY_SIZE(dev->resptr); i++) { + struct resource *r = &pdev->resource[i]; + + if ((r->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) + continue; + + /* + * must be the whole or part of the resource, + * not allowed to only overlap + */ + if (data->offset < r->start || data->offset > r->end) + continue; + if (data->offset + data->size - 1 > r->end) + continue; + + dev = reg->dev; + *data->ops = &um_pci_device_bar_ops; + dev->resptr[i] = i; + *data->priv = &dev->resptr[i]; + data->ret = data->offset - r->start; + + /* no need to continue */ + return 1; + } + + return 0; +} + +static long um_pci_map_iomem(unsigned long offset, size_t size, + const struct logic_iomem_ops **ops, + void **priv) +{ + struct um_pci_map_iomem_data data = { + /* we want the full address here */ + .offset = offset + virt_iomem_resource.start, + .size = size, + .ops = ops, + .priv = priv, + .ret = -ENOENT, + }; + + pci_walk_bus(bridge->bus, um_pci_map_iomem_walk, &data); + return data.ret; +} + +static const struct logic_iomem_region_ops um_pci_iomem_ops = { + .map = um_pci_map_iomem, +}; + +static void um_pci_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + /* + * This is a very low address and not actually valid 'physical' memory + * in UML, so we can simply map MSI(-X) vectors to there, it cannot be + * legitimately written to by the device in any other way. + * We use the (virtual) IRQ number here as the message to simplify the + * code that receives the message, where for now we simply trust the + * device to send the correct message. + */ + msg->address_hi = 0; + msg->address_lo = 0xa0000; + msg->data = data->irq; +} + +static struct irq_chip um_pci_msi_bottom_irq_chip = { + .name = "UM virtio MSI", + .irq_compose_msi_msg = um_pci_compose_msi_msg, +}; + +static int um_pci_inner_domain_alloc(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs, + void *args) +{ + unsigned long bit; + + WARN_ON(nr_irqs != 1); + + mutex_lock(&um_pci_mtx); + bit = find_first_zero_bit(um_pci_msi_used, MAX_MSI_VECTORS); + if (bit >= MAX_MSI_VECTORS) { + mutex_unlock(&um_pci_mtx); + return -ENOSPC; + } + + set_bit(bit, um_pci_msi_used); + mutex_unlock(&um_pci_mtx); + + irq_domain_set_info(domain, virq, bit, &um_pci_msi_bottom_irq_chip, + domain->host_data, handle_simple_irq, + NULL, NULL); + + return 0; +} + +static void um_pci_inner_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + + mutex_lock(&um_pci_mtx); + + if (!test_bit(d->hwirq, um_pci_msi_used)) + pr_err("trying to free unused MSI#%lu\n", d->hwirq); + else + __clear_bit(d->hwirq, um_pci_msi_used); + + mutex_unlock(&um_pci_mtx); +} + +static const struct irq_domain_ops um_pci_inner_domain_ops = { + .alloc = um_pci_inner_domain_alloc, + .free = um_pci_inner_domain_free, +}; + +static struct irq_chip um_pci_msi_irq_chip = { + .name = "UM virtio PCIe MSI", + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + +static struct msi_domain_info um_pci_msi_domain_info = { + .flags = MSI_FLAG_USE_DEF_DOM_OPS | + MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX, + .chip = &um_pci_msi_irq_chip, +}; + +static struct resource busn_resource = { + .name = "PCI busn", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUS, +}; + +static int um_pci_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) +{ + struct um_pci_device_reg *reg = &um_pci_devices[pdev->devfn / 8]; + + if (WARN_ON(!reg->dev)) + return -EINVAL; + + /* Yes, we map all pins to the same IRQ ... doesn't matter for now. */ + return reg->dev->irq; +} + +void *pci_root_bus_fwnode(struct pci_bus *bus) +{ + return um_pci_fwnode; +} + +int um_pci_init(void) +{ + int err, i; + + WARN_ON(logic_iomem_add_region(&virt_cfgspace_resource, + &um_pci_cfgspace_ops)); + WARN_ON(logic_iomem_add_region(&virt_iomem_resource, + &um_pci_iomem_ops)); + + if (WARN(CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID < 0, + "No virtio device ID configured for PCI - no PCI support\n")) + return 0; + + bridge = pci_alloc_host_bridge(0); + if (!bridge) + return -ENOMEM; + + um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci"); + if (!um_pci_fwnode) { + err = -ENOMEM; + goto free; + } + + um_pci_inner_domain = __irq_domain_add(um_pci_fwnode, MAX_MSI_VECTORS, + MAX_MSI_VECTORS, 0, + &um_pci_inner_domain_ops, NULL); + if (!um_pci_inner_domain) { + err = -ENOMEM; + goto free; + } + + um_pci_msi_domain = pci_msi_create_irq_domain(um_pci_fwnode, + &um_pci_msi_domain_info, + um_pci_inner_domain); + if (!um_pci_msi_domain) { + err = -ENOMEM; + goto free; + } + + pci_add_resource(&bridge->windows, &virt_iomem_resource); + pci_add_resource(&bridge->windows, &busn_resource); + bridge->ops = &um_pci_ops; + bridge->map_irq = um_pci_map_irq; + + for (i = 0; i < MAX_DEVICES; i++) { + resource_size_t start; + + start = virt_cfgspace_resource.start + i * CFG_SPACE_SIZE; + um_pci_devices[i].iomem = ioremap(start, CFG_SPACE_SIZE); + if (WARN(!um_pci_devices[i].iomem, "failed to map %d\n", i)) { + err = -ENOMEM; + goto free; + } + } + + err = pci_host_probe(bridge); + if (err) + goto free; + + err = register_virtio_driver(&um_pci_virtio_driver); + if (err) + goto free; + return 0; +free: + if (um_pci_inner_domain) + irq_domain_remove(um_pci_inner_domain); + if (um_pci_fwnode) + irq_domain_free_fwnode(um_pci_fwnode); + pci_free_resource_list(&bridge->windows); + pci_free_host_bridge(bridge); + return err; +} +module_init(um_pci_init); + +void um_pci_exit(void) +{ + unregister_virtio_driver(&um_pci_virtio_driver); + irq_domain_remove(um_pci_msi_domain); + irq_domain_remove(um_pci_inner_domain); + pci_free_resource_list(&bridge->windows); + pci_free_host_bridge(bridge); +} +module_exit(um_pci_exit); diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 91ddf74ca888..4412d6febade 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -56,6 +56,7 @@ struct virtio_uml_device { u8 status; u8 registered:1; u8 suspended:1; + u8 no_vq_suspend:1; u8 config_changed_irq:1; uint64_t vq_irq_vq_map; @@ -1098,6 +1099,19 @@ static void virtio_uml_release_dev(struct device *d) kfree(vu_dev); } +void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, + bool no_vq_suspend) +{ + struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); + + if (WARN_ON(vdev->config != &virtio_uml_config_ops)) + return; + + vu_dev->no_vq_suspend = no_vq_suspend; + dev_info(&vdev->dev, "%sabled VQ suspend\n", + no_vq_suspend ? "dis" : "en"); +} + /* Platform device */ static int virtio_uml_probe(struct platform_device *pdev) @@ -1302,13 +1316,16 @@ MODULE_DEVICE_TABLE(of, virtio_uml_match); static int virtio_uml_suspend(struct platform_device *pdev, pm_message_t state) { struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); - struct virtqueue *vq; - virtio_device_for_each_vq((&vu_dev->vdev), vq) { - struct virtio_uml_vq_info *info = vq->priv; + if (!vu_dev->no_vq_suspend) { + struct virtqueue *vq; - info->suspended = true; - vhost_user_set_vring_enable(vu_dev, vq->index, false); + virtio_device_for_each_vq((&vu_dev->vdev), vq) { + struct virtio_uml_vq_info *info = vq->priv; + + info->suspended = true; + vhost_user_set_vring_enable(vu_dev, vq->index, false); + } } if (!device_may_wakeup(&vu_dev->vdev.dev)) { @@ -1322,13 +1339,16 @@ static int virtio_uml_suspend(struct platform_device *pdev, pm_message_t state) static int virtio_uml_resume(struct platform_device *pdev) { struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); - struct virtqueue *vq; - virtio_device_for_each_vq((&vu_dev->vdev), vq) { - struct virtio_uml_vq_info *info = vq->priv; + if (!vu_dev->no_vq_suspend) { + struct virtqueue *vq; - info->suspended = false; - vhost_user_set_vring_enable(vu_dev, vq->index, true); + virtio_device_for_each_vq((&vu_dev->vdev), vq) { + struct virtio_uml_vq_info *info = vq->priv; + + info->suspended = false; + vhost_user_set_vring_enable(vu_dev, vq->index, true); + } } vu_dev->suspended = false; diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index d7492e5a1bbb..e5a7b552bb38 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -7,8 +7,8 @@ generic-y += device.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h +generic-y += fb.h generic-y += ftrace.h -generic-y += futex.h generic-y += hw_irq.h generic-y += irq_regs.h generic-y += irq_work.h @@ -17,7 +17,6 @@ generic-y += mcs_spinlock.h generic-y += mmiowb.h generic-y += module.lds.h generic-y += param.h -generic-y += pci.h generic-y += percpu.h generic-y += preempt.h generic-y += softirq_stack.h @@ -27,3 +26,4 @@ generic-y += trace_clock.h generic-y += word-at-a-time.h generic-y += kprobes.h generic-y += mm_hooks.h +generic-y += vga.h diff --git a/arch/um/include/asm/cacheflush.h b/arch/um/include/asm/cacheflush.h new file mode 100644 index 000000000000..4c9858cd36ec --- /dev/null +++ b/arch/um/include/asm/cacheflush.h @@ -0,0 +1,9 @@ +#ifndef __UM_ASM_CACHEFLUSH_H +#define __UM_ASM_CACHEFLUSH_H + +#include +#define flush_cache_vmap flush_tlb_kernel_range +#define flush_cache_vunmap flush_tlb_kernel_range + +#include +#endif /* __UM_ASM_CACHEFLUSH_H */ diff --git a/arch/um/include/asm/cpufeature.h b/arch/um/include/asm/cpufeature.h new file mode 100644 index 000000000000..19cd7ed6ec3c --- /dev/null +++ b/arch/um/include/asm/cpufeature.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_UM_CPUFEATURE_H +#define _ASM_UM_CPUFEATURE_H + +#include + +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) + +#include +#include + +extern const char * const x86_cap_flags[NCAPINTS*32]; +extern const char * const x86_power_flags[32]; +#define X86_CAP_FMT "%s" +#define x86_cap_flag(flag) x86_cap_flags[flag] + +/* + * In order to save room, we index into this array by doing + * X86_BUG_ - NCAPINTS*32. + */ +extern const char * const x86_bug_flags[NBUGINTS*32]; + +#define test_cpu_cap(c, bit) \ + test_bit(bit, (unsigned long *)((c)->x86_capability)) + +/* + * There are 32 bits/features in each mask word. The high bits + * (selected with (bit>>5) give us the word number and the low 5 + * bits give us the bit/feature number inside the word. + * (1UL<<((bit)&31) gives us a mask for the feature_bit so we can + * see if it is set in the mask word. + */ +#define CHECK_BIT_IN_MASK_WORD(maskname, word, bit) \ + (((bit)>>5)==(word) && (1UL<<((bit)&31) & maskname##word )) + +#define cpu_has(c, bit) \ + test_cpu_cap(c, bit) + +#define this_cpu_has(bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ + x86_this_cpu_test_bit(bit, \ + (unsigned long __percpu *)&cpu_info.x86_capability)) + +/* + * This macro is for detection of features which need kernel + * infrastructure to be used. It may *not* directly test the CPU + * itself. Use the cpu_has() family if you want true runtime + * testing of CPU features, like in hypervisor code where you are + * supporting a possible guest feature where host support for it + * is not relevant. + */ +#define cpu_feature_enabled(bit) \ + (__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit)) + +#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) + +#define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) + +extern void setup_clear_cpu_cap(unsigned int bit); + +#define setup_force_cpu_cap(bit) do { \ + set_cpu_cap(&boot_cpu_data, bit); \ + set_bit(bit, (unsigned long *)cpu_caps_set); \ +} while (0) + +#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit) + +#if defined(__clang__) && !defined(CONFIG_CC_HAS_ASM_GOTO) + +/* + * Workaround for the sake of BPF compilation which utilizes kernel + * headers, but clang does not support ASM GOTO and fails the build. + */ +#ifndef __BPF_TRACING__ +#warning "Compiler lacks ASM_GOTO support. Add -D __BPF_TRACING__ to your compiler arguments" +#endif + +#define static_cpu_has(bit) boot_cpu_has(bit) + +#else + +/* + * Static testing of CPU features. Used the same as boot_cpu_has(). It + * statically patches the target code for additional performance. Use + * static_cpu_has() only in fast paths, where every cycle counts. Which + * means that the boot_cpu_has() variant is already fast enough for the + * majority of cases and you should stick to using it as it is generally + * only two instructions: a RIP-relative MOV and a TEST. + */ +static __always_inline bool _static_cpu_has(u16 bit) +{ + asm_volatile_goto("1: jmp 6f\n" + "2:\n" + ".skip -(((5f-4f) - (2b-1b)) > 0) * " + "((5f-4f) - (2b-1b)),0x90\n" + "3:\n" + ".section .altinstructions,\"a\"\n" + " .long 1b - .\n" /* src offset */ + " .long 4f - .\n" /* repl offset */ + " .word %P[always]\n" /* always replace */ + " .byte 3b - 1b\n" /* src len */ + " .byte 5f - 4f\n" /* repl len */ + " .byte 3b - 2b\n" /* pad len */ + ".previous\n" + ".section .altinstr_replacement,\"ax\"\n" + "4: jmp %l[t_no]\n" + "5:\n" + ".previous\n" + ".section .altinstructions,\"a\"\n" + " .long 1b - .\n" /* src offset */ + " .long 0\n" /* no replacement */ + " .word %P[feature]\n" /* feature bit */ + " .byte 3b - 1b\n" /* src len */ + " .byte 0\n" /* repl len */ + " .byte 0\n" /* pad len */ + ".previous\n" + ".section .altinstr_aux,\"ax\"\n" + "6:\n" + " testb %[bitnum],%[cap_byte]\n" + " jnz %l[t_yes]\n" + " jmp %l[t_no]\n" + ".previous\n" + : : [feature] "i" (bit), + [always] "i" (X86_FEATURE_ALWAYS), + [bitnum] "i" (1 << (bit & 7)), + [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3]) + : : t_yes, t_no); +t_yes: + return true; +t_no: + return false; +} + +#define static_cpu_has(bit) \ +( \ + __builtin_constant_p(boot_cpu_has(bit)) ? \ + boot_cpu_has(bit) : \ + _static_cpu_has(bit) \ +) +#endif + +#define cpu_has_bug(c, bit) cpu_has(c, (bit)) +#define set_cpu_bug(c, bit) set_cpu_cap(c, (bit)) + +#define static_cpu_has_bug(bit) static_cpu_has((bit)) +#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit)) +#define boot_cpu_set_bug(bit) set_cpu_cap(&boot_cpu_data, (bit)) + +#define MAX_CPU_FEATURES (NCAPINTS * 32) +#define cpu_have_feature boot_cpu_has + +#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X" +#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \ + boot_cpu_data.x86_model + +#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */ +#endif /* _ASM_UM_CPUFEATURE_H */ diff --git a/arch/um/include/asm/fpu/api.h b/arch/um/include/asm/fpu/api.h new file mode 100644 index 000000000000..71bfd9ef3938 --- /dev/null +++ b/arch/um/include/asm/fpu/api.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _ASM_UM_FPU_API_H +#define _ASM_UM_FPU_API_H + +/* Copyright (c) 2020 Cambridge Greys Ltd + * Copyright (c) 2020 Red Hat Inc. + * A set of "dummy" defines to allow the direct inclusion + * of x86 optimized copy, xor, etc routines into the + * UML code tree. */ + +#define kernel_fpu_begin() (void)0 +#define kernel_fpu_end() (void)0 + +static inline bool irq_fpu_usable(void) +{ + return true; +} + + +#endif diff --git a/arch/um/include/asm/futex.h b/arch/um/include/asm/futex.h new file mode 100644 index 000000000000..780aa6bfc050 --- /dev/null +++ b/arch/um/include/asm/futex.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_UM_FUTEX_H +#define _ASM_UM_FUTEX_H + +#include +#include +#include + + +int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr); +int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, + u32 oldval, u32 newval); + +#endif diff --git a/arch/um/include/asm/io.h b/arch/um/include/asm/io.h index 6ce18d343997..9ea42cc746d9 100644 --- a/arch/um/include/asm/io.h +++ b/arch/um/include/asm/io.h @@ -3,16 +3,23 @@ #define _ASM_UM_IO_H #include +/* get emulated iomem (if desired) */ +#include + +#ifndef ioremap #define ioremap ioremap static inline void __iomem *ioremap(phys_addr_t offset, size_t size) { return NULL; } +#endif /* ioremap */ +#ifndef iounmap #define iounmap iounmap static inline void iounmap(void __iomem *addr) { } +#endif /* iounmap */ #include diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h index 3f5d3e8228fc..e187c789369d 100644 --- a/arch/um/include/asm/irq.h +++ b/arch/um/include/asm/irq.h @@ -31,7 +31,13 @@ #endif -#define NR_IRQS 64 +#define UM_LAST_SIGNAL_IRQ 64 +/* If we have (simulated) PCI MSI, allow 64 more interrupt numbers for it */ +#ifdef CONFIG_PCI_MSI +#define NR_IRQS (UM_LAST_SIGNAL_IRQ + 64) +#else +#define NR_IRQS UM_LAST_SIGNAL_IRQ +#endif /* CONFIG_PCI_MSI */ #include #endif diff --git a/arch/um/include/asm/irqflags.h b/arch/um/include/asm/irqflags.h index 0642ad9035d1..dab5744e9253 100644 --- a/arch/um/include/asm/irqflags.h +++ b/arch/um/include/asm/irqflags.h @@ -2,15 +2,15 @@ #ifndef __UM_IRQFLAGS_H #define __UM_IRQFLAGS_H -extern int get_signals(void); -extern int set_signals(int enable); -extern void block_signals(void); -extern void unblock_signals(void); +extern int signals_enabled; +int set_signals(int enable); +void block_signals(void); +void unblock_signals(void); #define arch_local_save_flags arch_local_save_flags static inline unsigned long arch_local_save_flags(void) { - return get_signals(); + return signals_enabled; } #define arch_local_irq_restore arch_local_irq_restore diff --git a/arch/um/include/asm/msi.h b/arch/um/include/asm/msi.h new file mode 100644 index 000000000000..c8c6c381f394 --- /dev/null +++ b/arch/um/include/asm/msi.h @@ -0,0 +1 @@ +#include diff --git a/arch/um/include/asm/pci.h b/arch/um/include/asm/pci.h new file mode 100644 index 000000000000..da13fd5519ef --- /dev/null +++ b/arch/um/include/asm/pci.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_UM_PCI_H +#define __ASM_UM_PCI_H +#include +#include + +#define PCIBIOS_MIN_IO 0 +#define PCIBIOS_MIN_MEM 0 + +#define pcibios_assign_all_busses() 1 + +extern int isa_dma_bridge_buggy; + +#ifdef CONFIG_PCI +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + /* no legacy IRQs */ + return -ENODEV; +} +#endif + +#ifdef CONFIG_PCI_DOMAINS +static inline int pci_proc_domain(struct pci_bus *bus) +{ + /* always show the domain in /proc */ + return 1; +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +/* + * This is a bit of an annoying hack, and it assumes we only have + * the virt-pci (if anything). Which is true, but still. + */ +void *pci_root_bus_fwnode(struct pci_bus *bus); +#define pci_root_bus_fwnode pci_root_bus_fwnode +#endif + +#endif /* __ASM_UM_PCI_H */ diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h index 9289a86643a9..cb896e6121c8 100644 --- a/arch/um/include/asm/pgtable-3level.h +++ b/arch/um/include/asm/pgtable-3level.h @@ -83,7 +83,7 @@ static inline void pud_clear (pud_t *pud) } #define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK) -#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK)) +#define pud_pgtable(pud) ((pmd_t *) __va(pud_val(pud) & PAGE_MASK)) static inline unsigned long pte_pfn(pte_t pte) { diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index afd9b267cf81..b5cf0ed116d9 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -16,6 +16,8 @@ struct task_struct; #include +#include + struct mm_struct; struct thread_struct { @@ -90,12 +92,18 @@ extern void start_thread(struct pt_regs *regs, unsigned long entry, struct cpuinfo_um { unsigned long loops_per_jiffy; int ipi_pipe[2]; + int cache_alignment; + union { + __u32 x86_capability[NCAPINTS + NBUGINTS]; + unsigned long x86_capability_alignment; + }; }; extern struct cpuinfo_um boot_cpu_data; #define cpu_data (&boot_cpu_data) #define current_cpu_data boot_cpu_data +#define cache_line_size() (boot_cpu_data.cache_alignment) #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) extern unsigned long get_wchan(struct task_struct *p); diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h index ff9c62828962..0422467bda5b 100644 --- a/arch/um/include/asm/tlb.h +++ b/arch/um/include/asm/tlb.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #endif diff --git a/arch/um/include/asm/xor.h b/arch/um/include/asm/xor.h index 36b33d62a35d..f512704a9ec7 100644 --- a/arch/um/include/asm/xor.h +++ b/arch/um/include/asm/xor.h @@ -1,7 +1,22 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#include +#ifndef _ASM_UM_XOR_H +#define _ASM_UM_XOR_H + +#ifdef CONFIG_64BIT +#undef CONFIG_X86_32 +#else +#define CONFIG_X86_32 1 +#endif + +#include +#include <../../x86/include/asm/xor.h> #include +#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT +#undef XOR_SELECT_TEMPLATE /* pick an arbitrary one - measuring isn't possible with inf-cpu */ #define XOR_SELECT_TEMPLATE(x) \ (time_travel_mode == TT_MODE_INFCPU ? &xor_block_8regs : NULL) +#endif + +#endif diff --git a/arch/um/include/linux/time-internal.h b/arch/um/include/linux/time-internal.h index 759956ab0108..b22226634ff6 100644 --- a/arch/um/include/linux/time-internal.h +++ b/arch/um/include/linux/time-internal.h @@ -8,17 +8,11 @@ #define __TIMER_INTERNAL_H__ #include #include +#include #define TIMER_MULTIPLIER 256 #define TIMER_MIN_DELTA 500 -enum time_travel_mode { - TT_MODE_OFF, - TT_MODE_BASIC, - TT_MODE_INFCPU, - TT_MODE_EXTERNAL, -}; - #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT struct time_travel_event { unsigned long long time; @@ -27,8 +21,6 @@ struct time_travel_event { bool pending, onstack; }; -extern enum time_travel_mode time_travel_mode; - void time_travel_sleep(void); static inline void @@ -62,8 +54,6 @@ bool time_travel_del_event(struct time_travel_event *e); struct time_travel_event { }; -#define time_travel_mode TT_MODE_OFF - static inline void time_travel_sleep(void) { } diff --git a/arch/um/include/linux/virtio-uml.h b/arch/um/include/linux/virtio-uml.h new file mode 100644 index 000000000000..2f652fa90f04 --- /dev/null +++ b/arch/um/include/linux/virtio-uml.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Intel Corporation + * Author: Johannes Berg + */ + +#ifndef __VIRTIO_UML_H__ +#define __VIRTIO_UML_H__ + +void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, + bool no_vq_suspend); + +#endif /* __VIRTIO_UML_H__ */ diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h index 07239e801a5b..065829f443ae 100644 --- a/arch/um/include/shared/irq_user.h +++ b/arch/um/include/shared/irq_user.h @@ -17,6 +17,7 @@ enum um_irq_type { struct siginfo; extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +void sigio_run_timetravel_handlers(void); extern void free_irq_by_fd(int fd); extern void deactivate_fd(int fd, int irqnum); extern int deactivate_all_fds(void); diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index 2888ec812f6e..a2cfd42608a0 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -33,7 +33,6 @@ extern int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out); extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); -extern int smp_sigio_handler(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int is_syscall(unsigned long addr); diff --git a/arch/um/include/shared/longjmp.h b/arch/um/include/shared/longjmp.h index 85a1cc290ecb..bdb2869b72b3 100644 --- a/arch/um/include/shared/longjmp.h +++ b/arch/um/include/shared/longjmp.h @@ -5,6 +5,7 @@ #include #include +extern int signals_enabled; extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); @@ -12,13 +13,12 @@ extern void longjmp(jmp_buf, int); longjmp(*buf, val); \ } while(0) -#define UML_SETJMP(buf) ({ \ - int n; \ - volatile int enable; \ - enable = get_signals(); \ - n = setjmp(*buf); \ - if(n != 0) \ - set_signals_trace(enable); \ +#define UML_SETJMP(buf) ({ \ + int n, enable; \ + enable = *(volatile int *)&signals_enabled; \ + n = setjmp(*buf); \ + if(n != 0) \ + set_signals_trace(enable); \ n; }) #endif diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 13d86f94cf0f..60b84edc8a68 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -187,6 +187,9 @@ int os_poll(unsigned int n, const int *fds); extern void os_early_checks(void); extern void os_check_bugs(void); extern void check_host_supports_tls(int *supports_tls, int *tls_min); +extern void get_host_cpu_features( + void (*flags_helper_func)(char *line), + void (*cache_helper_func)(char *line)); /* mem.c */ extern int create_mem_file(unsigned long long len); @@ -211,7 +214,6 @@ extern int os_protect_memory(void *addr, unsigned long len, extern int os_unmap_memory(void *addr, int len); extern int os_drop_memory(void *addr, int length); extern int can_drop_memory(void); -extern void os_flush_stdout(void); extern int os_mincore(void *addr, unsigned long len); /* execvp.c */ @@ -237,12 +239,14 @@ extern void send_sigio_to_self(void); extern int change_sig(int signal, int on); extern void block_signals(void); extern void unblock_signals(void); -extern int get_signals(void); extern int set_signals(int enable); extern int set_signals_trace(int enable); extern int os_is_signal_stack(void); extern void deliver_alarm(void); extern void register_pm_wake_signal(void); +extern void block_signals_hard(void); +extern void unblock_signals_hard(void); +extern void mark_sigio_pending(void); /* util.c */ extern void stack_protections(unsigned long address); diff --git a/arch/um/include/shared/timetravel.h b/arch/um/include/shared/timetravel.h new file mode 100644 index 000000000000..e5c3d69f1b69 --- /dev/null +++ b/arch/um/include/shared/timetravel.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019-2021 Intel Corporation + */ +#ifndef _UM_TIME_TRAVEL_H_ +#define _UM_TIME_TRAVEL_H_ + +enum time_travel_mode { + TT_MODE_OFF, + TT_MODE_BASIC, + TT_MODE_INFCPU, + TT_MODE_EXTERNAL, +}; + +#if defined(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT) || \ + defined(CONFIG_UML_TIME_TRAVEL_SUPPORT) +extern enum time_travel_mode time_travel_mode; +#else +#define time_travel_mode TT_MODE_OFF +#endif /* (UML_)CONFIG_UML_TIME_TRAVEL_SUPPORT */ + +#endif /* _UM_TIME_TRAVEL_H_ */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index e698e0c7dbdc..1d18e4e46989 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -17,18 +17,19 @@ extra-y := vmlinux.lds obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ physmem.o process.o ptrace.o reboot.o sigio.o \ signal.o syscall.o sysrq.o time.o tlb.o trap.o \ - um_arch.o umid.o maccess.o kmsg_dump.o skas/ + um_arch.o umid.o maccess.o kmsg_dump.o capflags.o skas/ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_GENERIC_PCI_IOMAP) += ioport.o USER_OBJS := config.o include arch/um/scripts/Makefile.rules -targets := config.c config.tmp +targets := config.c config.tmp capflags.c # Be careful with the below Sed code - sed is pitfall-rich! # We use sed to lower build requirements, for "embedded" builders for instance. @@ -43,6 +44,15 @@ quiet_cmd_quote1 = QUOTE $@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE $(call if_changed,quote2) +quiet_cmd_mkcapflags = MKCAP $@ + cmd_mkcapflags = $(CONFIG_SHELL) $(srctree)/$(src)/../../x86/kernel/cpu/mkcapflags.sh $@ $^ + +cpufeature = $(src)/../../x86/include/asm/cpufeatures.h +vmxfeature = $(src)/../../x86/include/asm/vmxfeatures.h + +$(obj)/capflags.c: $(cpufeature) $(vmxfeature) $(src)/../../x86/kernel/cpu/mkcapflags.sh FORCE + $(call if_changed,mkcapflags) + quiet_cmd_quote2 = QUOTE $@ cmd_quote2 = sed -e '/CONFIG/{' \ -e 's/"CONFIG"//' \ diff --git a/arch/um/kernel/ioport.c b/arch/um/kernel/ioport.c new file mode 100644 index 000000000000..7220615b3beb --- /dev/null +++ b/arch/um/kernel/ioport.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Intel Corporation + * Author: Johannes Berg + */ +#include +#include + +void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port, + unsigned int nr) +{ + return NULL; +} diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 82af5191e73d..a8873d9bc28b 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -56,7 +56,7 @@ struct irq_entry { static DEFINE_SPINLOCK(irq_lock); static LIST_HEAD(active_fds); -static DECLARE_BITMAP(irqs_allocated, NR_IRQS); +static DECLARE_BITMAP(irqs_allocated, UM_LAST_SIGNAL_IRQ); static bool irqs_suspended; static void irq_io_loop(struct irq_reg *irq, struct uml_pt_regs *regs) @@ -101,10 +101,12 @@ static bool irq_do_timetravel_handler(struct irq_entry *entry, if (!reg->timetravel_handler) return false; - /* prevent nesting - we'll get it again later when we SIGIO ourselves */ - if (reg->pending_on_resume) - return true; - + /* + * Handle all messages - we might get multiple even while + * interrupts are already suspended, due to suspend order + * etc. Note that time_travel_add_irq_event() will not add + * an event twice, if it's pending already "first wins". + */ reg->timetravel_handler(reg->irq, entry->fd, reg->id, ®->event); if (!reg->event.pending) @@ -123,7 +125,8 @@ static bool irq_do_timetravel_handler(struct irq_entry *entry, #endif static void sigio_reg_handler(int idx, struct irq_entry *entry, enum um_irq_type t, - struct uml_pt_regs *regs) + struct uml_pt_regs *regs, + bool timetravel_handlers_only) { struct irq_reg *reg = &entry->reg[t]; @@ -136,18 +139,29 @@ static void sigio_reg_handler(int idx, struct irq_entry *entry, enum um_irq_type if (irq_do_timetravel_handler(entry, t)) return; - if (irqs_suspended) + /* + * If we're called to only run time-travel handlers then don't + * actually proceed but mark sigio as pending (if applicable). + * For suspend/resume, timetravel_handlers_only may be true + * despite time-travel not being configured and used. + */ + if (timetravel_handlers_only) { +#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT + mark_sigio_pending(); +#endif return; + } irq_io_loop(reg, regs); } -void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) +static void _sigio_handler(struct uml_pt_regs *regs, + bool timetravel_handlers_only) { struct irq_entry *irq_entry; int n, i; - if (irqs_suspended && !um_irq_timetravel_handler_used()) + if (timetravel_handlers_only && !um_irq_timetravel_handler_used()) return; while (1) { @@ -172,14 +186,20 @@ void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) irq_entry = os_epoll_get_data_pointer(i); for (t = 0; t < NUM_IRQ_TYPES; t++) - sigio_reg_handler(i, irq_entry, t, regs); + sigio_reg_handler(i, irq_entry, t, regs, + timetravel_handlers_only); } } - if (!irqs_suspended) + if (!timetravel_handlers_only) free_irqs(); } +void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) +{ + _sigio_handler(regs, irqs_suspended); +} + static struct irq_entry *get_irq_entry_by_fd(int fd) { struct irq_entry *walk; @@ -399,7 +419,8 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs) void um_free_irq(int irq, void *dev) { - if (WARN(irq < 0 || irq > NR_IRQS, "freeing invalid irq %d", irq)) + if (WARN(irq < 0 || irq > UM_LAST_SIGNAL_IRQ, + "freeing invalid irq %d", irq)) return; free_irq_by_irq_and_dev(irq, dev); @@ -467,6 +488,11 @@ int um_request_irq_tt(int irq, int fd, enum um_irq_type type, devname, dev_id, timetravel_handler); } EXPORT_SYMBOL(um_request_irq_tt); + +void sigio_run_timetravel_handlers(void) +{ + _sigio_handler(NULL, true); +} #endif #ifdef CONFIG_PM_SLEEP @@ -623,7 +649,7 @@ void __init init_IRQ(void) irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_edge_irq); - for (i = 1; i < NR_IRQS; i++) + for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++) irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); /* Initialize EPOLL Loop */ os_setup_epoll(); diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 8ade54a86a7e..b1e5634398d0 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -7,7 +7,7 @@ #include EXPORT_SYMBOL(set_signals); -EXPORT_SYMBOL(get_signals); +EXPORT_SYMBOL(signals_enabled); EXPORT_SYMBOL(os_stat_fd); EXPORT_SYMBOL(os_stat_file); diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 592cdb138441..5afac0fef24e 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -29,7 +29,7 @@ stub_clone_handler(void) long err; err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, - (unsigned long)data + UM_KERN_PAGE_SIZE / 2 - sizeof(void *)); + (unsigned long)data + UM_KERN_PAGE_SIZE / 2); if (err) { data->parent_err = err; goto done; diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 2dec915abe6f..6c76df96e858 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -11,6 +11,7 @@ #include #include #include +#include #include pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr) @@ -248,3 +249,138 @@ long __strnlen_user(const void __user *str, long len) return 0; } EXPORT_SYMBOL(__strnlen_user); + +/** + * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant + * argument and comparison of the previous + * futex value with another constant. + * + * @encoded_op: encoded operation to execute + * @uaddr: pointer to user space address + * + * Return: + * 0 - On success + * -EFAULT - User access resulted in a page fault + * -EAGAIN - Atomic operation was unable to complete due to contention + * -ENOSYS - Operation not supported + */ + +int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) +{ + int oldval, ret; + struct page *page; + unsigned long addr = (unsigned long) uaddr; + pte_t *pte; + + ret = -EFAULT; + if (!access_ok(uaddr, sizeof(*uaddr))) + return -EFAULT; + preempt_disable(); + pte = maybe_map(addr, 1); + if (pte == NULL) + goto out_inuser; + + page = pte_page(*pte); +#ifdef CONFIG_64BIT + pagefault_disable(); + addr = (unsigned long) page_address(page) + + (((unsigned long) addr) & ~PAGE_MASK); +#else + addr = (unsigned long) kmap_atomic(page) + + ((unsigned long) addr & ~PAGE_MASK); +#endif + uaddr = (u32 *) addr; + oldval = *uaddr; + + ret = 0; + + switch (op) { + case FUTEX_OP_SET: + *uaddr = oparg; + break; + case FUTEX_OP_ADD: + *uaddr += oparg; + break; + case FUTEX_OP_OR: + *uaddr |= oparg; + break; + case FUTEX_OP_ANDN: + *uaddr &= ~oparg; + break; + case FUTEX_OP_XOR: + *uaddr ^= oparg; + break; + default: + ret = -ENOSYS; + } +#ifdef CONFIG_64BIT + pagefault_enable(); +#else + kunmap_atomic((void *)addr); +#endif + +out_inuser: + preempt_enable(); + + if (ret == 0) + *oval = oldval; + + return ret; +} +EXPORT_SYMBOL(arch_futex_atomic_op_inuser); + +/** + * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the + * uaddr with newval if the current value is + * oldval. + * @uval: pointer to store content of @uaddr + * @uaddr: pointer to user space address + * @oldval: old value + * @newval: new value to store to @uaddr + * + * Return: + * 0 - On success + * -EFAULT - User access resulted in a page fault + * -EAGAIN - Atomic operation was unable to complete due to contention + * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) + */ + +int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, + u32 oldval, u32 newval) +{ + struct page *page; + pte_t *pte; + int ret = -EFAULT; + + if (!access_ok(uaddr, sizeof(*uaddr))) + return -EFAULT; + + preempt_disable(); + pte = maybe_map((unsigned long) uaddr, 1); + if (pte == NULL) + goto out_inatomic; + + page = pte_page(*pte); +#ifdef CONFIG_64BIT + pagefault_disable(); + uaddr = page_address(page) + (((unsigned long) uaddr) & ~PAGE_MASK); +#else + uaddr = kmap_atomic(page) + ((unsigned long) uaddr & ~PAGE_MASK); +#endif + + *uval = *uaddr; + + ret = cmpxchg(uaddr, oldval, newval); + +#ifdef CONFIG_64BIT + pagefault_enable(); +#else + kunmap_atomic(uaddr); +#endif + ret = 0; + +out_inatomic: + preempt_enable(); + return ret; +} +EXPORT_SYMBOL(futex_atomic_cmpxchg_inatomic); diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index e0cdb9694fb8..fddd1dec27e6 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -68,23 +68,15 @@ static void time_travel_handle_message(struct um_timetravel_msg *msg, int ret; /* - * Poll outside the locked section (if we're not called to only read - * the response) so we can get interrupts for e.g. virtio while we're - * here, but then we need to lock to not get interrupted between the - * read of the message and write of the ACK. + * We can't unlock here, but interrupt signals with a timetravel_handler + * (see um_request_irq_tt) get to the timetravel_handler anyway. */ if (mode != TTMH_READ) { - bool disabled = irqs_disabled(); + BUG_ON(mode == TTMH_IDLE && !irqs_disabled()); - BUG_ON(mode == TTMH_IDLE && !disabled); - - if (disabled) - local_irq_enable(); while (os_poll(1, &time_travel_ext_fd) != 0) { /* nothing */ } - if (disabled) - local_irq_disable(); } ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg)); @@ -123,15 +115,15 @@ static u64 time_travel_ext_req(u32 op, u64 time) .time = time, .seq = mseq, }; - unsigned long flags; /* - * We need to save interrupts here and only restore when we - * got the ACK - otherwise we can get interrupted and send - * another request while we're still waiting for an ACK, but - * the peer doesn't know we got interrupted and will send - * the ACKs in the same order as the message, but we'd need - * to see them in the opposite order ... + * We need to block even the timetravel handlers of SIGIO here and + * only restore their use when we got the ACK - otherwise we may + * (will) get interrupted by that, try to queue the IRQ for future + * processing and thus send another request while we're still waiting + * for an ACK, but the peer doesn't know we got interrupted and will + * send the ACKs in the same order as the message, but we'd need to + * see them in the opposite order ... * * This wouldn't matter *too* much, but some ACKs carry the * current time (for UM_TIMETRAVEL_GET) and getting another @@ -140,7 +132,7 @@ static u64 time_travel_ext_req(u32 op, u64 time) * The sequence number assignment that happens here lets us * debug such message handling issues more easily. */ - local_irq_save(flags); + block_signals_hard(); os_write_file(time_travel_ext_fd, &msg, sizeof(msg)); while (msg.op != UM_TIMETRAVEL_ACK) @@ -152,7 +144,7 @@ static u64 time_travel_ext_req(u32 op, u64 time) if (op == UM_TIMETRAVEL_GET) time_travel_set_time(msg.time); - local_irq_restore(flags); + unblock_signals_hard(); return msg.time; } @@ -352,9 +344,6 @@ void deliver_time_travel_irqs(void) while ((e = list_first_entry_or_null(&time_travel_irqs, struct time_travel_event, list))) { - WARN(e->time != time_travel_time, - "time moved from %lld to %lld before IRQ delivery\n", - time_travel_time, e->time); list_del(&e->list); e->pending = false; e->fn(e); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 9512253947d5..a149a5e9a16a 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include #include @@ -51,9 +53,13 @@ static void __init add_arg(char *arg) */ struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, - .ipi_pipe = { -1, -1 } + .ipi_pipe = { -1, -1 }, + .cache_alignment = L1_CACHE_BYTES, + .x86_capability = { 0 } }; +EXPORT_SYMBOL(boot_cpu_data); + union thread_union cpu0_irqstack __section(".data..init_irqstack") = { .thread_info = INIT_THREAD_INFO(init_task) }; @@ -63,17 +69,25 @@ static char host_info[(__NEW_UTS_LEN + 1) * 5]; static int show_cpuinfo(struct seq_file *m, void *v) { - int index = 0; + int i = 0; - seq_printf(m, "processor\t: %d\n", index); + seq_printf(m, "processor\t: %d\n", i); seq_printf(m, "vendor_id\t: User Mode Linux\n"); seq_printf(m, "model name\t: UML\n"); seq_printf(m, "mode\t\t: skas\n"); seq_printf(m, "host\t\t: %s\n", host_info); - seq_printf(m, "bogomips\t: %lu.%02lu\n\n", + seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no"); + seq_printf(m, "flags\t\t:"); + for (i = 0; i < 32*NCAPINTS; i++) + if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL)) + seq_printf(m, " %s", x86_cap_flags[i]); + seq_printf(m, "\n"); + seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment); + seq_printf(m, "bogomips\t: %lu.%02lu\n", loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); + return 0; } @@ -262,6 +276,30 @@ EXPORT_SYMBOL(end_iomem); #define MIN_VMALLOC (32 * 1024 * 1024) +static void parse_host_cpu_flags(char *line) +{ + int i; + for (i = 0; i < 32*NCAPINTS; i++) { + if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i])) + set_cpu_cap(&boot_cpu_data, i); + } +} +static void parse_cache_line(char *line) +{ + long res; + char *to_parse = strstr(line, ":"); + if (to_parse) { + to_parse++; + while (*to_parse != 0 && isspace(*to_parse)) { + to_parse++; + } + if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res)) + boot_cpu_data.cache_alignment = res; + else + boot_cpu_data.cache_alignment = L1_CACHE_BYTES; + } +} + int __init linux_main(int argc, char **argv) { unsigned long avail, diff; @@ -298,6 +336,8 @@ int __init linux_main(int argc, char **argv) /* OS sanity checks that need to happen before the kernel runs */ os_early_checks(); + get_host_cpu_features(parse_host_cpu_flags, parse_cache_line); + brk_start = (unsigned long) sbrk(0); /* diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 9fa6e4187d4f..32e88baf18dd 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -64,7 +64,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) goto out_close; } - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE; data.pre_exec = pre_exec; data.pre_data = pre_data; data.argv = argv; @@ -120,7 +120,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, if (stack == 0) return -ENOMEM; - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE; pid = clone(proc, (void *) sp, flags, arg); if (pid < 0) { err = -errno; diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 96f511d1aabe..6de99bb16113 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -18,6 +18,7 @@ #include #include #include +#include void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, @@ -62,17 +63,30 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) #define SIGALRM_BIT 1 #define SIGALRM_MASK (1 << SIGALRM_BIT) -static int signals_enabled; +int signals_enabled; +#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +static int signals_blocked; +#else +#define signals_blocked false +#endif static unsigned int signals_pending; static unsigned int signals_active = 0; void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { - int enabled; + int enabled = signals_enabled; - enabled = signals_enabled; - if (!enabled && (sig == SIGIO)) { - signals_pending |= SIGIO_MASK; + if ((signals_blocked || !enabled) && (sig == SIGIO)) { + /* + * In TT_MODE_EXTERNAL, need to still call time-travel + * handlers unless signals are also blocked for the + * external time message processing. This will mark + * signals_pending by itself (only if necessary.) + */ + if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL) + sigio_run_timetravel_handlers(); + else + signals_pending |= SIGIO_MASK; return; } @@ -129,7 +143,7 @@ void set_sigstack(void *sig_stack, int size) stack_t stack = { .ss_flags = 0, .ss_sp = sig_stack, - .ss_size = size - sizeof(void *) + .ss_size = size }; if (sigaltstack(&stack, NULL) != 0) @@ -334,11 +348,6 @@ void unblock_signals(void) } } -int get_signals(void) -{ - return signals_enabled; -} - int set_signals(int enable) { int ret; @@ -368,6 +377,39 @@ int set_signals_trace(int enable) return ret; } +#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +void mark_sigio_pending(void) +{ + signals_pending |= SIGIO_MASK; +} + +void block_signals_hard(void) +{ + if (signals_blocked) + return; + signals_blocked = 1; + barrier(); +} + +void unblock_signals_hard(void) +{ + if (!signals_blocked) + return; + /* Must be set to 0 before we check the pending bits etc. */ + signals_blocked = 0; + barrier(); + + if (signals_pending && signals_enabled) { + /* this is a bit inefficient, but that's not really important */ + block_signals(); + unblock_signals(); + } else if (signals_pending & SIGIO_MASK) { + /* we need to run time-travel handlers even if not enabled */ + sigio_run_timetravel_handlers(); + } +} +#endif + int os_is_signal_stack(void) { stack_t ss; diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index fba674fac8b7..87d3129e7362 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -327,7 +327,7 @@ int start_userspace(unsigned long stub_stack) } /* set stack pointer to the end of the stack page, so it can grow downwards */ - sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = (unsigned long)stack + UM_KERN_PAGE_SIZE; flags = CLONE_FILES | SIGCHLD; diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index f79dc338279e..8a72c99994eb 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -321,6 +321,38 @@ static void __init check_coredump_limit(void) os_info("%llu\n", (unsigned long long)lim.rlim_max); } +void __init get_host_cpu_features( + void (*flags_helper_func)(char *line), + void (*cache_helper_func)(char *line)) +{ + FILE *cpuinfo; + char *line = NULL; + size_t len = 0; + int done_parsing = 0; + + cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo == NULL) { + os_info("Failed to get host CPU features\n"); + } else { + while ((getline(&line, &len, cpuinfo)) != -1) { + if (strstr(line, "flags")) { + flags_helper_func(line); + done_parsing++; + } + if (strstr(line, "cache_alignment")) { + cache_helper_func(line); + done_parsing++; + } + free(line); + line = NULL; + if (done_parsing > 1) + break; + } + fclose(cpuinfo); + } +} + + void __init os_early_checks(void) { int pid; diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 23171b15f329..935c66f370dd 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -240,9 +240,6 @@ head-y += arch/x86/kernel/platform-quirks.o libs-y += arch/x86/lib/ -# See arch/x86/Kbuild for content of core part of the kernel -core-y += arch/x86/ - # drivers-y are linked after core-y drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/x86/pci/ diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um index 1db7913795f5..b3c1ae084180 100644 --- a/arch/x86/Makefile.um +++ b/arch/x86/Makefile.um @@ -44,7 +44,7 @@ ELF_FORMAT := elf64-x86-64 # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example. -LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64 +LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64 LINK-y += -m64 endif diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index fba2f615119a..ce763a12311c 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -451,3 +451,4 @@ 444 i386 landlock_create_ruleset sys_landlock_create_ruleset 445 i386 landlock_add_rule sys_landlock_add_rule 446 i386 landlock_restrict_self sys_landlock_restrict_self +447 i386 memfd_secret sys_memfd_secret diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index af973e400053..f6b57799c1ea 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -368,6 +368,7 @@ 444 common landlock_create_ruleset sys_landlock_create_ruleset 445 common landlock_add_rule sys_landlock_add_rule 446 common landlock_restrict_self sys_landlock_restrict_self +447 common memfd_secret sys_memfd_secret # # Due to a historical design error, certain syscalls are numbered differently diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 433399069e27..c6262b154c3a 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -40,7 +40,7 @@ * Model specific counters: * MSR_CORE_C1_RES: CORE C1 Residency Counter * perf code: 0x00 - * Available model: SLM,AMT,GLM,CNL,TNT,ADL + * Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL * Scope: Core (each processor core has a MSR) * MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter * perf code: 0x01 @@ -50,8 +50,8 @@ * MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter * perf code: 0x02 * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW, - * SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL, - * TNT,RKL,ADL + * SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX, + * TGL,TNT,RKL,ADL * Scope: Core * MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter * perf code: 0x03 @@ -61,7 +61,7 @@ * MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter. * perf code: 0x00 * Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL, - * KBL,CML,ICL,TGL,TNT,RKL,ADL + * KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL * Scope: Package (physical package) * MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter. * perf code: 0x01 @@ -72,8 +72,8 @@ * MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter. * perf code: 0x02 * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW, - * SKL,KNL,GLM,CNL,KBL,CML,ICL,TGL, - * TNT,RKL,ADL + * SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX, + * TGL,TNT,RKL,ADL * Scope: Package (physical package) * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. * perf code: 0x03 @@ -566,6 +566,14 @@ static const struct cstate_model icl_cstates __initconst = { BIT(PERF_CSTATE_PKG_C10_RES), }; +static const struct cstate_model icx_cstates __initconst = { + .core_events = BIT(PERF_CSTATE_CORE_C1_RES) | + BIT(PERF_CSTATE_CORE_C6_RES), + + .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | + BIT(PERF_CSTATE_PKG_C6_RES), +}; + static const struct cstate_model adl_cstates __initconst = { .core_events = BIT(PERF_CSTATE_CORE_C1_RES) | BIT(PERF_CSTATE_CORE_C6_RES) | @@ -664,6 +672,9 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &icl_cstates), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &icl_cstates), + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &icx_cstates), + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &icx_cstates), + X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &icl_cstates), X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &icl_cstates), X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &icl_cstates), diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index e8453de7a964..9e6d6eaeb4cb 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -491,7 +491,7 @@ static void intel_pmu_arch_lbr_xrstors(void *ctx) { struct x86_perf_task_context_arch_lbr_xsave *task_ctx = ctx; - copy_kernel_to_dynamic_supervisor(&task_ctx->xsave, XFEATURE_MASK_LBR); + xrstors(&task_ctx->xsave, XFEATURE_MASK_LBR); } static __always_inline bool lbr_is_reset_in_cstate(void *ctx) @@ -576,7 +576,7 @@ static void intel_pmu_arch_lbr_xsaves(void *ctx) { struct x86_perf_task_context_arch_lbr_xsave *task_ctx = ctx; - copy_dynamic_supervisor_to_kernel(&task_ctx->xsave, XFEATURE_MASK_LBR); + xsaves(&task_ctx->xsave, XFEATURE_MASK_LBR); } static void __intel_pmu_lbr_save(void *ctx) @@ -993,7 +993,7 @@ static void intel_pmu_arch_lbr_read_xsave(struct cpu_hw_events *cpuc) intel_pmu_store_lbr(cpuc, NULL); return; } - copy_dynamic_supervisor_to_kernel(&xsave->xsave, XFEATURE_MASK_LBR); + xsaves(&xsave->xsave, XFEATURE_MASK_LBR); intel_pmu_store_lbr(cpuc, xsave->lbr.entries); } diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index bb6eb1e5569c..609c24aec71a 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -3804,11 +3804,11 @@ pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag) /* One more for NULL. */ attrs = kcalloc((uncore_max_dies() + 1), sizeof(*attrs), GFP_KERNEL); if (!attrs) - goto err; + goto clear_topology; eas = kcalloc(uncore_max_dies(), sizeof(*eas), GFP_KERNEL); if (!eas) - goto err; + goto clear_attrs; for (die = 0; die < uncore_max_dies(); die++) { sprintf(buf, "die%ld", die); @@ -3829,7 +3829,9 @@ err: for (; die >= 0; die--) kfree(eas[die].attr.attr.name); kfree(eas); +clear_attrs: kfree(attrs); +clear_topology: kfree(type->topology); clear_attr_update: type->attr_update = NULL; diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 7d7500806af8..29fea180a665 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -312,6 +312,7 @@ do { \ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ } \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) /* @@ -328,6 +329,7 @@ extern unsigned long task_size_32bit(void); extern unsigned long task_size_64bit(int full_addr_space); extern unsigned long get_mmap_base(int is_legacy); extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); +extern unsigned long get_sigframe_size(void); #ifdef CONFIG_X86_32 @@ -349,6 +351,7 @@ do { \ if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) /* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */ @@ -357,6 +360,7 @@ do { \ if (vdso64_enabled) \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \ (unsigned long __force)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \ } while (0) #define AT_SYSINFO 32 diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 16bf4d4a8159..5a18694a89b2 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -26,16 +26,17 @@ /* * High level FPU state handling functions: */ -extern void fpu__prepare_read(struct fpu *fpu); -extern void fpu__prepare_write(struct fpu *fpu); -extern void fpu__save(struct fpu *fpu); extern int fpu__restore_sig(void __user *buf, int ia32_frame); extern void fpu__drop(struct fpu *fpu); -extern int fpu__copy(struct task_struct *dst, struct task_struct *src); extern void fpu__clear_user_states(struct fpu *fpu); -extern void fpu__clear_all(struct fpu *fpu); extern int fpu__exception_code(struct fpu *fpu, int trap_nr); +extern void fpu_sync_fpstate(struct fpu *fpu); + +/* Clone and exit operations */ +extern int fpu_clone(struct task_struct *dst); +extern void fpu_flush_thread(void); + /* * Boot time FPU initialization functions: */ @@ -45,7 +46,6 @@ extern void fpu__init_cpu_xstate(void); extern void fpu__init_system(struct cpuinfo_x86 *c); extern void fpu__init_check_bugs(void); extern void fpu__resume_cpu(void); -extern u64 fpu__get_supported_xfeatures_mask(void); /* * Debugging facility: @@ -86,23 +86,9 @@ extern void fpstate_init_soft(struct swregs_state *soft); #else static inline void fpstate_init_soft(struct swregs_state *soft) {} #endif +extern void save_fpregs_to_fpstate(struct fpu *fpu); -static inline void fpstate_init_xstate(struct xregs_state *xsave) -{ - /* - * XRSTORS requires these bits set in xcomp_bv, or it will - * trigger #GP: - */ - xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all; -} - -static inline void fpstate_init_fxstate(struct fxregs_state *fx) -{ - fx->cwd = 0x37f; - fx->mxcsr = MXCSR_DEFAULT; -} -extern void fpstate_sanitize_xstate(struct fpu *fpu); - +/* Returns 0 or the negated trap number, which results in -EFAULT for #PF */ #define user_insn(insn, output, input...) \ ({ \ int err; \ @@ -110,14 +96,14 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); might_fault(); \ \ asm volatile(ASM_STAC "\n" \ - "1:" #insn "\n\t" \ + "1: " #insn "\n" \ "2: " ASM_CLAC "\n" \ ".section .fixup,\"ax\"\n" \ - "3: movl $-1,%[err]\n" \ + "3: negl %%eax\n" \ " jmp 2b\n" \ ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : [err] "=r" (err), output \ + _ASM_EXTABLE_FAULT(1b, 3b) \ + : [err] "=a" (err), output \ : "0"(0), input); \ err; \ }) @@ -143,12 +129,12 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \ : output : input) -static inline int copy_fregs_to_user(struct fregs_state __user *fx) +static inline int fnsave_to_user_sigframe(struct fregs_state __user *fx) { return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx)); } -static inline int copy_fxregs_to_user(struct fxregs_state __user *fx) +static inline int fxsave_to_user_sigframe(struct fxregs_state __user *fx) { if (IS_ENABLED(CONFIG_X86_32)) return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); @@ -157,7 +143,7 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx) } -static inline void copy_kernel_to_fxregs(struct fxregs_state *fx) +static inline void fxrstor(struct fxregs_state *fx) { if (IS_ENABLED(CONFIG_X86_32)) kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); @@ -165,7 +151,7 @@ static inline void copy_kernel_to_fxregs(struct fxregs_state *fx) kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline int copy_kernel_to_fxregs_err(struct fxregs_state *fx) +static inline int fxrstor_safe(struct fxregs_state *fx) { if (IS_ENABLED(CONFIG_X86_32)) return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); @@ -173,7 +159,7 @@ static inline int copy_kernel_to_fxregs_err(struct fxregs_state *fx) return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline int copy_user_to_fxregs(struct fxregs_state __user *fx) +static inline int fxrstor_from_user_sigframe(struct fxregs_state __user *fx) { if (IS_ENABLED(CONFIG_X86_32)) return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); @@ -181,29 +167,21 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx) return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline void copy_kernel_to_fregs(struct fregs_state *fx) +static inline void frstor(struct fregs_state *fx) { kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline int copy_kernel_to_fregs_err(struct fregs_state *fx) +static inline int frstor_safe(struct fregs_state *fx) { return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline int copy_user_to_fregs(struct fregs_state __user *fx) +static inline int frstor_from_user_sigframe(struct fregs_state __user *fx) { return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); } -static inline void copy_fxregs_to_kernel(struct fpu *fpu) -{ - if (IS_ENABLED(CONFIG_X86_32)) - asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave)); - else - asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave)); -} - static inline void fxsave(struct fxregs_state *fx) { if (IS_ENABLED(CONFIG_X86_32)) @@ -219,16 +197,20 @@ static inline void fxsave(struct fxregs_state *fx) #define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f" #define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f" +/* + * After this @err contains 0 on success or the negated trap number when + * the operation raises an exception. For faults this results in -EFAULT. + */ #define XSTATE_OP(op, st, lmask, hmask, err) \ asm volatile("1:" op "\n\t" \ "xor %[err], %[err]\n" \ "2:\n\t" \ ".pushsection .fixup,\"ax\"\n\t" \ - "3: movl $-2,%[err]\n\t" \ + "3: negl %%eax\n\t" \ "jmp 2b\n\t" \ ".popsection\n\t" \ - _ASM_EXTABLE(1b, 3b) \ - : [err] "=r" (err) \ + _ASM_EXTABLE_FAULT(1b, 3b) \ + : [err] "=a" (err) \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "memory") @@ -280,9 +262,9 @@ static inline void fxsave(struct fxregs_state *fx) * This function is called only during boot time when x86 caps are not set * up and alternative can not be used yet. */ -static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate) +static inline void os_xrstor_booting(struct xregs_state *xstate) { - u64 mask = -1; + u64 mask = xfeatures_mask_fpstate(); u32 lmask = mask; u32 hmask = mask >> 32; int err; @@ -303,8 +285,11 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate) /* * Save processor xstate to xsave area. + * + * Uses either XSAVE or XSAVEOPT or XSAVES depending on the CPU features + * and command line options. The choice is permanent until the next reboot. */ -static inline void copy_xregs_to_kernel(struct xregs_state *xstate) +static inline void os_xsave(struct xregs_state *xstate) { u64 mask = xfeatures_mask_all; u32 lmask = mask; @@ -321,8 +306,10 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate) /* * Restore processor xstate from xsave area. + * + * Uses XRSTORS when XSAVES is used, XRSTOR otherwise. */ -static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) +static inline void os_xrstor(struct xregs_state *xstate, u64 mask) { u32 lmask = mask; u32 hmask = mask >> 32; @@ -340,9 +327,14 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) * backward compatibility for old applications which don't understand * compacted format of xsave area. */ -static inline int copy_xregs_to_user(struct xregs_state __user *buf) +static inline int xsave_to_user_sigframe(struct xregs_state __user *buf) { - u64 mask = xfeatures_mask_user(); + /* + * Include the features which are not xsaved/rstored by the kernel + * internally, e.g. PKRU. That's user space ABI and also required + * to allow the signal handler to modify PKRU. + */ + u64 mask = xfeatures_mask_uabi(); u32 lmask = mask; u32 hmask = mask >> 32; int err; @@ -365,7 +357,7 @@ static inline int copy_xregs_to_user(struct xregs_state __user *buf) /* * Restore xstate from user space xsave area. */ -static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask) +static inline int xrstor_from_user_sigframe(struct xregs_state __user *buf, u64 mask) { struct xregs_state *xstate = ((__force struct xregs_state *)buf); u32 lmask = mask; @@ -383,13 +375,13 @@ static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask) * Restore xstate from kernel space xsave area, return an error code instead of * an exception. */ -static inline int copy_kernel_to_xregs_err(struct xregs_state *xstate, u64 mask) +static inline int os_xrstor_safe(struct xregs_state *xstate, u64 mask) { u32 lmask = mask; u32 hmask = mask >> 32; int err; - if (static_cpu_has(X86_FEATURE_XSAVES)) + if (cpu_feature_enabled(X86_FEATURE_XSAVES)) XSTATE_OP(XRSTORS, xstate, lmask, hmask, err); else XSTATE_OP(XRSTOR, xstate, lmask, hmask, err); @@ -397,36 +389,11 @@ static inline int copy_kernel_to_xregs_err(struct xregs_state *xstate, u64 mask) return err; } -extern int copy_fpregs_to_fpstate(struct fpu *fpu); +extern void __restore_fpregs_from_fpstate(union fpregs_state *fpstate, u64 mask); -static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask) +static inline void restore_fpregs_from_fpstate(union fpregs_state *fpstate) { - if (use_xsave()) { - copy_kernel_to_xregs(&fpstate->xsave, mask); - } else { - if (use_fxsr()) - copy_kernel_to_fxregs(&fpstate->fxsave); - else - copy_kernel_to_fregs(&fpstate->fsave); - } -} - -static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate) -{ - /* - * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is - * pending. Clear the x87 state here by setting it to fixed values. - * "m" is a random variable that should be in L1. - */ - if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK))) { - asm volatile( - "fnclex\n\t" - "emms\n\t" - "fildl %P[addr]" /* set F?P to defined value */ - : : [addr] "m" (fpstate)); - } - - __copy_kernel_to_fpregs(fpstate, -1); + __restore_fpregs_from_fpstate(fpstate, xfeatures_mask_fpstate()); } extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size); @@ -485,10 +452,8 @@ static inline void fpregs_activate(struct fpu *fpu) trace_x86_fpu_regs_activated(fpu); } -/* - * Internal helper, do not use directly. Use switch_fpu_return() instead. - */ -static inline void __fpregs_load_activate(void) +/* Internal helper for switch_fpu_return() and signal frame setup */ +static inline void fpregs_restore_userregs(void) { struct fpu *fpu = ¤t->thread.fpu; int cpu = smp_processor_id(); @@ -497,7 +462,21 @@ static inline void __fpregs_load_activate(void) return; if (!fpregs_state_valid(fpu, cpu)) { - copy_kernel_to_fpregs(&fpu->state); + u64 mask; + + /* + * This restores _all_ xstate which has not been + * established yet. + * + * If PKRU is enabled, then the PKRU value is already + * correct because it was either set in switch_to() or in + * flush_thread(). So it is excluded because it might be + * not up to date in current->thread.fpu.xsave state. + */ + mask = xfeatures_mask_restore_user() | + xfeatures_mask_supervisor(); + __restore_fpregs_from_fpstate(&fpu->state, mask); + fpregs_activate(fpu); fpu->last_cpu = cpu; } @@ -529,12 +508,17 @@ static inline void __fpregs_load_activate(void) static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu) { if (static_cpu_has(X86_FEATURE_FPU) && !(current->flags & PF_KTHREAD)) { - if (!copy_fpregs_to_fpstate(old_fpu)) - old_fpu->last_cpu = -1; - else - old_fpu->last_cpu = cpu; + save_fpregs_to_fpstate(old_fpu); + /* + * The save operation preserved register state, so the + * fpu_fpregs_owner_ctx is still @old_fpu. Store the + * current CPU number in @old_fpu, so the next return + * to user space can avoid the FPU register restore + * when is returns on the same CPU and still owns the + * context. + */ + old_fpu->last_cpu = cpu; - /* But leave fpu_fpregs_owner_ctx! */ trace_x86_fpu_regs_deactivated(old_fpu); } } @@ -544,39 +528,13 @@ static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu) */ /* - * Load PKRU from the FPU context if available. Delay loading of the - * complete FPU state until the return to userland. + * Delay loading of the complete FPU state until the return to userland. + * PKRU is handled separately. */ static inline void switch_fpu_finish(struct fpu *new_fpu) { - u32 pkru_val = init_pkru_value; - struct pkru_state *pk; - - if (!static_cpu_has(X86_FEATURE_FPU)) - return; - - set_thread_flag(TIF_NEED_FPU_LOAD); - - if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) - return; - - /* - * PKRU state is switched eagerly because it needs to be valid before we - * return to userland e.g. for a copy_to_user() operation. - */ - if (!(current->flags & PF_KTHREAD)) { - /* - * If the PKRU bit in xsave.header.xfeatures is not set, - * then the PKRU component was in init state, which means - * XRSTOR will set PKRU to 0. If the bit is not set then - * get_xsave_addr() will return NULL because the PKRU value - * in memory is not valid. This means pkru_val has to be - * set to 0 and not to init_pkru_value. - */ - pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU); - pkru_val = pk ? pk->pkru : 0; - } - __write_pkru(pkru_val); + if (cpu_feature_enabled(X86_FEATURE_FPU)) + set_thread_flag(TIF_NEED_FPU_LOAD); } #endif /* _ASM_X86_FPU_INTERNAL_H */ diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h index 7fb516b6893a..8b6631dffefd 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -29,6 +29,8 @@ unsigned long fpu__alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx, unsigned long *size); +unsigned long fpu__get_fpstate_size(void); + extern void fpu__init_prepare_fx_sw_frame(void); #endif /* _ASM_X86_FPU_SIGNAL_H */ diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 47a92232d595..109dfcc75299 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -6,6 +6,7 @@ #include #include +#include #include /* Bit 63 of XCR0 is reserved for future expansion */ @@ -34,6 +35,14 @@ XFEATURE_MASK_BNDREGS | \ XFEATURE_MASK_BNDCSR) +/* + * Features which are restored when returning to user space. + * PKRU is not restored on return to user space because PKRU + * is switched eagerly in switch_to() and flush_thread() + */ +#define XFEATURE_MASK_USER_RESTORE \ + (XFEATURE_MASK_USER_SUPPORTED & ~XFEATURE_MASK_PKRU) + /* All currently supported supervisor features */ #define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID) @@ -42,21 +51,21 @@ * and its size may be huge. Saving/restoring such supervisor state components * at each context switch can cause high CPU and space overhead, which should * be avoided. Such supervisor state components should only be saved/restored - * on demand. The on-demand dynamic supervisor features are set in this mask. + * on demand. The on-demand supervisor features are set in this mask. * - * Unlike the existing supported supervisor features, a dynamic supervisor + * Unlike the existing supported supervisor features, an independent supervisor * feature does not allocate a buffer in task->fpu, and the corresponding * supervisor state component cannot be saved/restored at each context switch. * - * To support a dynamic supervisor feature, a developer should follow the + * To support an independent supervisor feature, a developer should follow the * dos and don'ts as below: * - Do dynamically allocate a buffer for the supervisor state component. * - Do manually invoke the XSAVES/XRSTORS instruction to save/restore the * state component to/from the buffer. - * - Don't set the bit corresponding to the dynamic supervisor feature in + * - Don't set the bit corresponding to the independent supervisor feature in * IA32_XSS at run time, since it has been set at boot time. */ -#define XFEATURE_MASK_DYNAMIC (XFEATURE_MASK_LBR) +#define XFEATURE_MASK_INDEPENDENT (XFEATURE_MASK_LBR) /* * Unsupported supervisor features. When a supervisor feature in this mask is @@ -66,7 +75,7 @@ /* All supervisor states including supported and unsupported states. */ #define XFEATURE_MASK_SUPERVISOR_ALL (XFEATURE_MASK_SUPERVISOR_SUPPORTED | \ - XFEATURE_MASK_DYNAMIC | \ + XFEATURE_MASK_INDEPENDENT | \ XFEATURE_MASK_SUPERVISOR_UNSUPPORTED) #ifdef CONFIG_X86_64 @@ -82,17 +91,42 @@ static inline u64 xfeatures_mask_supervisor(void) return xfeatures_mask_all & XFEATURE_MASK_SUPERVISOR_SUPPORTED; } -static inline u64 xfeatures_mask_user(void) +/* + * The xfeatures which are enabled in XCR0 and expected to be in ptrace + * buffers and signal frames. + */ +static inline u64 xfeatures_mask_uabi(void) { return xfeatures_mask_all & XFEATURE_MASK_USER_SUPPORTED; } -static inline u64 xfeatures_mask_dynamic(void) +/* + * The xfeatures which are restored by the kernel when returning to user + * mode. This is not necessarily the same as xfeatures_mask_uabi() as the + * kernel does not manage all XCR0 enabled features via xsave/xrstor as + * some of them have to be switched eagerly on context switch and exec(). + */ +static inline u64 xfeatures_mask_restore_user(void) +{ + return xfeatures_mask_all & XFEATURE_MASK_USER_RESTORE; +} + +/* + * Like xfeatures_mask_restore_user() but additionally restors the + * supported supervisor states. + */ +static inline u64 xfeatures_mask_fpstate(void) +{ + return xfeatures_mask_all & \ + (XFEATURE_MASK_USER_RESTORE | XFEATURE_MASK_SUPERVISOR_SUPPORTED); +} + +static inline u64 xfeatures_mask_independent(void) { if (!boot_cpu_has(X86_FEATURE_ARCH_LBR)) - return XFEATURE_MASK_DYNAMIC & ~XFEATURE_MASK_LBR; + return XFEATURE_MASK_INDEPENDENT & ~XFEATURE_MASK_LBR; - return XFEATURE_MASK_DYNAMIC; + return XFEATURE_MASK_INDEPENDENT; } extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; @@ -101,19 +135,21 @@ extern void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask); void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); -const void *get_xsave_field_ptr(int xfeature_nr); -int using_compacted_format(void); int xfeature_size(int xfeature_nr); +int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf); +int copy_sigframe_from_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf); + +void xsaves(struct xregs_state *xsave, u64 mask); +void xrstors(struct xregs_state *xsave, u64 mask); + +enum xstate_copy_mode { + XSTATE_COPY_FP, + XSTATE_COPY_FX, + XSTATE_COPY_XSAVE, +}; + struct membuf; -void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave); -int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf); -int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf); -void copy_supervisor_to_kernel(struct xregs_state *xsave); -void copy_dynamic_supervisor_to_kernel(struct xregs_state *xstate, u64 mask); -void copy_kernel_to_dynamic_supervisor(struct xregs_state *xstate, u64 mask); - - -/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */ -int validate_user_xstate_header(const struct xstate_header *hdr); +void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, + enum xstate_copy_mode mode); #endif diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index b1099f2d9800..448cd01eb3ec 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -23,7 +23,7 @@ #ifndef __ASSEMBLY__ #include -#include +#include #include #include @@ -126,35 +126,6 @@ static inline int pte_dirty(pte_t pte) return pte_flags(pte) & _PAGE_DIRTY; } - -static inline u32 read_pkru(void) -{ - if (boot_cpu_has(X86_FEATURE_OSPKE)) - return rdpkru(); - return 0; -} - -static inline void write_pkru(u32 pkru) -{ - struct pkru_state *pk; - - if (!boot_cpu_has(X86_FEATURE_OSPKE)) - return; - - pk = get_xsave_addr(¤t->thread.fpu.state.xsave, XFEATURE_PKRU); - - /* - * The PKRU value in xstate needs to be in sync with the value that is - * written to the CPU. The FPU restore on return to userland would - * otherwise load the previous value again. - */ - fpregs_lock(); - if (pk) - pk->pkru = pkru; - __write_pkru(pkru); - fpregs_unlock(); -} - static inline int pte_young(pte_t pte) { return pte_flags(pte) & _PAGE_ACCESSED; @@ -865,9 +836,9 @@ static inline int pud_present(pud_t pud) return pud_flags(pud) & _PAGE_PRESENT; } -static inline unsigned long pud_page_vaddr(pud_t pud) +static inline pmd_t *pud_pgtable(pud_t pud) { - return (unsigned long)__va(pud_val(pud) & pud_pfn_mask(pud)); + return (pmd_t *)__va(pud_val(pud) & pud_pfn_mask(pud)); } /* @@ -906,9 +877,9 @@ static inline int p4d_present(p4d_t p4d) return p4d_flags(p4d) & _PAGE_PRESENT; } -static inline unsigned long p4d_page_vaddr(p4d_t p4d) +static inline pud_t *p4d_pgtable(p4d_t p4d) { - return (unsigned long)__va(p4d_val(p4d) & p4d_pfn_mask(p4d)); + return (pud_t *)__va(p4d_val(p4d) & p4d_pfn_mask(p4d)); } /* @@ -1360,32 +1331,6 @@ static inline pmd_t pmd_swp_clear_uffd_wp(pmd_t pmd) } #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */ -#define PKRU_AD_BIT 0x1 -#define PKRU_WD_BIT 0x2 -#define PKRU_BITS_PER_PKEY 2 - -#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS -extern u32 init_pkru_value; -#else -#define init_pkru_value 0 -#endif - -static inline bool __pkru_allows_read(u32 pkru, u16 pkey) -{ - int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY; - return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); -} - -static inline bool __pkru_allows_write(u32 pkru, u16 pkey) -{ - int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY; - /* - * Access-disable disables writes too so we need to check - * both bits here. - */ - return !(pkru & ((PKRU_AD_BIT|PKRU_WD_BIT) << pkru_pkey_bits)); -} - static inline u16 pte_flags_pkey(unsigned long pte_flags) { #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index 2ff9b98812b7..5c7bcaa79623 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h @@ -9,14 +9,14 @@ * will be necessary to ensure that the types that store key * numbers and masks have sufficient capacity. */ -#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) +#define arch_max_pkey() (cpu_feature_enabled(X86_FEATURE_OSPKE) ? 16 : 1) extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, unsigned long init_val); static inline bool arch_pkeys_enabled(void) { - return boot_cpu_has(X86_FEATURE_OSPKE); + return cpu_feature_enabled(X86_FEATURE_OSPKE); } /* @@ -26,7 +26,7 @@ static inline bool arch_pkeys_enabled(void) extern int __execute_only_pkey(struct mm_struct *mm); static inline int execute_only_pkey(struct mm_struct *mm) { - if (!boot_cpu_has(X86_FEATURE_OSPKE)) + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) return ARCH_DEFAULT_PKEY; return __execute_only_pkey(mm); @@ -37,7 +37,7 @@ extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma, static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey) { - if (!boot_cpu_has(X86_FEATURE_OSPKE)) + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) return 0; return __arch_override_mprotect_pkey(vma, prot, pkey); @@ -124,7 +124,6 @@ extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, unsigned long init_val); extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, unsigned long init_val); -extern void copy_init_pkru_to_fpregs(void); static inline int vma_pkey(struct vm_area_struct *vma) { diff --git a/arch/x86/include/asm/pkru.h b/arch/x86/include/asm/pkru.h new file mode 100644 index 000000000000..ccc539faa5bb --- /dev/null +++ b/arch/x86/include/asm/pkru.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_PKRU_H +#define _ASM_X86_PKRU_H + +#include + +#define PKRU_AD_BIT 0x1 +#define PKRU_WD_BIT 0x2 +#define PKRU_BITS_PER_PKEY 2 + +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +extern u32 init_pkru_value; +#define pkru_get_init_value() READ_ONCE(init_pkru_value) +#else +#define init_pkru_value 0 +#define pkru_get_init_value() 0 +#endif + +static inline bool __pkru_allows_read(u32 pkru, u16 pkey) +{ + int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY; + return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); +} + +static inline bool __pkru_allows_write(u32 pkru, u16 pkey) +{ + int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY; + /* + * Access-disable disables writes too so we need to check + * both bits here. + */ + return !(pkru & ((PKRU_AD_BIT|PKRU_WD_BIT) << pkru_pkey_bits)); +} + +static inline u32 read_pkru(void) +{ + if (cpu_feature_enabled(X86_FEATURE_OSPKE)) + return rdpkru(); + return 0; +} + +static inline void write_pkru(u32 pkru) +{ + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) + return; + /* + * WRPKRU is relatively expensive compared to RDPKRU. + * Avoid WRPKRU when it would not change the value. + */ + if (pkru != rdpkru()) + wrpkru(pkru); +} + +static inline void pkru_write_default(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) + return; + + wrpkru(pkru_get_init_value()); +} + +#endif diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 364d0e42e280..f3020c54e2cb 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -518,6 +518,15 @@ struct thread_struct { unsigned int sig_on_uaccess_err:1; + /* + * Protection Keys Register for Userspace. Loaded immediately on + * context switch. Store it in thread_struct to avoid a lookup in + * the tasks's FPU xstate buffer. This value is only valid when a + * task is scheduled out. For 'current' the authoritative source of + * PKRU is the hardware itself. + */ + u32 pkru; + /* Floating point and extended processor state */ struct fpu fpu; /* diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h index 84eab2724875..5b1ed650b124 100644 --- a/arch/x86/include/asm/sigframe.h +++ b/arch/x86/include/asm/sigframe.h @@ -85,4 +85,6 @@ struct rt_sigframe_x32 { #endif /* CONFIG_X86_64 */ +void __init init_sigframe_size(void); + #endif /* _ASM_X86_SIGFRAME_H */ diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index 2acd6cb62328..f3fbb84ff8a7 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -104,25 +104,13 @@ static inline void wrpkru(u32 pkru) : : "a" (pkru), "c"(ecx), "d"(edx)); } -static inline void __write_pkru(u32 pkru) -{ - /* - * WRPKRU is relatively expensive compared to RDPKRU. - * Avoid WRPKRU when it would not change the value. - */ - if (pkru == rdpkru()) - return; - - wrpkru(pkru); -} - #else static inline u32 rdpkru(void) { return 0; } -static inline void __write_pkru(u32 pkru) +static inline void wrpkru(u32 pkru) { } #endif diff --git a/arch/x86/include/uapi/asm/auxvec.h b/arch/x86/include/uapi/asm/auxvec.h index 580e3c567046..6beb55bbefa4 100644 --- a/arch/x86/include/uapi/asm/auxvec.h +++ b/arch/x86/include/uapi/asm/auxvec.h @@ -12,9 +12,9 @@ /* entries in ARCH_DLINFO: */ #if defined(CONFIG_IA32_EMULATION) || !defined(CONFIG_X86_64) -# define AT_VECTOR_SIZE_ARCH 2 +# define AT_VECTOR_SIZE_ARCH 3 #else /* else it's non-compat x86-64 */ -# define AT_VECTOR_SIZE_ARCH 1 +# define AT_VECTOR_SIZE_ARCH 2 #endif #endif /* _ASM_X86_AUXVEC_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a99d00393206..64b805bd6a54 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "cpu.h" @@ -465,27 +466,22 @@ static bool pku_disabled; static __always_inline void setup_pku(struct cpuinfo_x86 *c) { - struct pkru_state *pk; + if (c == &boot_cpu_data) { + if (pku_disabled || !cpu_feature_enabled(X86_FEATURE_PKU)) + return; + /* + * Setting CR4.PKE will cause the X86_FEATURE_OSPKE cpuid + * bit to be set. Enforce it. + */ + setup_force_cpu_cap(X86_FEATURE_OSPKE); - /* check the boot processor, plus compile options for PKU: */ - if (!cpu_feature_enabled(X86_FEATURE_PKU)) - return; - /* checks the actual processor's cpuid bits: */ - if (!cpu_has(c, X86_FEATURE_PKU)) - return; - if (pku_disabled) + } else if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) { return; + } cr4_set_bits(X86_CR4_PKE); - pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU); - if (pk) - pk->pkru = init_pkru_value; - /* - * Setting X86_CR4_PKE will cause the X86_FEATURE_OSPKE - * cpuid bit to be set. We need to ensure that we - * update that bit in this CPU's "cpu_info". - */ - set_cpu_cap(c, X86_FEATURE_OSPKE); + /* Load the default PKRU value */ + pkru_write_default(); } #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS @@ -1332,6 +1328,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) fpu__init_system(c); + init_sigframe_size(); + #ifdef CONFIG_X86_32 /* * Regardless of whether PCID is enumerated, the SDM says @@ -1717,9 +1715,8 @@ void print_cpu_info(struct cpuinfo_x86 *c) } /* - * clearcpuid= was already parsed in fpu__init_parse_early_param. - * But we need to keep a dummy __setup around otherwise it would - * show up as an environment variable for init. + * clearcpuid= was already parsed in cpu_parse_early_param(). This dummy + * function prevents it from becoming an environment variable for init. */ static __init int setup_clearcpuid(char *arg) { diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 299c20f0a38b..ea4fe192189d 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -69,7 +69,7 @@ static void printk_stack_address(unsigned long address, int reliable, const char *log_lvl) { touch_nmi_watchdog(); - printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); + printk("%s %s%pBb\n", log_lvl, reliable ? "" : "? ", (void *)address); } static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src, diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 571220ac8bea..7ada7bd03a32 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -23,7 +23,7 @@ * Represents the initial FPU state. It's mostly (but not completely) zeroes, * depending on the FPU hardware format: */ -union fpregs_state init_fpstate __read_mostly; +union fpregs_state init_fpstate __ro_after_init; /* * Track whether the kernel is using the FPU state @@ -83,19 +83,23 @@ bool irq_fpu_usable(void) EXPORT_SYMBOL(irq_fpu_usable); /* - * These must be called with preempt disabled. Returns - * 'true' if the FPU state is still intact and we can - * keep registers active. + * Save the FPU register state in fpu->state. The register state is + * preserved. * - * The legacy FNSAVE instruction cleared all FPU state - * unconditionally, so registers are essentially destroyed. - * Modern FPU state can be kept in registers, if there are - * no pending FP exceptions. + * Must be called with fpregs_lock() held. + * + * The legacy FNSAVE instruction clears all FPU state unconditionally, so + * register state has to be reloaded. That might be a pointless exercise + * when the FPU is going to be used by another task right after that. But + * this only affects 20+ years old 32bit systems and avoids conditionals all + * over the place. + * + * FXSAVE and all XSAVE variants preserve the FPU register state. */ -int copy_fpregs_to_fpstate(struct fpu *fpu) +void save_fpregs_to_fpstate(struct fpu *fpu) { if (likely(use_xsave())) { - copy_xregs_to_kernel(&fpu->state.xsave); + os_xsave(&fpu->state.xsave); /* * AVX512 state is tracked here because its use is @@ -103,23 +107,49 @@ int copy_fpregs_to_fpstate(struct fpu *fpu) */ if (fpu->state.xsave.header.xfeatures & XFEATURE_MASK_AVX512) fpu->avx512_timestamp = jiffies; - return 1; + return; } if (likely(use_fxsr())) { - copy_fxregs_to_kernel(fpu); - return 1; + fxsave(&fpu->state.fxsave); + return; } /* * Legacy FPU register saving, FNSAVE always clears FPU registers, - * so we have to mark them inactive: + * so we have to reload them from the memory state. */ asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave)); - - return 0; + frstor(&fpu->state.fsave); } -EXPORT_SYMBOL(copy_fpregs_to_fpstate); +EXPORT_SYMBOL(save_fpregs_to_fpstate); + +void __restore_fpregs_from_fpstate(union fpregs_state *fpstate, u64 mask) +{ + /* + * AMD K7/K8 and later CPUs up to Zen don't save/restore + * FDP/FIP/FOP unless an exception is pending. Clear the x87 state + * here by setting it to fixed values. "m" is a random variable + * that should be in L1. + */ + if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK))) { + asm volatile( + "fnclex\n\t" + "emms\n\t" + "fildl %P[addr]" /* set F?P to defined value */ + : : [addr] "m" (fpstate)); + } + + if (use_xsave()) { + os_xrstor(&fpstate->xsave, mask); + } else { + if (use_fxsr()) + fxrstor(&fpstate->fxsave); + else + frstor(&fpstate->fsave); + } +} +EXPORT_SYMBOL_GPL(__restore_fpregs_from_fpstate); void kernel_fpu_begin_mask(unsigned int kfpu_mask) { @@ -133,11 +163,7 @@ void kernel_fpu_begin_mask(unsigned int kfpu_mask) if (!(current->flags & PF_KTHREAD) && !test_thread_flag(TIF_NEED_FPU_LOAD)) { set_thread_flag(TIF_NEED_FPU_LOAD); - /* - * Ignore return value -- we don't care if reg state - * is clobbered. - */ - copy_fpregs_to_fpstate(¤t->thread.fpu); + save_fpregs_to_fpstate(¤t->thread.fpu); } __cpu_invalidate_fpregs_state(); @@ -160,27 +186,38 @@ void kernel_fpu_end(void) EXPORT_SYMBOL_GPL(kernel_fpu_end); /* - * Save the FPU state (mark it for reload if necessary): - * - * This only ever gets called for the current task. + * Sync the FPU register state to current's memory register state when the + * current task owns the FPU. The hardware register state is preserved. */ -void fpu__save(struct fpu *fpu) +void fpu_sync_fpstate(struct fpu *fpu) { WARN_ON_FPU(fpu != ¤t->thread.fpu); fpregs_lock(); trace_x86_fpu_before_save(fpu); - if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { - if (!copy_fpregs_to_fpstate(fpu)) { - copy_kernel_to_fpregs(&fpu->state); - } - } + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) + save_fpregs_to_fpstate(fpu); trace_x86_fpu_after_save(fpu); fpregs_unlock(); } +static inline void fpstate_init_xstate(struct xregs_state *xsave) +{ + /* + * XRSTORS requires these bits set in xcomp_bv, or it will + * trigger #GP: + */ + xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all; +} + +static inline void fpstate_init_fxstate(struct fxregs_state *fx) +{ + fx->cwd = 0x37f; + fx->mxcsr = MXCSR_DEFAULT; +} + /* * Legacy x87 fpstate state init: */ @@ -210,18 +247,18 @@ void fpstate_init(union fpregs_state *state) } EXPORT_SYMBOL_GPL(fpstate_init); -int fpu__copy(struct task_struct *dst, struct task_struct *src) +/* Clone current's FPU state on fork */ +int fpu_clone(struct task_struct *dst) { + struct fpu *src_fpu = ¤t->thread.fpu; struct fpu *dst_fpu = &dst->thread.fpu; - struct fpu *src_fpu = &src->thread.fpu; + /* The new task's FPU state cannot be valid in the hardware. */ dst_fpu->last_cpu = -1; - if (!static_cpu_has(X86_FEATURE_FPU)) + if (!cpu_feature_enabled(X86_FEATURE_FPU)) return 0; - WARN_ON_FPU(src_fpu != ¤t->thread.fpu); - /* * Don't let 'init optimized' areas of the XSAVE area * leak into the child task: @@ -229,20 +266,16 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size); /* - * If the FPU registers are not current just memcpy() the state. - * Otherwise save current FPU registers directly into the child's FPU - * context, without any memory-to-memory copying. - * - * ( The function 'fails' in the FNSAVE case, which destroys - * register contents so we have to load them back. ) + * If the FPU registers are not owned by current just memcpy() the + * state. Otherwise save the FPU registers directly into the + * child's FPU context, without any memory-to-memory copying. */ fpregs_lock(); if (test_thread_flag(TIF_NEED_FPU_LOAD)) memcpy(&dst_fpu->state, &src_fpu->state, fpu_kernel_xstate_size); - else if (!copy_fpregs_to_fpstate(dst_fpu)) - copy_kernel_to_fpregs(&dst_fpu->state); - + else + save_fpregs_to_fpstate(dst_fpu); fpregs_unlock(); set_tsk_thread_flag(dst, TIF_NEED_FPU_LOAD); @@ -253,63 +286,6 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) return 0; } -/* - * Activate the current task's in-memory FPU context, - * if it has not been used before: - */ -static void fpu__initialize(struct fpu *fpu) -{ - WARN_ON_FPU(fpu != ¤t->thread.fpu); - - set_thread_flag(TIF_NEED_FPU_LOAD); - fpstate_init(&fpu->state); - trace_x86_fpu_init_state(fpu); -} - -/* - * This function must be called before we read a task's fpstate. - * - * There's two cases where this gets called: - * - * - for the current task (when coredumping), in which case we have - * to save the latest FPU registers into the fpstate, - * - * - or it's called for stopped tasks (ptrace), in which case the - * registers were already saved by the context-switch code when - * the task scheduled out. - * - * If the task has used the FPU before then save it. - */ -void fpu__prepare_read(struct fpu *fpu) -{ - if (fpu == ¤t->thread.fpu) - fpu__save(fpu); -} - -/* - * This function must be called before we write a task's fpstate. - * - * Invalidate any cached FPU registers. - * - * After this function call, after registers in the fpstate are - * modified and the child task has woken up, the child task will - * restore the modified FPU state from the modified context. If we - * didn't clear its cached status here then the cached in-registers - * state pending on its former CPU could be restored, corrupting - * the modifications. - */ -void fpu__prepare_write(struct fpu *fpu) -{ - /* - * Only stopped child tasks can be used to modify the FPU - * state in the fpstate buffer: - */ - WARN_ON_FPU(fpu == ¤t->thread.fpu); - - /* Invalidate any cached state: */ - __fpu_invalidate_fpregs_state(fpu); -} - /* * Drops current FPU state: deactivates the fpregs and * the fpstate. NOTE: it still leaves previous contents @@ -340,61 +316,97 @@ void fpu__drop(struct fpu *fpu) * Clear FPU registers by setting them up from the init fpstate. * Caller must do fpregs_[un]lock() around it. */ -static inline void copy_init_fpstate_to_fpregs(u64 features_mask) +static inline void restore_fpregs_from_init_fpstate(u64 features_mask) { if (use_xsave()) - copy_kernel_to_xregs(&init_fpstate.xsave, features_mask); - else if (static_cpu_has(X86_FEATURE_FXSR)) - copy_kernel_to_fxregs(&init_fpstate.fxsave); + os_xrstor(&init_fpstate.xsave, features_mask); + else if (use_fxsr()) + fxrstor(&init_fpstate.fxsave); else - copy_kernel_to_fregs(&init_fpstate.fsave); + frstor(&init_fpstate.fsave); - if (boot_cpu_has(X86_FEATURE_OSPKE)) - copy_init_pkru_to_fpregs(); + pkru_write_default(); +} + +static inline unsigned int init_fpstate_copy_size(void) +{ + if (!use_xsave()) + return fpu_kernel_xstate_size; + + /* XSAVE(S) just needs the legacy and the xstate header part */ + return sizeof(init_fpstate.xsave); } /* - * Clear the FPU state back to init state. - * - * Called by sys_execve(), by the signal handler code and by various - * error paths. + * Reset current->fpu memory state to the init values. */ -static void fpu__clear(struct fpu *fpu, bool user_only) +static void fpu_reset_fpstate(void) +{ + struct fpu *fpu = ¤t->thread.fpu; + + fpregs_lock(); + fpu__drop(fpu); + /* + * This does not change the actual hardware registers. It just + * resets the memory image and sets TIF_NEED_FPU_LOAD so a + * subsequent return to usermode will reload the registers from the + * task's memory image. + * + * Do not use fpstate_init() here. Just copy init_fpstate which has + * the correct content already except for PKRU. + * + * PKRU handling does not rely on the xstate when restoring for + * user space as PKRU is eagerly written in switch_to() and + * flush_thread(). + */ + memcpy(&fpu->state, &init_fpstate, init_fpstate_copy_size()); + set_thread_flag(TIF_NEED_FPU_LOAD); + fpregs_unlock(); +} + +/* + * Reset current's user FPU states to the init states. current's + * supervisor states, if any, are not modified by this function. The + * caller guarantees that the XSTATE header in memory is intact. + */ +void fpu__clear_user_states(struct fpu *fpu) { WARN_ON_FPU(fpu != ¤t->thread.fpu); - if (!static_cpu_has(X86_FEATURE_FPU)) { - fpu__drop(fpu); - fpu__initialize(fpu); + fpregs_lock(); + if (!cpu_feature_enabled(X86_FEATURE_FPU)) { + fpu_reset_fpstate(); + fpregs_unlock(); return; } - fpregs_lock(); - - if (user_only) { - if (!fpregs_state_valid(fpu, smp_processor_id()) && - xfeatures_mask_supervisor()) - copy_kernel_to_xregs(&fpu->state.xsave, - xfeatures_mask_supervisor()); - copy_init_fpstate_to_fpregs(xfeatures_mask_user()); - } else { - copy_init_fpstate_to_fpregs(xfeatures_mask_all); + /* + * Ensure that current's supervisor states are loaded into their + * corresponding registers. + */ + if (xfeatures_mask_supervisor() && + !fpregs_state_valid(fpu, smp_processor_id())) { + os_xrstor(&fpu->state.xsave, xfeatures_mask_supervisor()); } + /* Reset user states in registers. */ + restore_fpregs_from_init_fpstate(xfeatures_mask_restore_user()); + + /* + * Now all FPU registers have their desired values. Inform the FPU + * state machine that current's FPU registers are in the hardware + * registers. The memory image does not need to be updated because + * any operation relying on it has to save the registers first when + * current's FPU is marked active. + */ fpregs_mark_activate(); fpregs_unlock(); } -void fpu__clear_user_states(struct fpu *fpu) +void fpu_flush_thread(void) { - fpu__clear(fpu, true); + fpu_reset_fpstate(); } - -void fpu__clear_all(struct fpu *fpu) -{ - fpu__clear(fpu, false); -} - /* * Load FPU context before returning to userspace. */ @@ -403,7 +415,7 @@ void switch_fpu_return(void) if (!static_cpu_has(X86_FEATURE_FPU)) return; - __fpregs_load_activate(); + fpregs_restore_userregs(); } EXPORT_SYMBOL_GPL(switch_fpu_return); diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 701f196d7c68..64e29927cc32 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -89,7 +89,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) /* * Boot time FPU feature detection code: */ -unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; +unsigned int mxcsr_feature_mask __ro_after_init = 0xffffffffu; EXPORT_SYMBOL_GPL(mxcsr_feature_mask); static void __init fpu__init_system_mxcsr(void) @@ -135,7 +135,7 @@ static void __init fpu__init_system_generic(void) * This is inherent to the XSAVE architecture which puts all state * components into a single, continuous memory block: */ -unsigned int fpu_kernel_xstate_size; +unsigned int fpu_kernel_xstate_size __ro_after_init; EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size); /* Get alignment of the TYPE. */ @@ -216,17 +216,6 @@ static void __init fpu__init_system_xstate_size_legacy(void) fpu_user_xstate_size = fpu_kernel_xstate_size; } -/* - * Find supported xfeatures based on cpu features and command-line input. - * This must be called after fpu__init_parse_early_param() is called and - * xfeatures_mask is enumerated. - */ -u64 __init fpu__get_supported_xfeatures_mask(void) -{ - return XFEATURE_MASK_USER_SUPPORTED | - XFEATURE_MASK_SUPERVISOR_SUPPORTED; -} - /* Legacy code to initialize eager fpu mode. */ static void __init fpu__init_system_ctx_switch(void) { diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index c413756ba89f..66ed317ebc0d 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -2,11 +2,13 @@ /* * FPU register's regset abstraction, for ptrace, core dumps, etc. */ +#include +#include + #include #include #include #include -#include /* * The xstateregs_active() routine is the same as the regset_fpregs_active() routine, @@ -26,18 +28,58 @@ int regset_xregset_fpregs_active(struct task_struct *target, const struct user_r return 0; } +/* + * The regset get() functions are invoked from: + * + * - coredump to dump the current task's fpstate. If the current task + * owns the FPU then the memory state has to be synchronized and the + * FPU register state preserved. Otherwise fpstate is already in sync. + * + * - ptrace to dump fpstate of a stopped task, in which case the registers + * have already been saved to fpstate on context switch. + */ +static void sync_fpstate(struct fpu *fpu) +{ + if (fpu == ¤t->thread.fpu) + fpu_sync_fpstate(fpu); +} + +/* + * Invalidate cached FPU registers before modifying the stopped target + * task's fpstate. + * + * This forces the target task on resume to restore the FPU registers from + * modified fpstate. Otherwise the task might skip the restore and operate + * with the cached FPU registers which discards the modifications. + */ +static void fpu_force_restore(struct fpu *fpu) +{ + /* + * Only stopped child tasks can be used to modify the FPU + * state in the fpstate buffer: + */ + WARN_ON_FPU(fpu == ¤t->thread.fpu); + + __fpu_invalidate_fpregs_state(fpu); +} + int xfpregs_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { struct fpu *fpu = &target->thread.fpu; - if (!boot_cpu_has(X86_FEATURE_FXSR)) + if (!cpu_feature_enabled(X86_FEATURE_FXSR)) return -ENODEV; - fpu__prepare_read(fpu); - fpstate_sanitize_xstate(fpu); + sync_fpstate(fpu); - return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state)); + if (!use_xsave()) { + return membuf_write(&to, &fpu->state.fxsave, + sizeof(fpu->state.fxsave)); + } + + copy_xstate_to_uabi_buf(to, target, XSTATE_COPY_FX); + return 0; } int xfpregs_set(struct task_struct *target, const struct user_regset *regset, @@ -45,62 +87,52 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, const void *kbuf, const void __user *ubuf) { struct fpu *fpu = &target->thread.fpu; + struct user32_fxsr_struct newstate; int ret; - if (!boot_cpu_has(X86_FEATURE_FXSR)) + BUILD_BUG_ON(sizeof(newstate) != sizeof(struct fxregs_state)); + + if (!cpu_feature_enabled(X86_FEATURE_FXSR)) return -ENODEV; - fpu__prepare_write(fpu); - fpstate_sanitize_xstate(fpu); + /* No funny business with partial or oversized writes is permitted. */ + if (pos != 0 || count != sizeof(newstate)) + return -EINVAL; - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fxsave, 0, -1); + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1); + if (ret) + return ret; - /* - * mxcsr reserved bits must be masked to zero for security reasons. - */ - fpu->state.fxsave.mxcsr &= mxcsr_feature_mask; + /* Do not allow an invalid MXCSR value. */ + if (newstate.mxcsr & ~mxcsr_feature_mask) + return -EINVAL; - /* - * update the header bits in the xsave header, indicating the - * presence of FP and SSE state. - */ - if (boot_cpu_has(X86_FEATURE_XSAVE)) + fpu_force_restore(fpu); + + /* Copy the state */ + memcpy(&fpu->state.fxsave, &newstate, sizeof(newstate)); + + /* Clear xmm8..15 */ + BUILD_BUG_ON(sizeof(fpu->state.fxsave.xmm_space) != 16 * 16); + memset(&fpu->state.fxsave.xmm_space[8], 0, 8 * 16); + + /* Mark FP and SSE as in use when XSAVE is enabled */ + if (use_xsave()) fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE; - return ret; + return 0; } int xstateregs_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { - struct fpu *fpu = &target->thread.fpu; - struct xregs_state *xsave; - - if (!boot_cpu_has(X86_FEATURE_XSAVE)) + if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) return -ENODEV; - xsave = &fpu->state.xsave; + sync_fpstate(&target->thread.fpu); - fpu__prepare_read(fpu); - - if (using_compacted_format()) { - copy_xstate_to_kernel(to, xsave); - return 0; - } else { - fpstate_sanitize_xstate(fpu); - /* - * Copy the 48 bytes defined by the software into the xsave - * area in the thread struct, so that we can copy the whole - * area to user using one user_regset_copyout(). - */ - memcpy(&xsave->i387.sw_reserved, xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); - - /* - * Copy the xstate memory layout. - */ - return membuf_write(&to, xsave, fpu_user_xstate_size); - } + copy_xstate_to_uabi_buf(to, target, XSTATE_COPY_XSAVE); + return 0; } int xstateregs_set(struct task_struct *target, const struct user_regset *regset, @@ -108,44 +140,34 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, const void *kbuf, const void __user *ubuf) { struct fpu *fpu = &target->thread.fpu; - struct xregs_state *xsave; + struct xregs_state *tmpbuf = NULL; int ret; - if (!boot_cpu_has(X86_FEATURE_XSAVE)) + if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) return -ENODEV; /* * A whole standard-format XSAVE buffer is needed: */ - if ((pos != 0) || (count < fpu_user_xstate_size)) + if (pos != 0 || count != fpu_user_xstate_size) return -EFAULT; - xsave = &fpu->state.xsave; + if (!kbuf) { + tmpbuf = vmalloc(count); + if (!tmpbuf) + return -ENOMEM; - fpu__prepare_write(fpu); - - if (using_compacted_format()) { - if (kbuf) - ret = copy_kernel_to_xstate(xsave, kbuf); - else - ret = copy_user_to_xstate(xsave, ubuf); - } else { - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); - if (!ret) - ret = validate_user_xstate_header(&xsave->header); + if (copy_from_user(tmpbuf, ubuf, count)) { + ret = -EFAULT; + goto out; + } } - /* - * mxcsr reserved bits must be masked to zero for security reasons. - */ - xsave->i387.mxcsr &= mxcsr_feature_mask; - - /* - * In case of failure, mark all states as init: - */ - if (ret) - fpstate_init(&fpu->state); + fpu_force_restore(fpu); + ret = copy_uabi_from_kernel_to_xstate(&fpu->state.xsave, kbuf ?: tmpbuf); +out: + vfree(tmpbuf); return ret; } @@ -221,10 +243,10 @@ static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave) * FXSR floating point environment conversions. */ -void -convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) +static void __convert_from_fxsr(struct user_i387_ia32_struct *env, + struct task_struct *tsk, + struct fxregs_state *fxsave) { - struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; int i; @@ -258,6 +280,12 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) memcpy(&to[i], &from[i], sizeof(to[0])); } +void +convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) +{ + __convert_from_fxsr(env, tsk, &tsk->thread.fpu.state.fxsave); +} + void convert_to_fxsr(struct fxregs_state *fxsave, const struct user_i387_ia32_struct *env) @@ -290,25 +318,29 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, { struct fpu *fpu = &target->thread.fpu; struct user_i387_ia32_struct env; + struct fxregs_state fxsave, *fx; - fpu__prepare_read(fpu); + sync_fpstate(fpu); - if (!boot_cpu_has(X86_FEATURE_FPU)) + if (!cpu_feature_enabled(X86_FEATURE_FPU)) return fpregs_soft_get(target, regset, to); - if (!boot_cpu_has(X86_FEATURE_FXSR)) { + if (!cpu_feature_enabled(X86_FEATURE_FXSR)) { return membuf_write(&to, &fpu->state.fsave, sizeof(struct fregs_state)); } - fpstate_sanitize_xstate(fpu); + if (use_xsave()) { + struct membuf mb = { .p = &fxsave, .left = sizeof(fxsave) }; - if (to.left == sizeof(env)) { - convert_from_fxsr(to.p, target); - return 0; + /* Handle init state optimized xstate correctly */ + copy_xstate_to_uabi_buf(mb, target, XSTATE_COPY_FP); + fx = &fxsave; + } else { + fx = &fpu->state.fxsave; } - convert_from_fxsr(&env, target); + __convert_from_fxsr(&env, target, fx); return membuf_write(&to, &env, sizeof(env)); } @@ -320,31 +352,32 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, struct user_i387_ia32_struct env; int ret; - fpu__prepare_write(fpu); - fpstate_sanitize_xstate(fpu); + /* No funny business with partial or oversized writes is permitted. */ + if (pos != 0 || count != sizeof(struct user_i387_ia32_struct)) + return -EINVAL; - if (!boot_cpu_has(X86_FEATURE_FPU)) + if (!cpu_feature_enabled(X86_FEATURE_FPU)) return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); - if (!boot_cpu_has(X86_FEATURE_FXSR)) - return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fsave, 0, - -1); - - if (pos > 0 || count < sizeof(env)) - convert_from_fxsr(&env, target); - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); - if (!ret) - convert_to_fxsr(&target->thread.fpu.state.fxsave, &env); + if (ret) + return ret; + + fpu_force_restore(fpu); + + if (cpu_feature_enabled(X86_FEATURE_FXSR)) + convert_to_fxsr(&fpu->state.fxsave, &env); + else + memcpy(&fpu->state.fsave, &env, sizeof(env)); /* - * update the header bit in the xsave header, indicating the + * Update the header bit in the xsave header, indicating the * presence of FP. */ - if (boot_cpu_has(X86_FEATURE_XSAVE)) + if (cpu_feature_enabled(X86_FEATURE_XSAVE)) fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FP; - return ret; + + return 0; } #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index b7b92cdf3add..445c57c9c539 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -15,29 +15,30 @@ #include #include -static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; +static struct _fpx_sw_bytes fx_sw_reserved __ro_after_init; +static struct _fpx_sw_bytes fx_sw_reserved_ia32 __ro_after_init; /* * Check for the presence of extended state information in the * user fpstate pointer in the sigcontext. */ -static inline int check_for_xstate(struct fxregs_state __user *buf, - void __user *fpstate, - struct _fpx_sw_bytes *fx_sw) +static inline int check_xstate_in_sigframe(struct fxregs_state __user *fxbuf, + struct _fpx_sw_bytes *fx_sw) { int min_xstate_size = sizeof(struct fxregs_state) + sizeof(struct xstate_header); + void __user *fpstate = fxbuf; unsigned int magic2; - if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw))) - return -1; + if (__copy_from_user(fx_sw, &fxbuf->sw_reserved[0], sizeof(*fx_sw))) + return -EFAULT; /* Check for the first magic field and other error scenarios. */ if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || fx_sw->xstate_size < min_xstate_size || fx_sw->xstate_size > fpu_user_xstate_size || fx_sw->xstate_size > fx_sw->extended_size) - return -1; + goto setfx; /* * Check for the presence of second magic word at the end of memory @@ -45,10 +46,18 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, * fpstate layout with out copying the extended state information * in the memory layout. */ - if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size)) - || magic2 != FP_XSTATE_MAGIC2) - return -1; + if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))) + return -EFAULT; + if (likely(magic2 == FP_XSTATE_MAGIC2)) + return 0; +setfx: + trace_x86_fpu_xstate_check_failed(¤t->thread.fpu); + + /* Set the parameters for fx only state */ + fx_sw->magic1 = 0; + fx_sw->xstate_size = sizeof(struct fxregs_state); + fx_sw->xfeatures = XFEATURE_MASK_FPSSE; return 0; } @@ -64,7 +73,7 @@ static inline int save_fsave_header(struct task_struct *tsk, void __user *buf) fpregs_lock(); if (!test_thread_flag(TIF_NEED_FPU_LOAD)) - copy_fxregs_to_kernel(&tsk->thread.fpu); + fxsave(&tsk->thread.fpu.state.fxsave); fpregs_unlock(); convert_from_fxsr(&env, tsk); @@ -129,11 +138,11 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) int err; if (use_xsave()) - err = copy_xregs_to_user(buf); + err = xsave_to_user_sigframe(buf); else if (use_fxsr()) - err = copy_fxregs_to_user((struct fxregs_state __user *) buf); + err = fxsave_to_user_sigframe((struct fxregs_state __user *) buf); else - err = copy_fregs_to_user((struct fregs_state __user *) buf); + err = fnsave_to_user_sigframe((struct fregs_state __user *) buf); if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size)) err = -EFAULT; @@ -188,7 +197,7 @@ retry: */ fpregs_lock(); if (test_thread_flag(TIF_NEED_FPU_LOAD)) - __fpregs_load_activate(); + fpregs_restore_userregs(); pagefault_disable(); ret = copy_fpregs_to_sigframe(buf_fx); @@ -211,159 +220,45 @@ retry: return 0; } -static inline void -sanitize_restored_user_xstate(union fpregs_state *state, - struct user_i387_ia32_struct *ia32_env, - u64 user_xfeatures, int fx_only) +static int __restore_fpregs_from_user(void __user *buf, u64 xrestore, + bool fx_only) { - struct xregs_state *xsave = &state->xsave; - struct xstate_header *header = &xsave->header; - if (use_xsave()) { - /* - * Clear all feature bits which are not set in - * user_xfeatures and clear all extended features - * for fx_only mode. - */ - u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures; + u64 init_bv = xfeatures_mask_uabi() & ~xrestore; + int ret; - /* - * Supervisor state has to be preserved. The sigframe - * restore can only modify user features, i.e. @mask - * cannot contain them. - */ - header->xfeatures &= mask | xfeatures_mask_supervisor(); - } + if (likely(!fx_only)) + ret = xrstor_from_user_sigframe(buf, xrestore); + else + ret = fxrstor_from_user_sigframe(buf); - if (use_fxsr()) { - /* - * mscsr reserved bits must be masked to zero for security - * reasons. - */ - xsave->i387.mxcsr &= mxcsr_feature_mask; - - if (ia32_env) - convert_to_fxsr(&state->fxsave, ia32_env); + if (!ret && unlikely(init_bv)) + os_xrstor(&init_fpstate.xsave, init_bv); + return ret; + } else if (use_fxsr()) { + return fxrstor_from_user_sigframe(buf); + } else { + return frstor_from_user_sigframe(buf); } } /* - * Restore the extended state if present. Otherwise, restore the FP/SSE state. + * Attempt to restore the FPU registers directly from user memory. + * Pagefaults are handled and any errors returned are fatal. */ -static int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) +static int restore_fpregs_from_user(void __user *buf, u64 xrestore, + bool fx_only, unsigned int size) { - u64 init_bv; - int r; + struct fpu *fpu = ¤t->thread.fpu; + int ret; - if (use_xsave()) { - if (fx_only) { - init_bv = xfeatures_mask_user() & ~XFEATURE_MASK_FPSSE; - - r = copy_user_to_fxregs(buf); - if (!r) - copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); - return r; - } else { - init_bv = xfeatures_mask_user() & ~xbv; - - r = copy_user_to_xregs(buf, xbv); - if (!r && unlikely(init_bv)) - copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); - return r; - } - } else if (use_fxsr()) { - return copy_user_to_fxregs(buf); - } else - return copy_user_to_fregs(buf); -} - -static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) -{ - struct user_i387_ia32_struct *envp = NULL; - int state_size = fpu_kernel_xstate_size; - int ia32_fxstate = (buf != buf_fx); - struct task_struct *tsk = current; - struct fpu *fpu = &tsk->thread.fpu; - struct user_i387_ia32_struct env; - u64 user_xfeatures = 0; - int fx_only = 0; - int ret = 0; - - ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) || - IS_ENABLED(CONFIG_IA32_EMULATION)); - - if (!buf) { - fpu__clear_user_states(fpu); - return 0; - } - - if (!access_ok(buf, size)) { - ret = -EACCES; - goto out; - } - - if (!static_cpu_has(X86_FEATURE_FPU)) { - ret = fpregs_soft_set(current, NULL, 0, - sizeof(struct user_i387_ia32_struct), - NULL, buf); - goto out; - } - - if (use_xsave()) { - struct _fpx_sw_bytes fx_sw_user; - if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) { - /* - * Couldn't find the extended state information in the - * memory layout. Restore just the FP/SSE and init all - * the other extended state. - */ - state_size = sizeof(struct fxregs_state); - fx_only = 1; - trace_x86_fpu_xstate_check_failed(fpu); - } else { - state_size = fx_sw_user.xstate_size; - user_xfeatures = fx_sw_user.xfeatures; - } - } - - if ((unsigned long)buf_fx % 64) - fx_only = 1; - - if (!ia32_fxstate) { - /* - * Attempt to restore the FPU registers directly from user - * memory. For that to succeed, the user access cannot cause - * page faults. If it does, fall back to the slow path below, - * going through the kernel buffer with the enabled pagefault - * handler. - */ - fpregs_lock(); - pagefault_disable(); - ret = copy_user_to_fpregs_zeroing(buf_fx, user_xfeatures, fx_only); - pagefault_enable(); - if (!ret) { - - /* - * Restore supervisor states: previous context switch - * etc has done XSAVES and saved the supervisor states - * in the kernel buffer from which they can be restored - * now. - * - * We cannot do a single XRSTORS here - which would - * be nice - because the rest of the FPU registers are - * being restored from a user buffer directly. The - * single XRSTORS happens below, when the user buffer - * has been copied to the kernel one. - */ - if (test_thread_flag(TIF_NEED_FPU_LOAD) && - xfeatures_mask_supervisor()) - copy_kernel_to_xregs(&fpu->state.xsave, - xfeatures_mask_supervisor()); - fpregs_mark_activate(); - fpregs_unlock(); - return 0; - } +retry: + fpregs_lock(); + pagefault_disable(); + ret = __restore_fpregs_from_user(buf, xrestore, fx_only); + pagefault_enable(); + if (unlikely(ret)) { /* * The above did an FPU restore operation, restricted to * the user portion of the registers, and failed, but the @@ -371,29 +266,86 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) * nevertheless. * * If the FPU registers do not belong to current, then - * invalidate the FPU register state otherwise the task might - * preempt current and return to user space with corrupted - * FPU registers. - * - * In case current owns the FPU registers then no further - * action is required. The fixup below will handle it - * correctly. + * invalidate the FPU register state otherwise the task + * might preempt current and return to user space with + * corrupted FPU registers. */ if (test_thread_flag(TIF_NEED_FPU_LOAD)) __cpu_invalidate_fpregs_state(); - fpregs_unlock(); - } else { - /* - * For 32-bit frames with fxstate, copy the fxstate so it can - * be reconstructed later. - */ - ret = __copy_from_user(&env, buf, sizeof(env)); - if (ret) - goto out; - envp = &env; + + /* Try to handle #PF, but anything else is fatal. */ + if (ret != -EFAULT) + return -EINVAL; + + ret = fault_in_pages_readable(buf, size); + if (!ret) + goto retry; + return ret; } + /* + * Restore supervisor states: previous context switch etc has done + * XSAVES and saved the supervisor states in the kernel buffer from + * which they can be restored now. + * + * It would be optimal to handle this with a single XRSTORS, but + * this does not work because the rest of the FPU registers have + * been restored from a user buffer directly. + */ + if (test_thread_flag(TIF_NEED_FPU_LOAD) && xfeatures_mask_supervisor()) + os_xrstor(&fpu->state.xsave, xfeatures_mask_supervisor()); + + fpregs_mark_activate(); + fpregs_unlock(); + return 0; +} + +static int __fpu_restore_sig(void __user *buf, void __user *buf_fx, + bool ia32_fxstate) +{ + int state_size = fpu_kernel_xstate_size; + struct task_struct *tsk = current; + struct fpu *fpu = &tsk->thread.fpu; + struct user_i387_ia32_struct env; + u64 user_xfeatures = 0; + bool fx_only = false; + int ret; + + if (use_xsave()) { + struct _fpx_sw_bytes fx_sw_user; + + ret = check_xstate_in_sigframe(buf_fx, &fx_sw_user); + if (unlikely(ret)) + return ret; + + fx_only = !fx_sw_user.magic1; + state_size = fx_sw_user.xstate_size; + user_xfeatures = fx_sw_user.xfeatures; + } else { + user_xfeatures = XFEATURE_MASK_FPSSE; + } + + if (likely(!ia32_fxstate)) { + /* + * Attempt to restore the FPU registers directly from user + * memory. For that to succeed, the user access cannot cause page + * faults. If it does, fall back to the slow path below, going + * through the kernel buffer with the enabled pagefault handler. + */ + return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only, + state_size); + } + + /* + * Copy the legacy state because the FP portion of the FX frame has + * to be ignored for histerical raisins. The legacy state is folded + * in once the larger state has been copied. + */ + ret = __copy_from_user(&env, buf, sizeof(env)); + if (ret) + return ret; + /* * By setting TIF_NEED_FPU_LOAD it is ensured that our xstate is * not modified on context switch and that the xstate is considered @@ -401,80 +353,69 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) * the optimisation). */ fpregs_lock(); - if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { - /* - * Supervisor states are not modified by user space input. Save - * current supervisor states first and invalidate the FPU regs. + * If supervisor states are available then save the + * hardware state in current's fpstate so that the + * supervisor state is preserved. Save the full state for + * simplicity. There is no point in optimizing this by only + * saving the supervisor states and then shuffle them to + * the right place in memory. It's ia32 mode. Shrug. */ if (xfeatures_mask_supervisor()) - copy_supervisor_to_kernel(&fpu->state.xsave); + os_xsave(&fpu->state.xsave); set_thread_flag(TIF_NEED_FPU_LOAD); } __fpu_invalidate_fpregs_state(fpu); + __cpu_invalidate_fpregs_state(); fpregs_unlock(); if (use_xsave() && !fx_only) { - u64 init_bv = xfeatures_mask_user() & ~user_xfeatures; - - ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx); + ret = copy_sigframe_from_user_to_xstate(&fpu->state.xsave, buf_fx); if (ret) - goto out; - - sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures, - fx_only); - - fpregs_lock(); - if (unlikely(init_bv)) - copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); - - /* - * Restore previously saved supervisor xstates along with - * copied-in user xstates. - */ - ret = copy_kernel_to_xregs_err(&fpu->state.xsave, - user_xfeatures | xfeatures_mask_supervisor()); - - } else if (use_fxsr()) { - ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size); - if (ret) { - ret = -EFAULT; - goto out; - } - - sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures, - fx_only); - - fpregs_lock(); - if (use_xsave()) { - u64 init_bv; - - init_bv = xfeatures_mask_user() & ~XFEATURE_MASK_FPSSE; - copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); - } - - ret = copy_kernel_to_fxregs_err(&fpu->state.fxsave); + return ret; } else { - ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size); - if (ret) - goto out; + if (__copy_from_user(&fpu->state.fxsave, buf_fx, + sizeof(fpu->state.fxsave))) + return -EFAULT; - fpregs_lock(); - ret = copy_kernel_to_fregs_err(&fpu->state.fsave); + /* Reject invalid MXCSR values. */ + if (fpu->state.fxsave.mxcsr & ~mxcsr_feature_mask) + return -EINVAL; + + /* Enforce XFEATURE_MASK_FPSSE when XSAVE is enabled */ + if (use_xsave()) + fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE; } - if (!ret) - fpregs_mark_activate(); - else - fpregs_deactivate(fpu); - fpregs_unlock(); -out: - if (ret) - fpu__clear_user_states(fpu); + /* Fold the legacy FP storage */ + convert_to_fxsr(&fpu->state.fxsave, &env); + + fpregs_lock(); + if (use_xsave()) { + /* + * Remove all UABI feature bits not set in user_xfeatures + * from the memory xstate header which makes the full + * restore below bring them into init state. This works for + * fx_only mode as well because that has only FP and SSE + * set in user_xfeatures. + * + * Preserve supervisor states! + */ + u64 mask = user_xfeatures | xfeatures_mask_supervisor(); + + fpu->state.xsave.header.xfeatures &= mask; + ret = os_xrstor_safe(&fpu->state.xsave, xfeatures_mask_all); + } else { + ret = fxrstor_safe(&fpu->state.fxsave); + } + + if (likely(!ret)) + fpregs_mark_activate(); + + fpregs_unlock(); return ret; } - static inline int xstate_sigframe_size(void) { return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : @@ -486,15 +427,47 @@ static inline int xstate_sigframe_size(void) */ int fpu__restore_sig(void __user *buf, int ia32_frame) { + unsigned int size = xstate_sigframe_size(); + struct fpu *fpu = ¤t->thread.fpu; void __user *buf_fx = buf; - int size = xstate_sigframe_size(); + bool ia32_fxstate = false; + int ret; + if (unlikely(!buf)) { + fpu__clear_user_states(fpu); + return 0; + } + + ia32_frame &= (IS_ENABLED(CONFIG_X86_32) || + IS_ENABLED(CONFIG_IA32_EMULATION)); + + /* + * Only FXSR enabled systems need the FX state quirk. + * FRSTOR does not need it and can use the fast path. + */ if (ia32_frame && use_fxsr()) { buf_fx = buf + sizeof(struct fregs_state); size += sizeof(struct fregs_state); + ia32_fxstate = true; } - return __fpu__restore_sig(buf, buf_fx, size); + if (!access_ok(buf, size)) { + ret = -EACCES; + goto out; + } + + if (!IS_ENABLED(CONFIG_X86_64) && !cpu_feature_enabled(X86_FEATURE_FPU)) { + ret = fpregs_soft_set(current, NULL, 0, + sizeof(struct user_i387_ia32_struct), + NULL, buf); + } else { + ret = __fpu_restore_sig(buf, buf_fx, ia32_fxstate); + } + +out: + if (unlikely(ret)) + fpu__clear_user_states(fpu); + return ret; } unsigned long @@ -513,6 +486,25 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, return sp; } + +unsigned long fpu__get_fpstate_size(void) +{ + unsigned long ret = xstate_sigframe_size(); + + /* + * This space is needed on (most) 32-bit kernels, or when a 32-bit + * app is running on a 64-bit kernel. To keep things simple, just + * assume the worst case and always include space for 'freg_state', + * even for 64-bit apps on 64-bit kernels. This wastes a bit of + * space, but keeps the code simple. + */ + if ((IS_ENABLED(CONFIG_IA32_EMULATION) || + IS_ENABLED(CONFIG_X86_32)) && use_fxsr()) + ret += sizeof(struct fregs_state); + + return ret; +} + /* * Prepare the SW reserved portion of the fxsave memory layout, indicating * the presence of the extended state information in the memory layout @@ -526,7 +518,7 @@ void fpu__init_prepare_fx_sw_frame(void) fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; fx_sw_reserved.extended_size = size; - fx_sw_reserved.xfeatures = xfeatures_mask_user(); + fx_sw_reserved.xfeatures = xfeatures_mask_uabi(); fx_sw_reserved.xstate_size = fpu_user_xstate_size; if (IS_ENABLED(CONFIG_IA32_EMULATION) || diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 1cadb2faf740..c8def1b7f8fb 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -59,19 +59,24 @@ static short xsave_cpuid_features[] __initdata = { * This represents the full set of bits that should ever be set in a kernel * XSAVE buffer, both supervisor and user xstates. */ -u64 xfeatures_mask_all __read_mostly; +u64 xfeatures_mask_all __ro_after_init; +EXPORT_SYMBOL_GPL(xfeatures_mask_all); -static unsigned int xstate_offsets[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; -static unsigned int xstate_sizes[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; -static unsigned int xstate_comp_offsets[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; -static unsigned int xstate_supervisor_only_offsets[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; +static unsigned int xstate_offsets[XFEATURE_MAX] __ro_after_init = + { [ 0 ... XFEATURE_MAX - 1] = -1}; +static unsigned int xstate_sizes[XFEATURE_MAX] __ro_after_init = + { [ 0 ... XFEATURE_MAX - 1] = -1}; +static unsigned int xstate_comp_offsets[XFEATURE_MAX] __ro_after_init = + { [ 0 ... XFEATURE_MAX - 1] = -1}; +static unsigned int xstate_supervisor_only_offsets[XFEATURE_MAX] __ro_after_init = + { [ 0 ... XFEATURE_MAX - 1] = -1}; /* * The XSAVE area of kernel can be in standard or compacted format; * it is always in standard format for user mode. This is the user * mode standard format size used for signal and ptrace frames. */ -unsigned int fpu_user_xstate_size; +unsigned int fpu_user_xstate_size __ro_after_init; /* * Return whether the system supports a given xfeature. @@ -124,104 +129,14 @@ static bool xfeature_is_supervisor(int xfeature_nr) return ecx & 1; } -/* - * When executing XSAVEOPT (or other optimized XSAVE instructions), if - * a processor implementation detects that an FPU state component is still - * (or is again) in its initialized state, it may clear the corresponding - * bit in the header.xfeatures field, and can skip the writeout of registers - * to the corresponding memory layout. - * - * This means that when the bit is zero, the state component might still contain - * some previous - non-initialized register state. - * - * Before writing xstate information to user-space we sanitize those components, - * to always ensure that the memory layout of a feature will be in the init state - * if the corresponding header bit is zero. This is to ensure that user-space doesn't - * see some stale state in the memory layout during signal handling, debugging etc. - */ -void fpstate_sanitize_xstate(struct fpu *fpu) -{ - struct fxregs_state *fx = &fpu->state.fxsave; - int feature_bit; - u64 xfeatures; - - if (!use_xsaveopt()) - return; - - xfeatures = fpu->state.xsave.header.xfeatures; - - /* - * None of the feature bits are in init state. So nothing else - * to do for us, as the memory layout is up to date. - */ - if ((xfeatures & xfeatures_mask_all) == xfeatures_mask_all) - return; - - /* - * FP is in init state - */ - if (!(xfeatures & XFEATURE_MASK_FP)) { - fx->cwd = 0x37f; - fx->swd = 0; - fx->twd = 0; - fx->fop = 0; - fx->rip = 0; - fx->rdp = 0; - memset(fx->st_space, 0, sizeof(fx->st_space)); - } - - /* - * SSE is in init state - */ - if (!(xfeatures & XFEATURE_MASK_SSE)) - memset(fx->xmm_space, 0, sizeof(fx->xmm_space)); - - /* - * First two features are FPU and SSE, which above we handled - * in a special way already: - */ - feature_bit = 0x2; - xfeatures = (xfeatures_mask_user() & ~xfeatures) >> 2; - - /* - * Update all the remaining memory layouts according to their - * standard xstate layout, if their header bit is in the init - * state: - */ - while (xfeatures) { - if (xfeatures & 0x1) { - int offset = xstate_comp_offsets[feature_bit]; - int size = xstate_sizes[feature_bit]; - - memcpy((void *)fx + offset, - (void *)&init_fpstate.xsave + offset, - size); - } - - xfeatures >>= 1; - feature_bit++; - } -} - /* * Enable the extended processor state save/restore feature. * Called once per CPU onlining. */ void fpu__init_cpu_xstate(void) { - u64 unsup_bits; - if (!boot_cpu_has(X86_FEATURE_XSAVE) || !xfeatures_mask_all) return; - /* - * Unsupported supervisor xstates should not be found in - * the xfeatures mask. - */ - unsup_bits = xfeatures_mask_all & XFEATURE_MASK_SUPERVISOR_UNSUPPORTED; - WARN_ONCE(unsup_bits, "x86/fpu: Found unsupported supervisor xstates: 0x%llx\n", - unsup_bits); - - xfeatures_mask_all &= ~XFEATURE_MASK_SUPERVISOR_UNSUPPORTED; cr4_set_bits(X86_CR4_OSXSAVE); @@ -230,14 +145,14 @@ void fpu__init_cpu_xstate(void) * managed by XSAVE{C, OPT, S} and XRSTOR{S}. Only XSAVE user * states can be set here. */ - xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask_user()); + xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask_uabi()); /* * MSR_IA32_XSS sets supervisor states managed by XSAVES. */ if (boot_cpu_has(X86_FEATURE_XSAVES)) { wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() | - xfeatures_mask_dynamic()); + xfeatures_mask_independent()); } } @@ -486,7 +401,7 @@ static void __init setup_init_fpu_buf(void) /* * Init all the features state with header.xfeatures being 0x0 */ - copy_kernel_to_xregs_booting(&init_fpstate.xsave); + os_xrstor_booting(&init_fpstate.xsave); /* * All components are now in init state. Read the state back so @@ -535,25 +450,11 @@ int xfeature_size(int xfeature_nr) return eax; } -/* - * 'XSAVES' implies two different things: - * 1. saving of supervisor/system state - * 2. using the compacted format - * - * Use this function when dealing with the compacted format so - * that it is obvious which aspect of 'XSAVES' is being handled - * by the calling code. - */ -int using_compacted_format(void) -{ - return boot_cpu_has(X86_FEATURE_XSAVES); -} - /* Validate an xstate header supplied by userspace (ptrace or sigreturn) */ -int validate_user_xstate_header(const struct xstate_header *hdr) +static int validate_user_xstate_header(const struct xstate_header *hdr) { /* No unknown or supervisor features may be set */ - if (hdr->xfeatures & ~xfeatures_mask_user()) + if (hdr->xfeatures & ~xfeatures_mask_uabi()) return -EINVAL; /* Userspace must use the uncompacted format */ @@ -651,7 +552,7 @@ static void check_xstate_against_struct(int nr) * how large the XSAVE buffer needs to be. We are recalculating * it to be safe. * - * Dynamic XSAVE features allocate their own buffers and are not + * Independent XSAVE features allocate their own buffers and are not * covered by these checks. Only the size of the buffer for task->fpu * is checked here. */ @@ -667,9 +568,9 @@ static void do_extra_xstate_size_checks(void) check_xstate_against_struct(i); /* * Supervisor state components can be managed only by - * XSAVES, which is compacted-format only. + * XSAVES. */ - if (!using_compacted_format()) + if (!cpu_feature_enabled(X86_FEATURE_XSAVES)) XSTATE_WARN_ON(xfeature_is_supervisor(i)); /* Align from the end of the previous feature */ @@ -679,9 +580,9 @@ static void do_extra_xstate_size_checks(void) * The offset of a given state in the non-compacted * format is given to us in a CPUID leaf. We check * them for being ordered (increasing offsets) in - * setup_xstate_features(). + * setup_xstate_features(). XSAVES uses compacted format. */ - if (!using_compacted_format()) + if (!cpu_feature_enabled(X86_FEATURE_XSAVES)) paranoid_xstate_size = xfeature_uncompacted_offset(i); /* * The compacted-format offset always depends on where @@ -717,18 +618,18 @@ static unsigned int __init get_xsaves_size(void) } /* - * Get the total size of the enabled xstates without the dynamic supervisor + * Get the total size of the enabled xstates without the independent supervisor * features. */ -static unsigned int __init get_xsaves_size_no_dynamic(void) +static unsigned int __init get_xsaves_size_no_independent(void) { - u64 mask = xfeatures_mask_dynamic(); + u64 mask = xfeatures_mask_independent(); unsigned int size; if (!mask) return get_xsaves_size(); - /* Disable dynamic features. */ + /* Disable independent features. */ wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor()); /* @@ -737,7 +638,7 @@ static unsigned int __init get_xsaves_size_no_dynamic(void) */ size = get_xsaves_size(); - /* Re-enable dynamic features so XSAVES will work on them again. */ + /* Re-enable independent features so XSAVES will work on them again. */ wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() | mask); return size; @@ -780,7 +681,7 @@ static int __init init_xstate_size(void) xsave_size = get_xsave_size(); if (boot_cpu_has(X86_FEATURE_XSAVES)) - possible_xstate_size = get_xsaves_size_no_dynamic(); + possible_xstate_size = get_xsaves_size_no_independent(); else possible_xstate_size = xsave_size; @@ -821,6 +722,7 @@ void __init fpu__init_system_xstate(void) { unsigned int eax, ebx, ecx, edx; static int on_boot_cpu __initdata = 1; + u64 xfeatures; int err; int i; @@ -855,7 +757,7 @@ void __init fpu__init_system_xstate(void) cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); xfeatures_mask_all |= ecx + ((u64)edx << 32); - if ((xfeatures_mask_user() & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) { + if ((xfeatures_mask_uabi() & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) { /* * This indicates that something really unexpected happened * with the enumeration. Disable XSAVE and try to continue @@ -874,7 +776,11 @@ void __init fpu__init_system_xstate(void) xfeatures_mask_all &= ~BIT_ULL(i); } - xfeatures_mask_all &= fpu__get_supported_xfeatures_mask(); + xfeatures_mask_all &= XFEATURE_MASK_USER_SUPPORTED | + XFEATURE_MASK_SUPERVISOR_SUPPORTED; + + /* Store it for paranoia check at the end */ + xfeatures = xfeatures_mask_all; /* Enable xstate instructions to be able to continue with initialization: */ fpu__init_cpu_xstate(); @@ -886,14 +792,24 @@ void __init fpu__init_system_xstate(void) * Update info used for ptrace frames; use standard-format size and no * supervisor xstates: */ - update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask_user()); + update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask_uabi()); fpu__init_prepare_fx_sw_frame(); setup_init_fpu_buf(); setup_xstate_comp_offsets(); setup_supervisor_only_offsets(); - print_xstate_offset_size(); + /* + * Paranoia check whether something in the setup modified the + * xfeatures mask. + */ + if (xfeatures != xfeatures_mask_all) { + pr_err("x86/fpu: xfeatures modified from 0x%016llx to 0x%016llx during init, disabling XSAVE\n", + xfeatures, xfeatures_mask_all); + goto out_disable; + } + + print_xstate_offset_size(); pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", xfeatures_mask_all, fpu_kernel_xstate_size, @@ -913,16 +829,16 @@ void fpu__resume_cpu(void) /* * Restore XCR0 on xsave capable CPUs: */ - if (boot_cpu_has(X86_FEATURE_XSAVE)) - xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask_user()); + if (cpu_feature_enabled(X86_FEATURE_XSAVE)) + xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask_uabi()); /* * Restore IA32_XSS. The same CPUID bit enumerates support * of XSAVES and MSR_IA32_XSS. */ - if (boot_cpu_has(X86_FEATURE_XSAVES)) { + if (cpu_feature_enabled(X86_FEATURE_XSAVES)) { wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() | - xfeatures_mask_dynamic()); + xfeatures_mask_independent()); } } @@ -990,36 +906,6 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr) } EXPORT_SYMBOL_GPL(get_xsave_addr); -/* - * This wraps up the common operations that need to occur when retrieving - * data from xsave state. It first ensures that the current task was - * using the FPU and retrieves the data in to a buffer. It then calculates - * the offset of the requested field in the buffer. - * - * This function is safe to call whether the FPU is in use or not. - * - * Note that this only works on the current task. - * - * Inputs: - * @xfeature_nr: state which is defined in xsave.h (e.g. XFEATURE_FP, - * XFEATURE_SSE, etc...) - * Output: - * address of the state in the xsave area or NULL if the state - * is not present or is in its 'init state'. - */ -const void *get_xsave_field_ptr(int xfeature_nr) -{ - struct fpu *fpu = ¤t->thread.fpu; - - /* - * fpu__save() takes the CPU's xstate registers - * and saves them off to the 'fpu memory buffer. - */ - fpu__save(fpu); - - return get_xsave_addr(&fpu->state.xsave, xfeature_nr); -} - #ifdef CONFIG_ARCH_HAS_PKEYS /* @@ -1027,17 +913,16 @@ const void *get_xsave_field_ptr(int xfeature_nr) * rights for @pkey to @init_val. */ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, - unsigned long init_val) + unsigned long init_val) { - u32 old_pkru; - int pkey_shift = (pkey * PKRU_BITS_PER_PKEY); - u32 new_pkru_bits = 0; + u32 old_pkru, new_pkru_bits = 0; + int pkey_shift; /* * This check implies XSAVE support. OSPKE only gets * set if we enable XSAVE and we enable PKU in XCR0. */ - if (!boot_cpu_has(X86_FEATURE_OSPKE)) + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) return -EINVAL; /* @@ -1045,7 +930,8 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, * values originating from in-kernel users. Complain * if a bad value is observed. */ - WARN_ON_ONCE(pkey >= arch_max_pkey()); + if (WARN_ON_ONCE(pkey >= arch_max_pkey())) + return -EINVAL; /* Set the bits we need in PKRU: */ if (init_val & PKEY_DISABLE_ACCESS) @@ -1054,6 +940,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, new_pkru_bits |= PKRU_WD_BIT; /* Shift the bits in to the correct place in PKRU for pkey: */ + pkey_shift = pkey * PKRU_BITS_PER_PKEY; new_pkru_bits <<= pkey_shift; /* Get old PKRU and mask off any old bits in place: */ @@ -1067,170 +954,178 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, } #endif /* ! CONFIG_ARCH_HAS_PKEYS */ -/* - * Weird legacy quirk: SSE and YMM states store information in the - * MXCSR and MXCSR_FLAGS fields of the FP area. That means if the FP - * area is marked as unused in the xfeatures header, we need to copy - * MXCSR and MXCSR_FLAGS if either SSE or YMM are in use. - */ -static inline bool xfeatures_mxcsr_quirk(u64 xfeatures) +static void copy_feature(bool from_xstate, struct membuf *to, void *xstate, + void *init_xstate, unsigned int size) { - if (!(xfeatures & (XFEATURE_MASK_SSE|XFEATURE_MASK_YMM))) - return false; - - if (xfeatures & XFEATURE_MASK_FP) - return false; - - return true; + membuf_write(to, from_xstate ? xstate : init_xstate, size); } -static void fill_gap(struct membuf *to, unsigned *last, unsigned offset) -{ - if (*last >= offset) - return; - membuf_write(to, (void *)&init_fpstate.xsave + *last, offset - *last); - *last = offset; -} - -static void copy_part(struct membuf *to, unsigned *last, unsigned offset, - unsigned size, void *from) -{ - fill_gap(to, last, offset); - membuf_write(to, from, size); - *last = offset + size; -} - -/* - * Convert from kernel XSAVES compacted format to standard format and copy - * to a kernel-space ptrace buffer. +/** + * copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer + * @to: membuf descriptor + * @tsk: The task from which to copy the saved xstate + * @copy_mode: The requested copy mode * - * It supports partial copy but pos always starts from zero. This is called - * from xstateregs_get() and there we check the CPU has XSAVES. + * Converts from kernel XSAVE or XSAVES compacted format to UABI conforming + * format, i.e. from the kernel internal hardware dependent storage format + * to the requested @mode. UABI XSTATE is always uncompacted! + * + * It supports partial copy but @to.pos always starts from zero. */ -void copy_xstate_to_kernel(struct membuf to, struct xregs_state *xsave) +void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk, + enum xstate_copy_mode copy_mode) { + const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr); + struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; + struct xregs_state *xinit = &init_fpstate.xsave; struct xstate_header header; - const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr); - unsigned size = to.left; - unsigned last = 0; + unsigned int zerofrom; int i; - /* - * The destination is a ptrace buffer; we put in only user xstates: - */ memset(&header, 0, sizeof(header)); header.xfeatures = xsave->header.xfeatures; - header.xfeatures &= xfeatures_mask_user(); - if (header.xfeatures & XFEATURE_MASK_FP) - copy_part(&to, &last, 0, off_mxcsr, &xsave->i387); - if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)) - copy_part(&to, &last, off_mxcsr, - MXCSR_AND_FLAGS_SIZE, &xsave->i387.mxcsr); - if (header.xfeatures & XFEATURE_MASK_FP) - copy_part(&to, &last, offsetof(struct fxregs_state, st_space), - 128, &xsave->i387.st_space); - if (header.xfeatures & XFEATURE_MASK_SSE) - copy_part(&to, &last, xstate_offsets[XFEATURE_SSE], - 256, &xsave->i387.xmm_space); - /* - * Fill xsave->i387.sw_reserved value for ptrace frame: - */ - copy_part(&to, &last, offsetof(struct fxregs_state, sw_reserved), - 48, xstate_fx_sw_bytes); - /* - * Copy xregs_state->header: - */ - copy_part(&to, &last, offsetof(struct xregs_state, header), - sizeof(header), &header); + /* Mask out the feature bits depending on copy mode */ + switch (copy_mode) { + case XSTATE_COPY_FP: + header.xfeatures &= XFEATURE_MASK_FP; + break; + + case XSTATE_COPY_FX: + header.xfeatures &= XFEATURE_MASK_FP | XFEATURE_MASK_SSE; + break; + + case XSTATE_COPY_XSAVE: + header.xfeatures &= xfeatures_mask_uabi(); + break; + } + + /* Copy FP state up to MXCSR */ + copy_feature(header.xfeatures & XFEATURE_MASK_FP, &to, &xsave->i387, + &xinit->i387, off_mxcsr); + + /* Copy MXCSR when SSE or YMM are set in the feature mask */ + copy_feature(header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM), + &to, &xsave->i387.mxcsr, &xinit->i387.mxcsr, + MXCSR_AND_FLAGS_SIZE); + + /* Copy the remaining FP state */ + copy_feature(header.xfeatures & XFEATURE_MASK_FP, + &to, &xsave->i387.st_space, &xinit->i387.st_space, + sizeof(xsave->i387.st_space)); + + /* Copy the SSE state - shared with YMM, but independently managed */ + copy_feature(header.xfeatures & XFEATURE_MASK_SSE, + &to, &xsave->i387.xmm_space, &xinit->i387.xmm_space, + sizeof(xsave->i387.xmm_space)); + + if (copy_mode != XSTATE_COPY_XSAVE) + goto out; + + /* Zero the padding area */ + membuf_zero(&to, sizeof(xsave->i387.padding)); + + /* Copy xsave->i387.sw_reserved */ + membuf_write(&to, xstate_fx_sw_bytes, sizeof(xsave->i387.sw_reserved)); + + /* Copy the user space relevant state of @xsave->header */ + membuf_write(&to, &header, sizeof(header)); + + zerofrom = offsetof(struct xregs_state, extended_state_area); for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { /* - * Copy only in-use xstates: + * The ptrace buffer is in non-compacted XSAVE format. + * In non-compacted format disabled features still occupy + * state space, but there is no state to copy from in the + * compacted init_fpstate. The gap tracking will zero this + * later. */ - if ((header.xfeatures >> i) & 1) { - void *src = __raw_xsave_addr(xsave, i); + if (!(xfeatures_mask_uabi() & BIT_ULL(i))) + continue; - copy_part(&to, &last, xstate_offsets[i], - xstate_sizes[i], src); + /* + * If there was a feature or alignment gap, zero the space + * in the destination buffer. + */ + if (zerofrom < xstate_offsets[i]) + membuf_zero(&to, xstate_offsets[i] - zerofrom); + + if (i == XFEATURE_PKRU) { + struct pkru_state pkru = {0}; + /* + * PKRU is not necessarily up to date in the + * thread's XSAVE buffer. Fill this part from the + * per-thread storage. + */ + pkru.pkru = tsk->thread.pkru; + membuf_write(&to, &pkru, sizeof(pkru)); + } else { + copy_feature(header.xfeatures & BIT_ULL(i), &to, + __raw_xsave_addr(xsave, i), + __raw_xsave_addr(xinit, i), + xstate_sizes[i]); } - + /* + * Keep track of the last copied state in the non-compacted + * target buffer for gap zeroing. + */ + zerofrom = xstate_offsets[i] + xstate_sizes[i]; } - fill_gap(&to, &last, size); + +out: + if (to.left) + membuf_zero(&to, to.left); } -/* - * Convert from a ptrace standard-format kernel buffer to kernel XSAVES format - * and copy to the target thread. This is called from xstateregs_set(). - */ -int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf) +static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size, + const void *kbuf, const void __user *ubuf) { - unsigned int offset, size; - int i; - struct xstate_header hdr; - - offset = offsetof(struct xregs_state, header); - size = sizeof(hdr); - - memcpy(&hdr, kbuf + offset, size); - - if (validate_user_xstate_header(&hdr)) - return -EINVAL; - - for (i = 0; i < XFEATURE_MAX; i++) { - u64 mask = ((u64)1 << i); - - if (hdr.xfeatures & mask) { - void *dst = __raw_xsave_addr(xsave, i); - - offset = xstate_offsets[i]; - size = xstate_sizes[i]; - - memcpy(dst, kbuf + offset, size); - } + if (kbuf) { + memcpy(dst, kbuf + offset, size); + } else { + if (copy_from_user(dst, ubuf + offset, size)) + return -EFAULT; } - - if (xfeatures_mxcsr_quirk(hdr.xfeatures)) { - offset = offsetof(struct fxregs_state, mxcsr); - size = MXCSR_AND_FLAGS_SIZE; - memcpy(&xsave->i387.mxcsr, kbuf + offset, size); - } - - /* - * The state that came in from userspace was user-state only. - * Mask all the user states out of 'xfeatures': - */ - xsave->header.xfeatures &= XFEATURE_MASK_SUPERVISOR_ALL; - - /* - * Add back in the features that came in from userspace: - */ - xsave->header.xfeatures |= hdr.xfeatures; - return 0; } -/* - * Convert from a ptrace or sigreturn standard-format user-space buffer to - * kernel XSAVES format and copy to the target thread. This is called from - * xstateregs_set(), as well as potentially from the sigreturn() and - * rt_sigreturn() system calls. - */ -int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf) + +static int copy_uabi_to_xstate(struct xregs_state *xsave, const void *kbuf, + const void __user *ubuf) { unsigned int offset, size; - int i; struct xstate_header hdr; + u64 mask; + int i; offset = offsetof(struct xregs_state, header); - size = sizeof(hdr); - - if (__copy_from_user(&hdr, ubuf + offset, size)) + if (copy_from_buffer(&hdr, offset, sizeof(hdr), kbuf, ubuf)) return -EFAULT; if (validate_user_xstate_header(&hdr)) return -EINVAL; + /* Validate MXCSR when any of the related features is in use */ + mask = XFEATURE_MASK_FP | XFEATURE_MASK_SSE | XFEATURE_MASK_YMM; + if (hdr.xfeatures & mask) { + u32 mxcsr[2]; + + offset = offsetof(struct fxregs_state, mxcsr); + if (copy_from_buffer(mxcsr, offset, sizeof(mxcsr), kbuf, ubuf)) + return -EFAULT; + + /* Reserved bits in MXCSR must be zero. */ + if (mxcsr[0] & ~mxcsr_feature_mask) + return -EINVAL; + + /* SSE and YMM require MXCSR even when FP is not in use. */ + if (!(hdr.xfeatures & XFEATURE_MASK_FP)) { + xsave->i387.mxcsr = mxcsr[0]; + xsave->i387.mxcsr_mask = mxcsr[1]; + } + } + for (i = 0; i < XFEATURE_MAX; i++) { u64 mask = ((u64)1 << i); @@ -1240,18 +1135,11 @@ int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf) offset = xstate_offsets[i]; size = xstate_sizes[i]; - if (__copy_from_user(dst, ubuf + offset, size)) + if (copy_from_buffer(dst, offset, size, kbuf, ubuf)) return -EFAULT; } } - if (xfeatures_mxcsr_quirk(hdr.xfeatures)) { - offset = offsetof(struct fxregs_state, mxcsr); - size = MXCSR_AND_FLAGS_SIZE; - if (__copy_from_user(&xsave->i387.mxcsr, ubuf + offset, size)) - return -EFAULT; - } - /* * The state that came in from userspace was user-state only. * Mask all the user states out of 'xfeatures': @@ -1267,130 +1155,94 @@ int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf) } /* - * Save only supervisor states to the kernel buffer. This blows away all - * old states, and is intended to be used only in __fpu__restore_sig(), where - * user states are restored from the user buffer. + * Convert from a ptrace standard-format kernel buffer to kernel XSAVE[S] + * format and copy to the target thread. This is called from + * xstateregs_set(). */ -void copy_supervisor_to_kernel(struct xregs_state *xstate) +int copy_uabi_from_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf) { - struct xstate_header *header; - u64 max_bit, min_bit; - u32 lmask, hmask; - int err, i; + return copy_uabi_to_xstate(xsave, kbuf, NULL); +} - if (WARN_ON(!boot_cpu_has(X86_FEATURE_XSAVES))) - return; +/* + * Convert from a sigreturn standard-format user-space buffer to kernel + * XSAVE[S] format and copy to the target thread. This is called from the + * sigreturn() and rt_sigreturn() system calls. + */ +int copy_sigframe_from_user_to_xstate(struct xregs_state *xsave, + const void __user *ubuf) +{ + return copy_uabi_to_xstate(xsave, NULL, ubuf); +} - if (!xfeatures_mask_supervisor()) - return; - - max_bit = __fls(xfeatures_mask_supervisor()); - min_bit = __ffs(xfeatures_mask_supervisor()); - - lmask = xfeatures_mask_supervisor(); - hmask = xfeatures_mask_supervisor() >> 32; - XSTATE_OP(XSAVES, xstate, lmask, hmask, err); - - /* We should never fault when copying to a kernel buffer: */ - if (WARN_ON_FPU(err)) - return; +static bool validate_xsaves_xrstors(u64 mask) +{ + u64 xchk; + if (WARN_ON_FPU(!cpu_feature_enabled(X86_FEATURE_XSAVES))) + return false; /* - * At this point, the buffer has only supervisor states and must be - * converted back to normal kernel format. + * Validate that this is either a task->fpstate related component + * subset or an independent one. */ - header = &xstate->header; - header->xcomp_bv |= xfeatures_mask_all; + if (mask & xfeatures_mask_independent()) + xchk = ~xfeatures_mask_independent(); + else + xchk = ~xfeatures_mask_all; - /* - * This only moves states up in the buffer. Start with - * the last state and move backwards so that states are - * not overwritten until after they are moved. Note: - * memmove() allows overlapping src/dst buffers. - */ - for (i = max_bit; i >= min_bit; i--) { - u8 *xbuf = (u8 *)xstate; + if (WARN_ON_ONCE(!mask || mask & xchk)) + return false; - if (!((header->xfeatures >> i) & 1)) - continue; - - /* Move xfeature 'i' into its normal location */ - memmove(xbuf + xstate_comp_offsets[i], - xbuf + xstate_supervisor_only_offsets[i], - xstate_sizes[i]); - } + return true; } /** - * copy_dynamic_supervisor_to_kernel() - Save dynamic supervisor states to - * an xsave area - * @xstate: A pointer to an xsave area - * @mask: Represent the dynamic supervisor features saved into the xsave area + * xsaves - Save selected components to a kernel xstate buffer + * @xstate: Pointer to the buffer + * @mask: Feature mask to select the components to save * - * Only the dynamic supervisor states sets in the mask are saved into the xsave - * area (See the comment in XFEATURE_MASK_DYNAMIC for the details of dynamic - * supervisor feature). Besides the dynamic supervisor states, the legacy - * region and XSAVE header are also saved into the xsave area. The supervisor - * features in the XFEATURE_MASK_SUPERVISOR_SUPPORTED and - * XFEATURE_MASK_SUPERVISOR_UNSUPPORTED are not saved. + * The @xstate buffer must be 64 byte aligned and correctly initialized as + * XSAVES does not write the full xstate header. Before first use the + * buffer should be zeroed otherwise a consecutive XRSTORS from that buffer + * can #GP. * - * The xsave area must be 64-bytes aligned. + * The feature mask must either be a subset of the independent features or + * a subset of the task->fpstate related features. */ -void copy_dynamic_supervisor_to_kernel(struct xregs_state *xstate, u64 mask) +void xsaves(struct xregs_state *xstate, u64 mask) { - u64 dynamic_mask = xfeatures_mask_dynamic() & mask; - u32 lmask, hmask; int err; - if (WARN_ON_FPU(!boot_cpu_has(X86_FEATURE_XSAVES))) + if (!validate_xsaves_xrstors(mask)) return; - if (WARN_ON_FPU(!dynamic_mask)) - return; - - lmask = dynamic_mask; - hmask = dynamic_mask >> 32; - - XSTATE_OP(XSAVES, xstate, lmask, hmask, err); - - /* Should never fault when copying to a kernel buffer */ - WARN_ON_FPU(err); + XSTATE_OP(XSAVES, xstate, (u32)mask, (u32)(mask >> 32), err); + WARN_ON_ONCE(err); } /** - * copy_kernel_to_dynamic_supervisor() - Restore dynamic supervisor states from - * an xsave area - * @xstate: A pointer to an xsave area - * @mask: Represent the dynamic supervisor features restored from the xsave area + * xrstors - Restore selected components from a kernel xstate buffer + * @xstate: Pointer to the buffer + * @mask: Feature mask to select the components to restore * - * Only the dynamic supervisor states sets in the mask are restored from the - * xsave area (See the comment in XFEATURE_MASK_DYNAMIC for the details of - * dynamic supervisor feature). Besides the dynamic supervisor states, the - * legacy region and XSAVE header are also restored from the xsave area. The - * supervisor features in the XFEATURE_MASK_SUPERVISOR_SUPPORTED and - * XFEATURE_MASK_SUPERVISOR_UNSUPPORTED are not restored. + * The @xstate buffer must be 64 byte aligned and correctly initialized + * otherwise XRSTORS from that buffer can #GP. * - * The xsave area must be 64-bytes aligned. + * Proper usage is to restore the state which was saved with + * xsaves() into @xstate. + * + * The feature mask must either be a subset of the independent features or + * a subset of the task->fpstate related features. */ -void copy_kernel_to_dynamic_supervisor(struct xregs_state *xstate, u64 mask) +void xrstors(struct xregs_state *xstate, u64 mask) { - u64 dynamic_mask = xfeatures_mask_dynamic() & mask; - u32 lmask, hmask; int err; - if (WARN_ON_FPU(!boot_cpu_has(X86_FEATURE_XSAVES))) + if (!validate_xsaves_xrstors(mask)) return; - if (WARN_ON_FPU(!dynamic_mask)) - return; - - lmask = dynamic_mask; - hmask = dynamic_mask >> 32; - - XSTATE_OP(XRSTORS, xstate, lmask, hmask, err); - - /* Should never fault when copying from a kernel buffer */ - WARN_ON_FPU(err); + XSTATE_OP(XRSTORS, xstate, (u32)mask, (u32)(mask >> 32), err); + WARN_ON_ONCE(err); } #ifdef CONFIG_PROC_PID_ARCH_STATUS diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index e52b208b4641..1d9463e3096b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -87,8 +87,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) #ifdef CONFIG_VM86 dst->thread.vm86 = NULL; #endif - - return fpu__copy(dst, src); + return fpu_clone(dst); } /* @@ -157,11 +156,18 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, /* Kernel thread ? */ if (unlikely(p->flags & PF_KTHREAD)) { + p->thread.pkru = pkru_get_init_value(); memset(childregs, 0, sizeof(struct pt_regs)); kthread_frame_init(frame, sp, arg); return 0; } + /* + * Clone current's PKRU value from hardware. tsk->thread.pkru + * is only valid when scheduled out. + */ + p->thread.pkru = read_pkru(); + frame->bx = 0; *childregs = *current_pt_regs(); childregs->ax = 0; @@ -199,6 +205,15 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, return ret; } +static void pkru_flush_thread(void) +{ + /* + * If PKRU is enabled the default PKRU value has to be loaded into + * the hardware right here (similar to context switch). + */ + pkru_write_default(); +} + void flush_thread(void) { struct task_struct *tsk = current; @@ -206,7 +221,8 @@ void flush_thread(void) flush_ptrace_hw_breakpoint(tsk); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); - fpu__clear_all(&tsk->thread.fpu); + fpu_flush_thread(); + pkru_flush_thread(); } void disable_TSC(void) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index d08307df69ad..ec0d836a13b1 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -136,7 +137,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode, log_lvl, d3, d6, d7); } - if (boot_cpu_has(X86_FEATURE_OSPKE)) + if (cpu_feature_enabled(X86_FEATURE_OSPKE)) printk("%sPKRU: %08x\n", log_lvl, read_pkru()); } @@ -339,6 +340,29 @@ static __always_inline void load_seg_legacy(unsigned short prev_index, } } +/* + * Store prev's PKRU value and load next's PKRU value if they differ. PKRU + * is not XSTATE managed on context switch because that would require a + * lookup in the task's FPU xsave buffer and require to keep that updated + * in various places. + */ +static __always_inline void x86_pkru_load(struct thread_struct *prev, + struct thread_struct *next) +{ + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) + return; + + /* Stash the prev task's value: */ + prev->pkru = rdpkru(); + + /* + * PKRU writes are slightly expensive. Avoid them when not + * strictly necessary: + */ + if (prev->pkru != next->pkru) + wrpkru(next->pkru); +} + static __always_inline void x86_fsgsbase_load(struct thread_struct *prev, struct thread_struct *next) { @@ -588,6 +612,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) x86_fsgsbase_load(prev, next); + x86_pkru_load(prev, next); + /* * Switch the PDA and FPU contexts. */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9f1d9215a9fb..bff3a784aec5 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -847,10 +847,7 @@ void __init setup_arch(char **cmdline_p) if (!boot_params.hdr.root_flags) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = _brk_end; + setup_initial_init_mm(_text, _etext, _edata, (void *)_brk_end); code_resource.start = __pa_symbol(_text); code_resource.end = __pa_symbol(_etext)-1; diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index e12779a2714d..f4d21e470083 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -212,6 +212,11 @@ do { \ * Set up a signal frame. */ +/* x86 ABI requires 16-byte alignment */ +#define FRAME_ALIGNMENT 16UL + +#define MAX_FRAME_PADDING (FRAME_ALIGNMENT - 1) + /* * Determine which stack to use.. */ @@ -222,9 +227,9 @@ static unsigned long align_sigframe(unsigned long sp) * Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ - sp = ((sp + 4) & -16ul) - 4; + sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4; #else /* !CONFIG_X86_32 */ - sp = round_down(sp, 16) - 8; + sp = round_down(sp, FRAME_ALIGNMENT) - 8; #endif return sp; } @@ -234,10 +239,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, void __user **fpstate) { /* Default to using normal stack */ + bool nested_altstack = on_sig_stack(regs->sp); + bool entering_altstack = false; unsigned long math_size = 0; unsigned long sp = regs->sp; unsigned long buf_fx = 0; - int onsigstack = on_sig_stack(sp); int ret; /* redzone */ @@ -246,15 +252,23 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) + /* + * This checks nested_altstack via sas_ss_flags(). Sensible + * programs use SS_AUTODISARM, which disables that check, and + * programs that don't use SS_AUTODISARM get compatible. + */ + if (sas_ss_flags(sp) == 0) { sp = current->sas_ss_sp + current->sas_ss_size; + entering_altstack = true; + } } else if (IS_ENABLED(CONFIG_X86_32) && - !onsigstack && + !nested_altstack && regs->ss != __USER_DS && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) { /* This is the legacy signal stack switching. */ sp = (unsigned long) ka->sa.sa_restorer; + entering_altstack = true; } sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), @@ -267,8 +281,15 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV. */ - if (onsigstack && !likely(on_sig_stack(sp))) + if (unlikely((nested_altstack || entering_altstack) && + !__on_sig_stack(sp))) { + + if (show_unhandled_signals && printk_ratelimit()) + pr_info("%s[%d] overflowed sigaltstack\n", + current->comm, task_pid_nr(current)); + return (void __user *)-1L; + } /* save i387 and extended state */ ret = copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size); @@ -663,6 +684,61 @@ badframe: return 0; } +/* + * There are four different struct types for signal frame: sigframe_ia32, + * rt_sigframe_ia32, rt_sigframe_x32, and rt_sigframe. Use the worst case + * -- the largest size. It means the size for 64-bit apps is a bit more + * than needed, but this keeps the code simple. + */ +#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) +# define MAX_FRAME_SIGINFO_UCTXT_SIZE sizeof(struct sigframe_ia32) +#else +# define MAX_FRAME_SIGINFO_UCTXT_SIZE sizeof(struct rt_sigframe) +#endif + +/* + * The FP state frame contains an XSAVE buffer which must be 64-byte aligned. + * If a signal frame starts at an unaligned address, extra space is required. + * This is the max alignment padding, conservatively. + */ +#define MAX_XSAVE_PADDING 63UL + +/* + * The frame data is composed of the following areas and laid out as: + * + * ------------------------- + * | alignment padding | + * ------------------------- + * | (f)xsave frame | + * ------------------------- + * | fsave header | + * ------------------------- + * | alignment padding | + * ------------------------- + * | siginfo + ucontext | + * ------------------------- + */ + +/* max_frame_size tells userspace the worst case signal stack size. */ +static unsigned long __ro_after_init max_frame_size; + +void __init init_sigframe_size(void) +{ + max_frame_size = MAX_FRAME_SIGINFO_UCTXT_SIZE + MAX_FRAME_PADDING; + + max_frame_size += fpu__get_fpstate_size() + MAX_XSAVE_PADDING; + + /* Userspace expects an aligned size. */ + max_frame_size = round_up(max_frame_size, FRAME_ALIGNMENT); + + pr_info("max sigframe size: %lu\n", max_frame_size); +} + +unsigned long get_sigframe_size(void) +{ + return max_frame_size; +} + static inline int is_ia32_compat_frame(struct ksignal *ksig) { return IS_ENABLED(CONFIG_IA32_EMULATION) && diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index ed540e09a399..a58800973aed 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -1046,9 +1046,10 @@ static void math_error(struct pt_regs *regs, int trapnr) } /* - * Save the info for the exception handler and clear the error. + * Synchronize the FPU register state to the memory register state + * if necessary. This allows the exception handler to inspect it. */ - fpu__save(fpu); + fpu_sync_fpstate(fpu); task->thread.trap_nr = trapnr; task->thread.error_code = 0; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 8d36f0c73071..62926f1a5f7b 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "x86.h" diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 17468d983fbd..c6dc1b445231 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include /* Ugh! */ #include @@ -939,7 +940,7 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) (kvm_read_cr4_bits(vcpu, X86_CR4_PKE) || (vcpu->arch.xcr0 & XFEATURE_MASK_PKRU)) && vcpu->arch.pkru != vcpu->arch.host_pkru) - __write_pkru(vcpu->arch.pkru); + write_pkru(vcpu->arch.pkru); } EXPORT_SYMBOL_GPL(kvm_load_guest_xsave_state); @@ -953,7 +954,7 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu) (vcpu->arch.xcr0 & XFEATURE_MASK_PKRU))) { vcpu->arch.pkru = rdpkru(); if (vcpu->arch.pkru != vcpu->arch.host_pkru) - __write_pkru(vcpu->arch.host_pkru); + write_pkru(vcpu->arch.host_pkru); } if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE)) { @@ -4704,20 +4705,21 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) */ valid = xstate_bv & ~XFEATURE_MASK_FPSSE; while (valid) { + u32 size, offset, ecx, edx; u64 xfeature_mask = valid & -valid; int xfeature_nr = fls64(xfeature_mask) - 1; - void *src = get_xsave_addr(xsave, xfeature_nr); + void *src; - if (src) { - u32 size, offset, ecx, edx; - cpuid_count(XSTATE_CPUID, xfeature_nr, - &size, &offset, &ecx, &edx); - if (xfeature_nr == XFEATURE_PKRU) - memcpy(dest + offset, &vcpu->arch.pkru, - sizeof(vcpu->arch.pkru)); - else + cpuid_count(XSTATE_CPUID, xfeature_nr, + &size, &offset, &ecx, &edx); + + if (xfeature_nr == XFEATURE_PKRU) { + memcpy(dest + offset, &vcpu->arch.pkru, + sizeof(vcpu->arch.pkru)); + } else { + src = get_xsave_addr(xsave, xfeature_nr); + if (src) memcpy(dest + offset, src, size); - } valid -= xfeature_mask; @@ -4747,18 +4749,20 @@ static void load_xsave(struct kvm_vcpu *vcpu, u8 *src) */ valid = xstate_bv & ~XFEATURE_MASK_FPSSE; while (valid) { + u32 size, offset, ecx, edx; u64 xfeature_mask = valid & -valid; int xfeature_nr = fls64(xfeature_mask) - 1; - void *dest = get_xsave_addr(xsave, xfeature_nr); - if (dest) { - u32 size, offset, ecx, edx; - cpuid_count(XSTATE_CPUID, xfeature_nr, - &size, &offset, &ecx, &edx); - if (xfeature_nr == XFEATURE_PKRU) - memcpy(&vcpu->arch.pkru, src + offset, - sizeof(vcpu->arch.pkru)); - else + cpuid_count(XSTATE_CPUID, xfeature_nr, + &size, &offset, &ecx, &edx); + + if (xfeature_nr == XFEATURE_PKRU) { + memcpy(&vcpu->arch.pkru, src + offset, + sizeof(vcpu->arch.pkru)); + } else { + void *dest = get_xsave_addr(xsave, xfeature_nr); + + if (dest) memcpy(dest, src + offset, size); } @@ -9885,7 +9889,7 @@ static void kvm_save_current_fpu(struct fpu *fpu) memcpy(&fpu->state, ¤t->thread.fpu.state, fpu_kernel_xstate_size); else - copy_fpregs_to_fpstate(fpu); + save_fpregs_to_fpstate(fpu); } /* Swap (qemu) user FPU context for the guest FPU context. */ @@ -9901,7 +9905,7 @@ static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) */ if (vcpu->arch.guest_fpu) /* PKRU is separately restored in kvm_x86_ops.run. */ - __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu->state, + __restore_fpregs_from_fpstate(&vcpu->arch.guest_fpu->state, ~XFEATURE_MASK_PKRU); fpregs_mark_activate(); @@ -9922,7 +9926,7 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) if (vcpu->arch.guest_fpu) kvm_save_current_fpu(vcpu->arch.guest_fpu); - copy_kernel_to_fpregs(&vcpu->arch.user_fpu->state); + restore_fpregs_from_fpstate(&vcpu->arch.user_fpu->state); fpregs_mark_activate(); fpregs_unlock(); diff --git a/arch/x86/math-emu/fpu_proto.h b/arch/x86/math-emu/fpu_proto.h index 70d35c200945..94c4023092f3 100644 --- a/arch/x86/math-emu/fpu_proto.h +++ b/arch/x86/math-emu/fpu_proto.h @@ -144,7 +144,7 @@ extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d); extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d); extern int FPU_round_to_int(FPU_REG *r, u_char tag); extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s); -extern void frstor(fpu_addr_modes addr_modes, u_char __user *data_address); +extern void FPU_frstor(fpu_addr_modes addr_modes, u_char __user *data_address); extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d); extern void fsave(fpu_addr_modes addr_modes, u_char __user *data_address); extern int FPU_tagof(FPU_REG *ptr); diff --git a/arch/x86/math-emu/load_store.c b/arch/x86/math-emu/load_store.c index f15263e158e8..4092df79de4f 100644 --- a/arch/x86/math-emu/load_store.c +++ b/arch/x86/math-emu/load_store.c @@ -240,7 +240,7 @@ int FPU_load_store(u_char type, fpu_addr_modes addr_modes, fix-up operations. */ return 1; case 022: /* frstor m94/108byte */ - frstor(addr_modes, (u_char __user *) data_address); + FPU_frstor(addr_modes, (u_char __user *) data_address); /* Ensure that the values just loaded are not changed by fix-up operations. */ return 1; diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c index 7ca6417c0c8d..7e4521fbe7da 100644 --- a/arch/x86/math-emu/reg_ld_str.c +++ b/arch/x86/math-emu/reg_ld_str.c @@ -1117,7 +1117,7 @@ u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s) return s; } -void frstor(fpu_addr_modes addr_modes, u_char __user *data_address) +void FPU_frstor(fpu_addr_modes addr_modes, u_char __user *data_address) { int i, regnr; u_char __user *s = fldenv(addr_modes, data_address); diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 121921b2927c..e1664e9f969c 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -65,7 +65,7 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup, WARN_ONCE(1, "Bad FPU state detected at %pB, reinitializing FPU registers.", (void *)instruction_pointer(regs)); - __copy_kernel_to_fpregs(&init_fpstate, -1); + __restore_fpregs_from_fpstate(&init_fpstate, xfeatures_mask_fpstate()); return true; } EXPORT_SYMBOL_GPL(ex_handler_fprestore); diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 2d27932c9ac7..b2eefdefc108 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -875,7 +875,7 @@ static inline bool bad_area_access_from_pkeys(unsigned long error_code, /* This code is always called on the current mm */ bool foreign = false; - if (!boot_cpu_has(X86_FEATURE_OSPKE)) + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) return false; if (error_code & X86_PF_PK) return true; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 65ea58527176..ddeaba947eb3 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -194,8 +194,8 @@ static void sync_global_pgds_l4(unsigned long start, unsigned long end) spin_lock(pgt_lock); if (!p4d_none(*p4d_ref) && !p4d_none(*p4d)) - BUG_ON(p4d_page_vaddr(*p4d) - != p4d_page_vaddr(*p4d_ref)); + BUG_ON(p4d_pgtable(*p4d) + != p4d_pgtable(*p4d_ref)); if (p4d_none(*p4d)) set_p4d(p4d, *p4d_ref); diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 156cd235659f..ad8a5c586a35 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -1134,7 +1134,7 @@ static void __unmap_pmd_range(pud_t *pud, pmd_t *pmd, unsigned long start, unsigned long end) { if (unmap_pte_range(pmd, start, end)) - if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + if (try_to_free_pmd_page(pud_pgtable(*pud))) pud_clear(pud); } @@ -1178,7 +1178,7 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) * Try again to free the PMD page if haven't succeeded above. */ if (!pud_none(*pud)) - if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + if (try_to_free_pmd_page(pud_pgtable(*pud))) pud_clear(pud); } diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 1303ff6ef7be..3364fe62b903 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -801,7 +801,7 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) pte_t *pte; int i; - pmd = (pmd_t *)pud_page_vaddr(*pud); + pmd = pud_pgtable(*pud); pmd_sv = (pmd_t *)__get_free_page(GFP_KERNEL); if (!pmd_sv) return 0; diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index 4a67b922bce1..e44e938885b7 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -10,7 +10,6 @@ #include /* boot_cpu_has, ... */ #include /* vma_pkey() */ -#include /* init_fpstate */ int __execute_only_pkey(struct mm_struct *mm) { @@ -125,22 +124,6 @@ u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) | PKRU_AD_KEY(10) | PKRU_AD_KEY(11) | PKRU_AD_KEY(12) | PKRU_AD_KEY(13) | PKRU_AD_KEY(14) | PKRU_AD_KEY(15); -/* - * Called from the FPU code when creating a fresh set of FPU - * registers. This is called from a very specific context where - * we know the FPU registers are safe for use and we can use PKRU - * directly. - */ -void copy_init_pkru_to_fpregs(void) -{ - u32 init_pkru_value_snapshot = READ_ONCE(init_pkru_value); - /* - * Override the PKRU state that came from 'init_fpstate' - * with the baseline from the process. - */ - write_pkru(init_pkru_value_snapshot); -} - static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -154,7 +137,6 @@ static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf, static ssize_t init_pkru_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct pkru_state *pk; char buf[32]; ssize_t len; u32 new_init_pkru; @@ -177,10 +159,6 @@ static ssize_t init_pkru_write_file(struct file *file, return -EINVAL; WRITE_ONCE(init_pkru_value, new_init_pkru); - pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU); - if (!pk) - return -EINVAL; - pk->pkru = new_init_pkru; return count; } diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index de6bf0e7e8f8..758cbfe55daa 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -461,7 +461,7 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, } if (size < (16UL<<20) && size != old_size) - return 0; + return false; if (dev) dev_info(dev, "MMCONFIG at %pR reserved in %s\n", @@ -493,7 +493,7 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, &cfg->res, (unsigned long) cfg->address); } - return 1; + return true; } static bool __ref @@ -501,7 +501,7 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e { if (!early && !acpi_disabled) { if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0)) - return 1; + return true; if (dev) dev_info(dev, FW_INFO @@ -522,14 +522,14 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e * _CBA method, just assume it's reserved. */ if (pci_mmcfg_running_state) - return 1; + return true; /* Don't try to do this check unless configuration type 1 is available. how about type 2 ?*/ if (raw_pci_ops) return is_mmconf_reserved(e820__mapped_all, cfg, dev, 1); - return 0; + return false; } static void __init pci_mmcfg_reject_broken(int early) diff --git a/arch/xtensa/Kbuild b/arch/xtensa/Kbuild new file mode 100644 index 000000000000..a4e40e534e6a --- /dev/null +++ b/arch/xtensa/Kbuild @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-only diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 7b06a5fa3cac..575d7a2e7203 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -56,6 +56,8 @@ static LIST_HEAD(all_blkcgs); /* protected by blkcg_pol_mutex */ bool blkcg_debug_stats = false; static struct workqueue_struct *blkcg_punt_bio_wq; +#define BLKG_DESTROY_BATCH_SIZE 64 + static bool blkcg_policy_enabled(struct request_queue *q, const struct blkcg_policy *pol) { @@ -422,7 +424,9 @@ static void blkg_destroy(struct blkcg_gq *blkg) static void blkg_destroy_all(struct request_queue *q) { struct blkcg_gq *blkg, *n; + int count = BLKG_DESTROY_BATCH_SIZE; +restart: spin_lock_irq(&q->queue_lock); list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) { struct blkcg *blkcg = blkg->blkcg; @@ -430,6 +434,17 @@ static void blkg_destroy_all(struct request_queue *q) spin_lock(&blkcg->lock); blkg_destroy(blkg); spin_unlock(&blkcg->lock); + + /* + * in order to avoid holding the spin lock for too long, release + * it when a batch of blkgs are destroyed. + */ + if (!(--count)) { + count = BLKG_DESTROY_BATCH_SIZE; + spin_unlock_irq(&q->queue_lock); + cond_resched(); + goto restart; + } } q->root_blkg = NULL; diff --git a/block/blk-core.c b/block/blk-core.c index 514838ccab2d..04477697ee4b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -142,8 +142,6 @@ static const char *const blk_op_name[] = { REQ_OP_NAME(ZONE_APPEND), REQ_OP_NAME(WRITE_SAME), REQ_OP_NAME(WRITE_ZEROES), - REQ_OP_NAME(SCSI_IN), - REQ_OP_NAME(SCSI_OUT), REQ_OP_NAME(DRV_IN), REQ_OP_NAME(DRV_OUT), }; @@ -1243,7 +1241,7 @@ static void update_io_ticks(struct block_device *part, unsigned long now, unsigned long stamp; again: stamp = READ_ONCE(part->bd_stamp); - if (unlikely(stamp != now)) { + if (unlikely(time_after(now, stamp))) { if (likely(cmpxchg(&part->bd_stamp, stamp, now) == stamp)) __part_stat_add(part, io_ticks, end ? now - stamp : 1); } diff --git a/block/blk-exec.c b/block/blk-exec.c index beae70a0e5e5..d6cd501c0d34 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -21,7 +21,7 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error) { struct completion *waiting = rq->end_io_data; - rq->end_io_data = NULL; + rq->end_io_data = (void *)(uintptr_t)error; /* * complete last, if this is a stack request the process (and thus @@ -63,6 +63,19 @@ void blk_execute_rq_nowait(struct gendisk *bd_disk, struct request *rq, } EXPORT_SYMBOL_GPL(blk_execute_rq_nowait); +static bool blk_rq_is_poll(struct request *rq) +{ + return rq->mq_hctx && rq->mq_hctx->type == HCTX_TYPE_POLL; +} + +static void blk_rq_poll_completion(struct request *rq, struct completion *wait) +{ + do { + blk_poll(rq->q, request_to_qc_t(rq->mq_hctx, rq), true); + cond_resched(); + } while (!completion_done(wait)); +} + /** * blk_execute_rq - insert a request into queue for execution * @bd_disk: matching gendisk @@ -72,8 +85,9 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait); * Description: * Insert a fully prepared request at the back of the I/O scheduler queue * for execution and wait for completion. + * Return: The blk_status_t result provided to blk_mq_end_request(). */ -void blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head) +blk_status_t blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head) { DECLARE_COMPLETION_ONSTACK(wait); unsigned long hang_check; @@ -83,9 +97,14 @@ void blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head) /* Prevent hang_check timer from firing at us during very long I/O */ hang_check = sysctl_hung_task_timeout_secs; - if (hang_check) + + if (blk_rq_is_poll(rq)) + blk_rq_poll_completion(rq, &wait); + else if (hang_check) while (!wait_for_completion_io_timeout(&wait, hang_check * (HZ/2))); else wait_for_completion_io(&wait); + + return (blk_status_t)(uintptr_t)rq->end_io_data; } EXPORT_SYMBOL(blk_execute_rq); diff --git a/block/blk-mq.c b/block/blk-mq.c index 2e9fd0ec63d7..2c4ac51e54eb 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -3109,7 +3109,7 @@ void blk_mq_release(struct request_queue *q) blk_mq_sysfs_deinit(q); } -struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, +static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, void *queuedata) { struct request_queue *q; @@ -3126,7 +3126,6 @@ struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, } return q; } -EXPORT_SYMBOL_GPL(blk_mq_init_queue_data); struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) { diff --git a/block/bsg-lib.c b/block/bsg-lib.c index cf1811261722..a89d80102304 100644 --- a/block/bsg-lib.c +++ b/block/bsg-lib.c @@ -45,7 +45,7 @@ static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, return PTR_ERR(job->request); if (hdr->dout_xfer_len && hdr->din_xfer_len) { - job->bidi_rq = blk_get_request(rq->q, REQ_OP_SCSI_IN, 0); + job->bidi_rq = blk_get_request(rq->q, REQ_OP_DRV_IN, 0); if (IS_ERR(job->bidi_rq)) { ret = PTR_ERR(job->bidi_rq); goto out; diff --git a/block/bsg.c b/block/bsg.c index 33e3f82ed03a..1f196563ae6c 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -154,7 +154,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) return ret; rq = blk_get_request(q, hdr.dout_xfer_len ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) return PTR_ERR(rq); diff --git a/block/genhd.c b/block/genhd.c index 79aa40b4c39c..af4d2ab4a633 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -365,12 +365,12 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action) xa_for_each(&disk->part_tbl, idx, part) { if (bdev_is_partition(part) && !bdev_nr_sectors(part)) continue; - if (!bdgrab(part)) + if (!kobject_get_unless_zero(&part->bd_device.kobj)) continue; rcu_read_unlock(); kobject_uevent(bdev_kobj(part), action); - bdput(part); + put_device(&part->bd_device); rcu_read_lock(); } rcu_read_unlock(); diff --git a/block/partitions/core.c b/block/partitions/core.c index 347c56a51d87..4230d4f71879 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -453,17 +453,26 @@ int bdev_add_partition(struct block_device *bdev, int partno, sector_t start, sector_t length) { struct block_device *part; + struct gendisk *disk = bdev->bd_disk; + int ret; - mutex_lock(&bdev->bd_disk->open_mutex); - if (partition_overlaps(bdev->bd_disk, start, length, -1)) { - mutex_unlock(&bdev->bd_disk->open_mutex); - return -EBUSY; + mutex_lock(&disk->open_mutex); + if (!(disk->flags & GENHD_FL_UP)) { + ret = -ENXIO; + goto out; } - part = add_partition(bdev->bd_disk, partno, start, length, + if (partition_overlaps(disk, start, length, -1)) { + ret = -EBUSY; + goto out; + } + + part = add_partition(disk, partno, start, length, ADDPART_FLAG_NONE, NULL); - mutex_unlock(&bdev->bd_disk->open_mutex); - return PTR_ERR_OR_ZERO(part); + ret = PTR_ERR_OR_ZERO(part); +out: + mutex_unlock(&disk->open_mutex); + return ret; } int bdev_del_partition(struct block_device *bdev, int partno) @@ -537,12 +546,8 @@ void blk_drop_partitions(struct gendisk *disk) lockdep_assert_held(&disk->open_mutex); - xa_for_each_start(&disk->part_tbl, idx, part, 1) { - if (!bdgrab(part)) - continue; + xa_for_each_start(&disk->part_tbl, idx, part, 1) delete_partition(part); - bdput(part); - } } static bool blk_add_partition(struct gendisk *disk, diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index fa6df11b8bdd..d247431a6853 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -313,7 +313,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, at_head = 1; ret = -ENOMEM; - rq = blk_get_request(q, writing ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + rq = blk_get_request(q, writing ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) return PTR_ERR(rq); req = scsi_req(rq); @@ -435,7 +435,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, } - rq = blk_get_request(q, in_len ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + rq = blk_get_request(q, in_len ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto error_free_buffer; @@ -524,7 +524,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, struct request *rq; int err; - rq = blk_get_request(q, REQ_OP_SCSI_OUT, 0); + rq = blk_get_request(q, REQ_OP_DRV_OUT, 0); if (IS_ERR(rq)) return PTR_ERR(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 1f7f63e836ae..c978e41f11a1 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4686,8 +4686,11 @@ static const struct alg_test_desc alg_test_descs[] = { .test = alg_test_null, }, { .alg = "drbg_nopr_hmac_sha512", - .test = alg_test_null, + .test = alg_test_drbg, .fips_allowed = 1, + .suite = { + .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) + } }, { .alg = "drbg_nopr_sha1", .fips_allowed = 1, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 96eb7ce9f81b..3ed6ab34ab51 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -21984,6 +21984,55 @@ static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { }, }; +/* Test vector obtained during NIST ACVP testing */ +static const struct drbg_testvec drbg_nopr_hmac_sha512_tv_template[] = { + { + .entropy = (unsigned char *) + "\xDF\xB0\xF2\x18\xF0\x78\x07\x01\x29\xA4\x29\x26" + "\x2F\x8A\x34\xCB\x37\xEF\xEE\x41\xE6\x96\xF7\xFF" + "\x61\x47\xD3\xED\x41\x97\xEF\x64\x0C\x48\x56\x5A" + "\xE6\x40\x6E\x4A\x3B\x9E\x7F\xAC\x08\xEC\x25\xAE" + "\x0B\x51\x0E\x2C\x44\x2E\xBD\xDB\x57\xD0\x4A\x6D" + "\x80\x3E\x37\x0F", + .entropylen = 64, + .expected = (unsigned char *) + "\x48\xc6\xa8\xdb\x09\xae\xde\x5d\x8c\x77\xf3\x52" + "\x92\x71\xa7\xb9\x6d\x53\x6d\xa3\x73\xe3\x55\xb8" + "\x39\xd6\x44\x2b\xee\xcb\xe1\x32\x15\x30\xbe\x4e" + "\x9b\x1e\x06\xd1\x6b\xbf\xd5\x3e\xea\x7c\xf5\xaa" + "\x4b\x05\xb5\xd3\xa7\xb2\xc4\xfe\xe7\x1b\xda\x11" + "\x43\x98\x03\x70\x90\xbf\x6e\x43\x9b\xe4\x14\xef" + "\x71\xa3\x2a\xef\x9f\x0d\xb9\xe3\x52\xf2\x89\xc9" + "\x66\x9a\x60\x60\x99\x60\x62\x4c\xd6\x45\x52\x54" + "\xe6\x32\xb2\x1b\xd4\x48\xb5\xa6\xf9\xba\xd3\xff" + "\x29\xc5\x21\xe0\x91\x31\xe0\x38\x8c\x93\x0f\x3c" + "\x30\x7b\x53\xa3\xc0\x7f\x2d\xc1\x39\xec\x69\x0e" + "\xf2\x4a\x3c\x65\xcc\xed\x07\x2a\xf2\x33\x83\xdb" + "\x10\x74\x96\x40\xa7\xc5\x1b\xde\x81\xca\x0b\x8f" + "\x1e\x0a\x1a\x7a\xbf\x3c\x4a\xb8\x8c\xaf\x7b\x80" + "\xb7\xdc\x5d\x0f\xef\x1b\x97\x6e\x3d\x17\x23\x5a" + "\x31\xb9\x19\xcf\x5a\xc5\x00\x2a\xb6\xf3\x99\x34" + "\x65\xee\xe9\x1c\x55\xa0\x3b\x07\x60\xc9\xc4\xe4" + "\xf7\x57\x5c\x34\x9f\xc6\x31\x30\x3f\x23\xb2\x89" + "\xc0\xe7\x50\xf3\xde\x59\xd1\x0e\xb3\x0f\x78\xcc" + "\x7e\x54\x5e\x61\xf6\x86\x3d\xb3\x11\x94\x36\x3e" + "\x61\x5c\x48\x99\xf6\x7b\x02\x9a\xdc\x6a\x28\xe6" + "\xd1\xa7\xd1\xa3", + .expectedlen = 256, + .addtla = (unsigned char *) + "\x6B\x0F\x4A\x48\x0B\x12\x85\xE4\x72\x23\x7F\x7F" + "\x94\x7C\x24\x69\x14\x9F\xDC\x72\xA6\x33\xAD\x3C" + "\x8C\x72\xC1\x88\x49\x59\x82\xC5", + .addtlb = (unsigned char *) + "\xC4\xAF\x36\x3D\xB8\x5D\x9D\xFA\x92\xF5\xC3\x3C" + "\x2D\x1E\x22\x2A\xBD\x8B\x05\x6F\xA3\xFC\xBF\x16" + "\xED\xAA\x75\x8D\x73\x9A\xF6\xEC", + .addtllen = 32, + .pers = NULL, + .perslen = 0, + } +}; + static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { { .entropy = (unsigned char *) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fe0bb6277e4d..9d872ea477a6 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -551,3 +551,13 @@ config ACPI_PRMT bool "Platform Runtime Mechanism Support" depends on EFI && X86_64 default y + help + Platform Runtime Mechanism (PRM) is a firmware interface exposing a + set of binary executables that can be called from the AML interpreter + or directly from device drivers. + + Say Y to enable the AML interpreter to execute the PRM code. + + While this feature is optional in principle, leaving it out may + substantially increase computational overhead related to the + initialization of some server systems. diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c index 49b781a9cd97..ab8a4e0191b1 100644 --- a/drivers/acpi/acpi_amba.c +++ b/drivers/acpi/acpi_amba.c @@ -76,6 +76,7 @@ static int amba_handler_attach(struct acpi_device *adev, case IORESOURCE_MEM: if (!address_found) { dev->res = *rentry->res; + dev->res.name = dev_name(&dev->dev); address_found = true; } break; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index ffb4afc5aad9..42ede059728c 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -540,6 +540,15 @@ static const struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), }, }, + { + .callback = video_set_report_key_events, + .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS), + .ident = "Dell Vostro 3350", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), + }, + }, /* * Some machines change the brightness themselves when a brightness * hotkey gets pressed, despite us telling them not to. In this case diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ee24246d88fd..f854bcb8d010 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -304,7 +304,8 @@ static void acpi_bus_osc_negotiate_platform_control(void) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT; - capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PRM_SUPPORT; + if (IS_ENABLED(CONFIG_ACPI_PRMT)) + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PRM_SUPPORT; #ifdef CONFIG_ARM64 capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT; diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 816bf2c34b7a..1c507804fb10 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -417,11 +417,15 @@ static int lps0_device_attach(struct acpi_device *adev, mem_sleep_current = PM_SUSPEND_TO_IDLE; /* - * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the - * EC GPE to be enabled while suspended for certain wakeup devices to - * work, so mark it as wakeup-capable. + * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't + * use intel-hid or intel-vbtn but require the EC GPE to be enabled while + * suspended for certain wakeup devices to work, so mark it as wakeup-capable. + * + * Only enable on !AMD as enabling this universally causes problems for a number + * of AMD based systems. */ - acpi_ec_mark_gpe_for_wake(); + if (!acpi_s2idle_vendor_amd()) + acpi_ec_mark_gpe_for_wake(); return 0; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b7a5abee2147..a7da8ea7b3ed 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -1058,7 +1058,7 @@ config PATA_ISAPNP config PATA_IXP4XX_CF tristate "IXP4XX Compact Flash support" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX || COMPILE_TEST help This option enables support for a Compact Flash connected on the ixp4xx expansion bus. This driver had been written for diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 43215a4c1e54..5881d64af943 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define DRV_NAME "pata_ixp4xx_cf" diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index e74219436fbb..72e44cf21297 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -18,11 +18,12 @@ #include #include #include +#include #include #include #include -static DEFINE_PER_CPU(struct scale_freq_data *, sft_data); +static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data); static struct cpumask scale_freq_counters_mask; static bool scale_freq_invariant; @@ -67,16 +68,20 @@ void topology_set_scale_freq_source(struct scale_freq_data *data, if (cpumask_empty(&scale_freq_counters_mask)) scale_freq_invariant = topology_scale_freq_invariant(); + rcu_read_lock(); + for_each_cpu(cpu, cpus) { - sfd = per_cpu(sft_data, cpu); + sfd = rcu_dereference(*per_cpu_ptr(&sft_data, cpu)); /* Use ARCH provided counters whenever possible */ if (!sfd || sfd->source != SCALE_FREQ_SOURCE_ARCH) { - per_cpu(sft_data, cpu) = data; + rcu_assign_pointer(per_cpu(sft_data, cpu), data); cpumask_set_cpu(cpu, &scale_freq_counters_mask); } } + rcu_read_unlock(); + update_scale_freq_invariant(true); } EXPORT_SYMBOL_GPL(topology_set_scale_freq_source); @@ -87,22 +92,32 @@ void topology_clear_scale_freq_source(enum scale_freq_source source, struct scale_freq_data *sfd; int cpu; + rcu_read_lock(); + for_each_cpu(cpu, cpus) { - sfd = per_cpu(sft_data, cpu); + sfd = rcu_dereference(*per_cpu_ptr(&sft_data, cpu)); if (sfd && sfd->source == source) { - per_cpu(sft_data, cpu) = NULL; + rcu_assign_pointer(per_cpu(sft_data, cpu), NULL); cpumask_clear_cpu(cpu, &scale_freq_counters_mask); } } + rcu_read_unlock(); + + /* + * Make sure all references to previous sft_data are dropped to avoid + * use-after-free races. + */ + synchronize_rcu(); + update_scale_freq_invariant(false); } EXPORT_SYMBOL_GPL(topology_clear_scale_freq_source); void topology_scale_freq_tick(void) { - struct scale_freq_data *sfd = *this_cpu_ptr(&sft_data); + struct scale_freq_data *sfd = rcu_dereference_sched(*this_cpu_ptr(&sft_data)); if (sfd) sfd->set_freq_scale(); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index ab0b740cc0f1..a934c679e6ce 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2018,8 +2018,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); - genpd_debug_add(genpd); mutex_unlock(&gpd_list_lock); + genpd_debug_add(genpd); return 0; } @@ -2206,12 +2206,19 @@ static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, static bool genpd_present(const struct generic_pm_domain *genpd) { + bool ret = false; const struct generic_pm_domain *gpd; - list_for_each_entry(gpd, &gpd_list, gpd_list_node) - if (gpd == genpd) - return true; - return false; + mutex_lock(&gpd_list_lock); + list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + if (gpd == genpd) { + ret = true; + break; + } + } + mutex_unlock(&gpd_list_lock); + + return ret; } /** @@ -2222,15 +2229,13 @@ static bool genpd_present(const struct generic_pm_domain *genpd) int of_genpd_add_provider_simple(struct device_node *np, struct generic_pm_domain *genpd) { - int ret = -EINVAL; + int ret; if (!np || !genpd) return -EINVAL; - mutex_lock(&gpd_list_lock); - if (!genpd_present(genpd)) - goto unlock; + return -EINVAL; genpd->dev.of_node = np; @@ -2241,7 +2246,7 @@ int of_genpd_add_provider_simple(struct device_node *np, if (ret != -EPROBE_DEFER) dev_err(&genpd->dev, "Failed to add OPP table: %d\n", ret); - goto unlock; + return ret; } /* @@ -2259,16 +2264,13 @@ int of_genpd_add_provider_simple(struct device_node *np, dev_pm_opp_of_remove_table(&genpd->dev); } - goto unlock; + return ret; } genpd->provider = &np->fwnode; genpd->has_provider = true; -unlock: - mutex_unlock(&gpd_list_lock); - - return ret; + return 0; } EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple); @@ -2287,8 +2289,6 @@ int of_genpd_add_provider_onecell(struct device_node *np, if (!np || !data) return -EINVAL; - mutex_lock(&gpd_list_lock); - if (!data->xlate) data->xlate = genpd_xlate_onecell; @@ -2328,8 +2328,6 @@ int of_genpd_add_provider_onecell(struct device_node *np, if (ret < 0) goto error; - mutex_unlock(&gpd_list_lock); - return 0; error: @@ -2348,8 +2346,6 @@ error: } } - mutex_unlock(&gpd_list_lock); - return ret; } EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 920f1619c5e7..1c94f3068391 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -221,16 +221,13 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime, void *cb, int error) { ktime_t rettime; - s64 nsecs; if (!pm_print_times_enabled) return; rettime = ktime_get(); - nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); - dev_info(dev, "%pS returned %d after %Ld usecs\n", cb, error, - (unsigned long long)nsecs >> 10); + (unsigned long long)ktime_us_delta(rettime, calltime)); } /** diff --git a/drivers/block/loop.c b/drivers/block/loop.c index cc0e8c39a48b..f37b9e3d833c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1434,7 +1434,6 @@ static int loop_set_status(struct loop_device *lo, const struct loop_info64 *info) { int err; - struct block_device *bdev; kuid_t uid = current_uid(); int prev_lo_flags; bool partscan = false; @@ -1503,7 +1502,6 @@ out_unfreeze: if (!err && (lo->lo_flags & LO_FLAGS_PARTSCAN) && !(prev_lo_flags & LO_FLAGS_PARTSCAN)) { lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; - bdev = lo->lo_device; partscan = true; } out_unlock: @@ -2237,7 +2235,7 @@ static const struct blk_mq_ops loop_mq_ops = { .complete = lo_complete_rq, }; -static int loop_add(struct loop_device **l, int i) +static int loop_add(int i) { struct loop_device *lo; struct gendisk *disk; @@ -2247,9 +2245,12 @@ static int loop_add(struct loop_device **l, int i) lo = kzalloc(sizeof(*lo), GFP_KERNEL); if (!lo) goto out; - lo->lo_state = Lo_unbound; + err = mutex_lock_killable(&loop_ctl_mutex); + if (err) + goto out_free_dev; + /* allocate id, if @id >= 0, we're requesting that specific id */ if (i >= 0) { err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL); @@ -2259,7 +2260,7 @@ static int loop_add(struct loop_device **l, int i) err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL); } if (err < 0) - goto out_free_dev; + goto out_unlock; i = err; err = -ENOMEM; @@ -2326,13 +2327,15 @@ static int loop_add(struct loop_device **l, int i) disk->queue = lo->lo_queue; sprintf(disk->disk_name, "loop%d", i); add_disk(disk); - *l = lo; - return lo->lo_number; + mutex_unlock(&loop_ctl_mutex); + return i; out_cleanup_tags: blk_mq_free_tag_set(&lo->tag_set); out_free_idr: idr_remove(&loop_index_idr, i); +out_unlock: + mutex_unlock(&loop_ctl_mutex); out_free_dev: kfree(lo); out: @@ -2348,109 +2351,86 @@ static void loop_remove(struct loop_device *lo) kfree(lo); } -static int find_free_cb(int id, void *ptr, void *data) -{ - struct loop_device *lo = ptr; - struct loop_device **l = data; - - if (lo->lo_state == Lo_unbound) { - *l = lo; - return 1; - } - return 0; -} - -static int loop_lookup(struct loop_device **l, int i) -{ - struct loop_device *lo; - int ret = -ENODEV; - - if (i < 0) { - int err; - - err = idr_for_each(&loop_index_idr, &find_free_cb, &lo); - if (err == 1) { - *l = lo; - ret = lo->lo_number; - } - goto out; - } - - /* lookup and return a specific i */ - lo = idr_find(&loop_index_idr, i); - if (lo) { - *l = lo; - ret = lo->lo_number; - } -out: - return ret; -} - static void loop_probe(dev_t dev) { int idx = MINOR(dev) >> part_shift; - struct loop_device *lo; if (max_loop && idx >= max_loop) return; + loop_add(idx); +} - mutex_lock(&loop_ctl_mutex); - if (loop_lookup(&lo, idx) < 0) - loop_add(&lo, idx); +static int loop_control_remove(int idx) +{ + struct loop_device *lo; + int ret; + + if (idx < 0) { + pr_warn("deleting an unspecified loop device is not supported.\n"); + return -EINVAL; + } + + ret = mutex_lock_killable(&loop_ctl_mutex); + if (ret) + return ret; + + lo = idr_find(&loop_index_idr, idx); + if (!lo) { + ret = -ENODEV; + goto out_unlock_ctrl; + } + + ret = mutex_lock_killable(&lo->lo_mutex); + if (ret) + goto out_unlock_ctrl; + if (lo->lo_state != Lo_unbound || + atomic_read(&lo->lo_refcnt) > 0) { + mutex_unlock(&lo->lo_mutex); + ret = -EBUSY; + goto out_unlock_ctrl; + } + lo->lo_state = Lo_deleting; + mutex_unlock(&lo->lo_mutex); + + idr_remove(&loop_index_idr, lo->lo_number); + loop_remove(lo); +out_unlock_ctrl: mutex_unlock(&loop_ctl_mutex); + return ret; +} + +static int loop_control_get_free(int idx) +{ + struct loop_device *lo; + int id, ret; + + ret = mutex_lock_killable(&loop_ctl_mutex); + if (ret) + return ret; + idr_for_each_entry(&loop_index_idr, lo, id) { + if (lo->lo_state == Lo_unbound) + goto found; + } + mutex_unlock(&loop_ctl_mutex); + return loop_add(-1); +found: + mutex_unlock(&loop_ctl_mutex); + return id; } static long loop_control_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { - struct loop_device *lo; - int ret; - - ret = mutex_lock_killable(&loop_ctl_mutex); - if (ret) - return ret; - - ret = -ENOSYS; switch (cmd) { case LOOP_CTL_ADD: - ret = loop_lookup(&lo, parm); - if (ret >= 0) { - ret = -EEXIST; - break; - } - ret = loop_add(&lo, parm); - break; + return loop_add(parm); case LOOP_CTL_REMOVE: - ret = loop_lookup(&lo, parm); - if (ret < 0) - break; - ret = mutex_lock_killable(&lo->lo_mutex); - if (ret) - break; - if (lo->lo_state != Lo_unbound) { - ret = -EBUSY; - mutex_unlock(&lo->lo_mutex); - break; - } - if (atomic_read(&lo->lo_refcnt) > 0) { - ret = -EBUSY; - mutex_unlock(&lo->lo_mutex); - break; - } - lo->lo_state = Lo_deleting; - mutex_unlock(&lo->lo_mutex); - idr_remove(&loop_index_idr, lo->lo_number); - loop_remove(lo); - break; + return loop_control_remove(parm); case LOOP_CTL_GET_FREE: - ret = loop_lookup(&lo, -1); - if (ret >= 0) - break; - ret = loop_add(&lo, -1); + return loop_control_get_free(parm); + default: + return -ENOSYS; } - mutex_unlock(&loop_ctl_mutex); - - return ret; } static const struct file_operations loop_ctl_fops = { @@ -2473,7 +2453,6 @@ MODULE_ALIAS("devname:loop-control"); static int __init loop_init(void) { int i, nr; - struct loop_device *lo; int err; part_shift = 0; @@ -2525,10 +2504,8 @@ static int __init loop_init(void) } /* pre-create number of devices given by config or max_loop */ - mutex_lock(&loop_ctl_mutex); for (i = 0; i < nr; i++) - loop_add(&lo, i); - mutex_unlock(&loop_ctl_mutex); + loop_add(i); printk(KERN_INFO "loop: module loaded\n"); return 0; @@ -2539,26 +2516,20 @@ err_out: return err; } -static int loop_exit_cb(int id, void *ptr, void *data) -{ - struct loop_device *lo = ptr; - - loop_remove(lo); - return 0; -} - static void __exit loop_exit(void) { - mutex_lock(&loop_ctl_mutex); - - idr_for_each(&loop_index_idr, &loop_exit_cb, NULL); - idr_destroy(&loop_index_idr); + struct loop_device *lo; + int id; unregister_blkdev(LOOP_MAJOR, "loop"); - misc_deregister(&loop_misc); + mutex_lock(&loop_ctl_mutex); + idr_for_each_entry(&loop_index_idr, lo, id) + loop_remove(lo); mutex_unlock(&loop_ctl_mutex); + + idr_destroy(&loop_index_idr); } module_init(loop_init); diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index ff3e7b3f5ad8..901855717cb5 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -2160,6 +2160,20 @@ static ssize_t mtip_hw_show_status(struct device *dev, static DEVICE_ATTR(status, 0444, mtip_hw_show_status, NULL); +static struct attribute *mtip_disk_attrs[] = { + &dev_attr_status.attr, + NULL, +}; + +static const struct attribute_group mtip_disk_attr_group = { + .attrs = mtip_disk_attrs, +}; + +static const struct attribute_group *mtip_disk_attr_groups[] = { + &mtip_disk_attr_group, + NULL, +}; + /* debugsfs entries */ static ssize_t show_device_status(struct device_driver *drv, char *buf) @@ -2374,47 +2388,6 @@ static const struct file_operations mtip_flags_fops = { .llseek = no_llseek, }; -/* - * Create the sysfs related attributes. - * - * @dd Pointer to the driver data structure. - * @kobj Pointer to the kobj for the block device. - * - * return value - * 0 Operation completed successfully. - * -EINVAL Invalid parameter. - */ -static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) -{ - if (!kobj || !dd) - return -EINVAL; - - if (sysfs_create_file(kobj, &dev_attr_status.attr)) - dev_warn(&dd->pdev->dev, - "Error creating 'status' sysfs entry\n"); - return 0; -} - -/* - * Remove the sysfs related attributes. - * - * @dd Pointer to the driver data structure. - * @kobj Pointer to the kobj for the block device. - * - * return value - * 0 Operation completed successfully. - * -EINVAL Invalid parameter. - */ -static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) -{ - if (!kobj || !dd) - return -EINVAL; - - sysfs_remove_file(kobj, &dev_attr_status.attr); - - return 0; -} - static int mtip_hw_debugfs_init(struct driver_data *dd) { if (!dfs_parent) @@ -3566,7 +3539,6 @@ static int mtip_block_initialize(struct driver_data *dd) int rv = 0, wait_for_rebuild = 0; sector_t capacity; unsigned int index = 0; - struct kobject *kobj; if (dd->disk) goto skip_create_disk; /* hw init done, before rebuild */ @@ -3576,14 +3548,33 @@ static int mtip_block_initialize(struct driver_data *dd) goto protocol_init_error; } - dd->disk = alloc_disk_node(MTIP_MAX_MINORS, dd->numa_node); - if (dd->disk == NULL) { + memset(&dd->tags, 0, sizeof(dd->tags)); + dd->tags.ops = &mtip_mq_ops; + dd->tags.nr_hw_queues = 1; + dd->tags.queue_depth = MTIP_MAX_COMMAND_SLOTS; + dd->tags.reserved_tags = 1; + dd->tags.cmd_size = sizeof(struct mtip_cmd); + dd->tags.numa_node = dd->numa_node; + dd->tags.flags = BLK_MQ_F_SHOULD_MERGE; + dd->tags.driver_data = dd; + dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS; + + rv = blk_mq_alloc_tag_set(&dd->tags); + if (rv) { dev_err(&dd->pdev->dev, - "Unable to allocate gendisk structure\n"); - rv = -EINVAL; - goto alloc_disk_error; + "Unable to allocate request queue\n"); + goto block_queue_alloc_tag_error; } + dd->disk = blk_mq_alloc_disk(&dd->tags, dd); + if (IS_ERR(dd->disk)) { + dev_err(&dd->pdev->dev, + "Unable to allocate request queue\n"); + rv = -ENOMEM; + goto block_queue_alloc_init_error; + } + dd->queue = dd->disk->queue; + rv = ida_alloc(&rssd_index_ida, GFP_KERNEL); if (rv < 0) goto ida_get_error; @@ -3605,36 +3596,6 @@ static int mtip_block_initialize(struct driver_data *dd) mtip_hw_debugfs_init(dd); - memset(&dd->tags, 0, sizeof(dd->tags)); - dd->tags.ops = &mtip_mq_ops; - dd->tags.nr_hw_queues = 1; - dd->tags.queue_depth = MTIP_MAX_COMMAND_SLOTS; - dd->tags.reserved_tags = 1; - dd->tags.cmd_size = sizeof(struct mtip_cmd); - dd->tags.numa_node = dd->numa_node; - dd->tags.flags = BLK_MQ_F_SHOULD_MERGE; - dd->tags.driver_data = dd; - dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS; - - rv = blk_mq_alloc_tag_set(&dd->tags); - if (rv) { - dev_err(&dd->pdev->dev, - "Unable to allocate request queue\n"); - goto block_queue_alloc_tag_error; - } - - /* Allocate the request queue. */ - dd->queue = blk_mq_init_queue(&dd->tags); - if (IS_ERR(dd->queue)) { - dev_err(&dd->pdev->dev, - "Unable to allocate request queue\n"); - rv = -ENOMEM; - goto block_queue_alloc_init_error; - } - - dd->disk->queue = dd->queue; - dd->queue->queuedata = dd; - skip_create_disk: /* Initialize the protocol layer. */ wait_for_rebuild = mtip_hw_get_identify(dd); @@ -3672,17 +3633,7 @@ skip_create_disk: set_capacity(dd->disk, capacity); /* Enable the block device and add it to /dev */ - device_add_disk(&dd->pdev->dev, dd->disk, NULL); - - /* - * Now that the disk is active, initialize any sysfs attributes - * managed by the protocol layer. - */ - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); - if (kobj) { - mtip_hw_sysfs_init(dd, kobj); - kobject_put(kobj); - } + device_add_disk(&dd->pdev->dev, dd->disk, mtip_disk_attr_groups); if (dd->mtip_svc_handler) { set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); @@ -3709,23 +3660,17 @@ start_service_thread: kthread_run_error: /* Delete our gendisk. This also removes the device from /dev */ del_gendisk(dd->disk); - read_capacity_error: init_hw_cmds_error: - blk_cleanup_queue(dd->queue); -block_queue_alloc_init_error: - blk_mq_free_tag_set(&dd->tags); -block_queue_alloc_tag_error: mtip_hw_debugfs_exit(dd); disk_index_error: ida_free(&rssd_index_ida, index); - ida_get_error: - put_disk(dd->disk); - -alloc_disk_error: + blk_cleanup_disk(dd->disk); +block_queue_alloc_init_error: + blk_mq_free_tag_set(&dd->tags); +block_queue_alloc_tag_error: mtip_hw_exit(dd); /* De-initialize the protocol layer. */ - protocol_init_error: return rv; } @@ -3751,8 +3696,6 @@ static bool mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv) */ static int mtip_block_remove(struct driver_data *dd) { - struct kobject *kobj; - mtip_hw_debugfs_exit(dd); if (dd->mtip_svc_handler) { @@ -3761,15 +3704,6 @@ static int mtip_block_remove(struct driver_data *dd) kthread_stop(dd->mtip_svc_handler); } - /* Clean up the sysfs attributes, if created */ - if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); - if (kobj) { - mtip_hw_sysfs_exit(dd, kobj); - kobject_put(kobj); - } - } - if (!dd->sr) { /* * Explicitly wait here for IOs to quiesce, diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 614d82e7fae4..b7d663736d35 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -79,6 +79,7 @@ struct link_dead_args { #define NBD_RT_HAS_CONFIG_REF 4 #define NBD_RT_BOUND 5 #define NBD_RT_DISCONNECT_ON_CLOSE 6 +#define NBD_RT_HAS_BACKEND_FILE 7 #define NBD_DESTROY_ON_DISCONNECT 0 #define NBD_DISCONNECT_REQUESTED 1 @@ -119,6 +120,8 @@ struct nbd_device { struct completion *destroy_complete; unsigned long flags; + + char *backend; }; #define NBD_CMD_REQUEUED 1 @@ -216,6 +219,20 @@ static const struct device_attribute pid_attr = { .show = pid_show, }; +static ssize_t backend_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + struct nbd_device *nbd = (struct nbd_device *)disk->private_data; + + return sprintf(buf, "%s\n", nbd->backend ?: ""); +} + +static const struct device_attribute backend_attr = { + .attr = { .name = "backend", .mode = 0444}, + .show = backend_show, +}; + static void nbd_dev_remove(struct nbd_device *nbd) { struct gendisk *disk = nbd->disk; @@ -1211,6 +1228,12 @@ static void nbd_config_put(struct nbd_device *nbd) &config->runtime_flags)) device_remove_file(disk_to_dev(nbd->disk), &pid_attr); nbd->task_recv = NULL; + if (test_and_clear_bit(NBD_RT_HAS_BACKEND_FILE, + &config->runtime_flags)) { + device_remove_file(disk_to_dev(nbd->disk), &backend_attr); + kfree(nbd->backend); + nbd->backend = NULL; + } nbd_clear_sock(nbd); if (config->num_connections) { int i; @@ -1270,7 +1293,7 @@ static int nbd_start_device(struct nbd_device *nbd) error = device_create_file(disk_to_dev(nbd->disk), &pid_attr); if (error) { - dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n"); + dev_err(disk_to_dev(nbd->disk), "device_create_file failed for pid!\n"); return error; } set_bit(NBD_RT_HAS_PID_FILE, &config->runtime_flags); @@ -1657,6 +1680,7 @@ static int nbd_dev_add(int index) BLK_MQ_F_BLOCKING; nbd->tag_set.driver_data = nbd; nbd->destroy_complete = NULL; + nbd->backend = NULL; err = blk_mq_alloc_tag_set(&nbd->tag_set); if (err) @@ -1743,6 +1767,7 @@ static const struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = { [NBD_ATTR_SOCKETS] = { .type = NLA_NESTED}, [NBD_ATTR_DEAD_CONN_TIMEOUT] = { .type = NLA_U64 }, [NBD_ATTR_DEVICE_LIST] = { .type = NLA_NESTED}, + [NBD_ATTR_BACKEND_IDENTIFIER] = { .type = NLA_STRING}, }; static const struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = { @@ -1945,6 +1970,23 @@ again: } } ret = nbd_start_device(nbd); + if (ret) + goto out; + if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) { + nbd->backend = nla_strdup(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER], + GFP_KERNEL); + if (!nbd->backend) { + ret = -ENOMEM; + goto out; + } + } + ret = device_create_file(disk_to_dev(nbd->disk), &backend_attr); + if (ret) { + dev_err(disk_to_dev(nbd->disk), + "device_create_file failed for backend!\n"); + goto out; + } + set_bit(NBD_RT_HAS_BACKEND_FILE, &config->runtime_flags); out: mutex_unlock(&nbd->config_lock); if (!ret) { @@ -2037,6 +2079,22 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) index); return -EINVAL; } + if (nbd->backend) { + if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) { + if (nla_strcmp(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER], + nbd->backend)) { + mutex_unlock(&nbd_index_mutex); + dev_err(nbd_to_dev(nbd), + "backend image doesn't match with %s\n", + nbd->backend); + return -EINVAL; + } + } else { + mutex_unlock(&nbd_index_mutex); + dev_err(nbd_to_dev(nbd), "must specify backend\n"); + return -EINVAL; + } + } if (!refcount_inc_not_zero(&nbd->refs)) { mutex_unlock(&nbd_index_mutex); printk(KERN_ERR "nbd: device at index %d is going down\n", diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index 3b320b005aa8..d734e9ee1546 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -1849,7 +1849,6 @@ static int null_add_dev(struct nullb_device *dev) if (!null_setup_fault()) goto out_cleanup_tags; - rv = -ENOMEM; nullb->tag_set->timeout = 5 * HZ; nullb->disk = blk_mq_alloc_disk(nullb->tag_set, nullb); if (IS_ERR(nullb->disk)) { diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index f69b5c69c2a6..538446b652de 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -704,7 +704,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * int ret = 0; rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) return PTR_ERR(rq); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index b1dcff284b38..ca5f3e502411 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -21,6 +21,9 @@ #define VQ_NAME_LEN 16 #define MAX_DISCARD_SEGMENTS 256u +/* The maximum number of sg elements that fit into a virtqueue */ +#define VIRTIO_BLK_MAX_SG_ELEMS 32768 + static int major; static DEFINE_IDA(vd_index_ida); @@ -449,13 +452,6 @@ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) /* Host must always specify the capacity. */ virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity); - /* If capacity is too big, truncate with warning. */ - if ((sector_t)capacity != capacity) { - dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n", - (unsigned long long)capacity); - capacity = (sector_t)-1; - } - nblocks = DIV_ROUND_UP_ULL(capacity, queue_logical_block_size(q) >> 9); string_get_size(nblocks, queue_logical_block_size(q), @@ -730,7 +726,10 @@ static int virtblk_probe(struct virtio_device *vdev) if (err || !sg_elems) sg_elems = 1; - /* We need an extra sg elements at head and tail. */ + /* Prevent integer overflows and honor max vq size */ + sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2); + + /* We need extra sg elements at head and tail. */ sg_elems += 2; vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); if (!vblk) { @@ -938,6 +937,8 @@ static int virtblk_freeze(struct virtio_device *vdev) blk_mq_quiesce_queue(vblk->disk->queue); vdev->config->del_vqs(vdev); + kfree(vblk->vqs); + return 0; } diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c index 0b8f53a688b8..663c82749222 100644 --- a/drivers/bus/qcom-ebi2.c +++ b/drivers/bus/qcom-ebi2.c @@ -102,8 +102,8 @@ /** * struct cs_data - struct with info on a chipselect setting * @enable_mask: mask to enable the chipselect in the EBI2 config - * @slow_cfg0: offset to XMEMC slow CS config - * @fast_cfg1: offset to XMEMC fast CS config + * @slow_cfg: offset to XMEMC slow CS config + * @fast_cfg: offset to XMEMC fast CS config */ struct cs_data { u32 enable_mask; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 90ad34c6ef8e..feb827eefd1a 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2186,7 +2186,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, len = nr * CD_FRAMESIZE_RAW; - rq = blk_get_request(q, REQ_OP_SCSI_IN, 0); + rq = blk_get_request(q, REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) { ret = PTR_ERR(rq); break; diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c11f12d4ab53..3f166c8a4099 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -152,7 +152,7 @@ config HW_RANDOM_VIA config HW_RANDOM_IXP4XX tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX || COMPILE_TEST default HW_RANDOM help This driver provides kernel-side support for the Pseudo-Random diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index beec1627db3c..188854dd16a9 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/char/hw_random/ixp4xx-rng.c * @@ -8,23 +9,20 @@ * Copyright 2005 (c) MontaVista Software, Inc. * * Fixes by Michael Buesch - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include #include #include +#include #include #include #include +#include +#include #include -#include - static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer) { @@ -40,35 +38,40 @@ static struct hwrng ixp4xx_rng_ops = { .data_read = ixp4xx_rng_data_read, }; -static int __init ixp4xx_rng_init(void) +static int ixp4xx_rng_probe(struct platform_device *pdev) { void __iomem * rng_base; - int err; + struct device *dev = &pdev->dev; + struct resource *res; if (!cpu_is_ixp46x()) /* includes IXP455 */ return -ENOSYS; - rng_base = ioremap(0x70002100, 4); - if (!rng_base) - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng_base = devm_ioremap_resource(dev, res); + if (IS_ERR(rng_base)) + return PTR_ERR(rng_base); + ixp4xx_rng_ops.priv = (unsigned long)rng_base; - err = hwrng_register(&ixp4xx_rng_ops); - if (err) - iounmap(rng_base); - - return err; + return devm_hwrng_register(dev, &ixp4xx_rng_ops); } -static void __exit ixp4xx_rng_exit(void) -{ - void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv; +static const struct of_device_id ixp4xx_rng_of_match[] = { + { + .compatible = "intel,ixp46x-rng", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ixp4xx_rng_of_match); - hwrng_unregister(&ixp4xx_rng_ops); - iounmap(rng_base); -} - -module_init(ixp4xx_rng_init); -module_exit(ixp4xx_rng_exit); +static struct platform_driver ixp4xx_rng_driver = { + .driver = { + .name = "ixp4xx-hwrandom", + .of_match_table = ixp4xx_rng_of_match, + }, + .probe = ixp4xx_rng_probe, +}; +module_platform_driver(ixp4xx_rng_driver); MODULE_AUTHOR("Deepak Saxena "); MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x"); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 59dfd9c421a1..7eaf303a7a86 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -475,7 +475,7 @@ static struct port_buffer *get_inbuf(struct port *port) buf = virtqueue_get_buf(port->in_vq, &len); if (buf) { - buf->len = len; + buf->len = min_t(size_t, len, buf->size); buf->offset = 0; port->stats.bytes_received += len; } @@ -1709,7 +1709,7 @@ static void control_work_handler(struct work_struct *work) while ((buf = virtqueue_get_buf(vq, &len))) { spin_unlock(&portdev->c_ivq_lock); - buf->len = len; + buf->len = min_t(size_t, len, buf->size); buf->offset = 0; handle_control_message(vq->vdev, portdev, buf); diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 344997203f0e..87ba4966b0e8 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -343,16 +343,63 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent, return bestdiv; } +int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req, + const struct clk_div_table *table, u8 width, + unsigned long flags) +{ + int div; + + div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate, + &req->best_parent_rate, table, width, flags); + + req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); + + return 0; +} +EXPORT_SYMBOL_GPL(divider_determine_rate); + +int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val) +{ + int div; + + div = _get_div(table, val, flags, width); + + /* Even a read-only clock can propagate a rate change */ + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + if (!req->best_parent_hw) + return -EINVAL; + + req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, + req->rate * div); + } + + req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); + + return 0; +} +EXPORT_SYMBOL_GPL(divider_ro_determine_rate); + long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, u8 width, unsigned long flags) { - int div; + struct clk_rate_request req = { + .rate = rate, + .best_parent_rate = *prate, + .best_parent_hw = parent, + }; + int ret; - div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags); + ret = divider_determine_rate(hw, &req, table, width, flags); + if (ret) + return ret; - return DIV_ROUND_UP_ULL((u64)*prate, div); + *prate = req.best_parent_rate; + + return req.rate; } EXPORT_SYMBOL_GPL(divider_round_rate_parent); @@ -361,23 +408,23 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, const struct clk_div_table *table, u8 width, unsigned long flags, unsigned int val) { - int div; + struct clk_rate_request req = { + .rate = rate, + .best_parent_rate = *prate, + .best_parent_hw = parent, + }; + int ret; - div = _get_div(table, val, flags, width); + ret = divider_ro_determine_rate(hw, &req, table, width, flags, val); + if (ret) + return ret; - /* Even a read-only clock can propagate a rate change */ - if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - if (!parent) - return -EINVAL; + *prate = req.best_parent_rate; - *prate = clk_hw_round_rate(parent, rate * div); - } - - return DIV_ROUND_UP_ULL((u64)*prate, div); + return req.rate; } EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); - static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c index 6c84abf5b2e3..67a7cb3503c3 100644 --- a/drivers/clk/clk-k210.c +++ b/drivers/clk/clk-k210.c @@ -722,6 +722,7 @@ static int k210_clk_set_parent(struct clk_hw *hw, u8 index) reg |= BIT(cfg->mux_bit); else reg &= ~BIT(cfg->mux_bit); + writel(reg, ksc->regs + cfg->mux_reg); spin_unlock_irqrestore(&ksc->clk_lock, flags); return 0; diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index c1095e733220..c7a3a029fb1e 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -519,7 +519,7 @@ static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate, vco_rate = lmk04832_calc_pll2_params(*prate, rate, &n, &p, &r); if (vco_rate < 0) { - dev_err(lmk->dev, "PLL2 parmeters out of range\n"); + dev_err(lmk->dev, "PLL2 parameters out of range\n"); return vco_rate; } @@ -550,7 +550,7 @@ static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, vco_rate = lmk04832_calc_pll2_params(prate, rate, &n, &p, &r); if (vco_rate < 0) { - dev_err(lmk->dev, "failed to determine PLL2 parmeters\n"); + dev_err(lmk->dev, "failed to determine PLL2 parameters\n"); return vco_rate; } @@ -573,7 +573,7 @@ static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, /* * PLL2_N registers must be programmed after other PLL2 dividers are - * programed to ensure proper VCO frequency calibration + * programmed to ensure proper VCO frequency calibration */ ret = regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_0, FIELD_GET(0x030000, n)); @@ -1120,7 +1120,7 @@ static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; } - /* Enable Duty Cycle Corretion */ + /* Enable Duty Cycle Correction */ if (dclk_div == 1) { ret = regmap_update_bits(lmk->regmap, LMK04832_REG_CLKOUT_CTRL3(dclk->id), @@ -1425,23 +1425,23 @@ static int lmk04832_probe(struct spi_device *spi) lmk->dclk = devm_kcalloc(lmk->dev, info->num_channels >> 1, sizeof(struct lmk_dclk), GFP_KERNEL); - if (IS_ERR(lmk->dclk)) { - ret = PTR_ERR(lmk->dclk); + if (!lmk->dclk) { + ret = -ENOMEM; goto err_disable_oscin; } lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels, sizeof(*lmk->clkout), GFP_KERNEL); - if (IS_ERR(lmk->clkout)) { - ret = PTR_ERR(lmk->clkout); + if (!lmk->clkout) { + ret = -ENOMEM; goto err_disable_oscin; } lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws, info->num_channels), GFP_KERNEL); - if (IS_ERR(lmk->clk_data)) { - ret = PTR_ERR(lmk->clk_data); + if (!lmk->clk_data) { + ret = -ENOMEM; goto err_disable_oscin; } diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 6adc625e79cb..256575bd29b9 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -2263,6 +2263,7 @@ static int stm32_rcc_reset_init(struct device *dev, void __iomem *base, if (!reset_data) return -ENOMEM; + spin_lock_init(&reset_data->lock); reset_data->membase = base; reset_data->rcdev.owner = THIS_MODULE; reset_data->rcdev.ops = &stm32_reset_ops; diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c index b1f19c43b558..56012a3d0219 100644 --- a/drivers/clk/hisilicon/clk-hi3559a.c +++ b/drivers/clk/hisilicon/clk-hi3559a.c @@ -107,25 +107,25 @@ static const struct hisi_fixed_rate_clock hi3559av100_fixed_rate_clks_crg[] = { }; -static const char *fmc_mux_p[] __initconst = { +static const char *fmc_mux_p[] = { "24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m" }; -static const char *mmc_mux_p[] __initconst = { +static const char *mmc_mux_p[] = { "100k", "25m", "49p5m", "99m", "187p5m", "150m", "198m", "400k" }; -static const char *sysapb_mux_p[] __initconst = { +static const char *sysapb_mux_p[] = { "24m", "50m", }; -static const char *sysbus_mux_p[] __initconst = { +static const char *sysbus_mux_p[] = { "24m", "300m" }; -static const char *uart_mux_p[] __initconst = { "50m", "24m", "3m" }; +static const char *uart_mux_p[] = { "50m", "24m", "3m" }; -static const char *a73_clksel_mux_p[] __initconst = { +static const char *a73_clksel_mux_p[] = { "24m", "apll", "1000m" }; @@ -136,7 +136,7 @@ static const u32 sysbus_mux_table[] = { 0, 1 }; static const u32 uart_mux_table[] = { 0, 1, 2 }; static const u32 a73_clksel_mux_table[] = { 0, 1, 2 }; -static struct hisi_mux_clock hi3559av100_mux_clks_crg[] __initdata = { +static struct hisi_mux_clock hi3559av100_mux_clks_crg[] = { { HI3559AV100_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p), CLK_SET_RATE_PARENT, 0x170, 2, 3, 0, fmc_mux_table, @@ -181,7 +181,7 @@ static struct hisi_mux_clock hi3559av100_mux_clks_crg[] __initdata = { }, }; -static struct hisi_gate_clock hi3559av100_gate_clks[] __initdata = { +static struct hisi_gate_clock hi3559av100_gate_clks[] = { { HI3559AV100_FMC_CLK, "clk_fmc", "fmc_mux", CLK_SET_RATE_PARENT, 0x170, 1, 0, @@ -336,7 +336,7 @@ static struct hisi_gate_clock hi3559av100_gate_clks[] __initdata = { }, }; -static struct hi3559av100_pll_clock hi3559av100_pll_clks[] __initdata = { +static struct hi3559av100_pll_clock hi3559av100_pll_clks[] = { { HI3559AV100_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3, 0x4, 0, 12, 12, 6 @@ -502,7 +502,7 @@ static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks, } } -static __init struct hisi_clock_data *hi3559av100_clk_register( +static struct hisi_clock_data *hi3559av100_clk_register( struct platform_device *pdev) { struct hisi_clock_data *clk_data; @@ -549,7 +549,7 @@ unregister_fixed_rate: return ERR_PTR(ret); } -static __init void hi3559av100_clk_unregister(struct platform_device *pdev) +static void hi3559av100_clk_unregister(struct platform_device *pdev) { struct hisi_crg_dev *crg = platform_get_drvdata(pdev); @@ -568,8 +568,7 @@ static const struct hisi_crg_funcs hi3559av100_crg_funcs = { .unregister_clks = hi3559av100_clk_unregister, }; -static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] - __initdata = { +static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] = { { HI3559AV100_SHUB_SOURCE_SOC_24M, "clk_source_24M", NULL, 0, 24000000UL, }, { HI3559AV100_SHUB_SOURCE_SOC_200M, "clk_source_200M", NULL, 0, 200000000UL, }, { HI3559AV100_SHUB_SOURCE_SOC_300M, "clk_source_300M", NULL, 0, 300000000UL, }, @@ -587,16 +586,16 @@ static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] /* shub mux clk */ static u32 shub_source_clk_mux_table[] = {0, 1, 2, 3}; -static const char *shub_source_clk_mux_p[] __initconst = { +static const char *shub_source_clk_mux_p[] = { "clk_source_24M", "clk_source_200M", "clk_source_300M", "clk_source_PLL" }; static u32 shub_uart_source_clk_mux_table[] = {0, 1, 2, 3}; -static const char *shub_uart_source_clk_mux_p[] __initconst = { +static const char *shub_uart_source_clk_mux_p[] = { "clk_uart_32K", "clk_uart_div_clk", "clk_uart_div_clk", "clk_source_24M" }; -static struct hisi_mux_clock hi3559av100_shub_mux_clks[] __initdata = { +static struct hisi_mux_clock hi3559av100_shub_mux_clks[] = { { HI3559AV100_SHUB_SOURCE_CLK, "shub_clk", shub_source_clk_mux_p, ARRAY_SIZE(shub_source_clk_mux_p), @@ -615,7 +614,7 @@ static struct hisi_mux_clock hi3559av100_shub_mux_clks[] __initdata = { static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}}; static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}}; -static struct hisi_divider_clock hi3559av100_shub_div_clks[] __initdata = { +static struct hisi_divider_clock hi3559av100_shub_div_clks[] = { { HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk", "shub_clk", 0, 0x20, 24, 2, CLK_DIVIDER_ALLOW_ZERO, shub_spi_clk_table, }, @@ -625,7 +624,7 @@ static struct hisi_divider_clock hi3559av100_shub_div_clks[] __initdata = { }; /* shub gate clk */ -static struct hisi_gate_clock hi3559av100_shub_gate_clks[] __initdata = { +static struct hisi_gate_clock hi3559av100_shub_gate_clks[] = { { HI3559AV100_SHUB_SPI0_CLK, "clk_shub_spi0", "clk_spi_clk", 0, 0x20, 1, 0, @@ -697,7 +696,7 @@ static int hi3559av100_shub_default_clk_set(void) return 0; } -static __init struct hisi_clock_data *hi3559av100_shub_clk_register( +static struct hisi_clock_data *hi3559av100_shub_clk_register( struct platform_device *pdev) { struct hisi_clock_data *clk_data = NULL; @@ -751,7 +750,7 @@ unregister_fixed_rate: return ERR_PTR(ret); } -static __init void hi3559av100_shub_clk_unregister(struct platform_device *pdev) +static void hi3559av100_shub_clk_unregister(struct platform_device *pdev) { struct hisi_crg_dev *crg = platform_get_drvdata(pdev); diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index dcd1757cc5df..8ad8977cf1c2 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -75,8 +75,8 @@ static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, div->width); } -static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_regmap_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_regmap *clk = to_clk_regmap(hw); struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); @@ -87,18 +87,17 @@ static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate, if (div->flags & CLK_DIVIDER_READ_ONLY) { ret = regmap_read(clk->map, div->offset, &val); if (ret) - /* Gives a hint that something is wrong */ - return 0; + return ret; val >>= div->shift; val &= clk_div_mask(div->width); - return divider_ro_round_rate(hw, rate, prate, div->table, - div->width, div->flags, val); + return divider_ro_determine_rate(hw, req, div->table, + div->width, div->flags, val); } - return divider_round_rate(hw, rate, prate, div->table, div->width, - div->flags); + return divider_determine_rate(hw, req, div->table, div->width, + div->flags); } static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -123,14 +122,14 @@ static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_regmap_divider_ops = { .recalc_rate = clk_regmap_div_recalc_rate, - .round_rate = clk_regmap_div_round_rate, + .determine_rate = clk_regmap_div_determine_rate, .set_rate = clk_regmap_div_set_rate, }; EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); const struct clk_ops clk_regmap_divider_ro_ops = { .recalc_rate = clk_regmap_div_recalc_rate, - .round_rate = clk_regmap_div_round_rate, + .determine_rate = clk_regmap_div_determine_rate, }; EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index e65e0a43be64..a5c5f70acfc9 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -19,6 +19,16 @@ config ACPI_CPPC_CPUFREQ If in doubt, say N. +config ACPI_CPPC_CPUFREQ_FIE + bool "Frequency Invariance support for CPPC cpufreq driver" + depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY + default y + help + This extends frequency invariance support in the CPPC cpufreq driver, + by using CPPC delivered and reference performance counters. + + If in doubt, say N. + config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM tristate "Allwinner nvmem based SUN50I CPUFreq driver" depends on ARCH_SUNXI diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 2f769b1630c5..d4c27022b9c9 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -10,14 +10,18 @@ #define pr_fmt(fmt) "CPPC Cpufreq:" fmt +#include #include #include #include #include #include #include +#include +#include #include #include +#include #include @@ -57,6 +61,216 @@ static struct cppc_workaround_oem_info wa_info[] = { } }; +#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE + +/* Frequency invariance support */ +struct cppc_freq_invariance { + int cpu; + struct irq_work irq_work; + struct kthread_work work; + struct cppc_perf_fb_ctrs prev_perf_fb_ctrs; + struct cppc_cpudata *cpu_data; +}; + +static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); +static struct kthread_worker *kworker_fie; + +static struct cpufreq_driver cppc_cpufreq_driver; +static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu); +static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, + struct cppc_perf_fb_ctrs *fb_ctrs_t0, + struct cppc_perf_fb_ctrs *fb_ctrs_t1); + +/** + * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance + * @work: The work item. + * + * The CPPC driver register itself with the topology core to provide its own + * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which + * gets called by the scheduler on every tick. + * + * Note that the arch specific counters have higher priority than CPPC counters, + * if available, though the CPPC driver doesn't need to have any special + * handling for that. + * + * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we + * reach here from hard-irq context), which then schedules a normal work item + * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable + * based on the counter updates since the last tick. + */ +static void cppc_scale_freq_workfn(struct kthread_work *work) +{ + struct cppc_freq_invariance *cppc_fi; + struct cppc_perf_fb_ctrs fb_ctrs = {0}; + struct cppc_cpudata *cpu_data; + unsigned long local_freq_scale; + u64 perf; + + cppc_fi = container_of(work, struct cppc_freq_invariance, work); + cpu_data = cppc_fi->cpu_data; + + if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) { + pr_warn("%s: failed to read perf counters\n", __func__); + return; + } + + perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs, + &fb_ctrs); + cppc_fi->prev_perf_fb_ctrs = fb_ctrs; + + perf <<= SCHED_CAPACITY_SHIFT; + local_freq_scale = div64_u64(perf, cpu_data->perf_caps.highest_perf); + + /* This can happen due to counter's overflow */ + if (unlikely(local_freq_scale > 1024)) + local_freq_scale = 1024; + + per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale; +} + +static void cppc_irq_work(struct irq_work *irq_work) +{ + struct cppc_freq_invariance *cppc_fi; + + cppc_fi = container_of(irq_work, struct cppc_freq_invariance, irq_work); + kthread_queue_work(kworker_fie, &cppc_fi->work); +} + +static void cppc_scale_freq_tick(void) +{ + struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id()); + + /* + * cppc_get_perf_ctrs() can potentially sleep, call that from the right + * context. + */ + irq_work_queue(&cppc_fi->irq_work); +} + +static struct scale_freq_data cppc_sftd = { + .source = SCALE_FREQ_SOURCE_CPPC, + .set_freq_scale = cppc_scale_freq_tick, +}; + +static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy) +{ + struct cppc_freq_invariance *cppc_fi; + int cpu, ret; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + for_each_cpu(cpu, policy->cpus) { + cppc_fi = &per_cpu(cppc_freq_inv, cpu); + cppc_fi->cpu = cpu; + cppc_fi->cpu_data = policy->driver_data; + kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn); + init_irq_work(&cppc_fi->irq_work, cppc_irq_work); + + ret = cppc_get_perf_ctrs(cpu, &cppc_fi->prev_perf_fb_ctrs); + if (ret) { + pr_warn("%s: failed to read perf counters for cpu:%d: %d\n", + __func__, cpu, ret); + + /* + * Don't abort if the CPU was offline while the driver + * was getting registered. + */ + if (cpu_online(cpu)) + return; + } + } + + /* Register for freq-invariance */ + topology_set_scale_freq_source(&cppc_sftd, policy->cpus); +} + +/* + * We free all the resources on policy's removal and not on CPU removal as the + * irq-work are per-cpu and the hotplug core takes care of flushing the pending + * irq-works (hint: smpcfd_dying_cpu()) on CPU hotplug. Even if the kthread-work + * fires on another CPU after the concerned CPU is removed, it won't harm. + * + * We just need to make sure to remove them all on policy->exit(). + */ +static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy) +{ + struct cppc_freq_invariance *cppc_fi; + int cpu; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + /* policy->cpus will be empty here, use related_cpus instead */ + topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus); + + for_each_cpu(cpu, policy->related_cpus) { + cppc_fi = &per_cpu(cppc_freq_inv, cpu); + irq_work_sync(&cppc_fi->irq_work); + kthread_cancel_work_sync(&cppc_fi->work); + } +} + +static void __init cppc_freq_invariance_init(void) +{ + struct sched_attr attr = { + .size = sizeof(struct sched_attr), + .sched_policy = SCHED_DEADLINE, + .sched_nice = 0, + .sched_priority = 0, + /* + * Fake (unused) bandwidth; workaround to "fix" + * priority inheritance. + */ + .sched_runtime = 1000000, + .sched_deadline = 10000000, + .sched_period = 10000000, + }; + int ret; + + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + kworker_fie = kthread_create_worker(0, "cppc_fie"); + if (IS_ERR(kworker_fie)) + return; + + ret = sched_setattr_nocheck(kworker_fie->task, &attr); + if (ret) { + pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__, + ret); + kthread_destroy_worker(kworker_fie); + return; + } +} + +static void cppc_freq_invariance_exit(void) +{ + if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate) + return; + + kthread_destroy_worker(kworker_fie); + kworker_fie = NULL; +} + +#else +static inline void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy) +{ +} + +static inline void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy) +{ +} + +static inline void cppc_freq_invariance_init(void) +{ +} + +static inline void cppc_freq_invariance_exit(void) +{ +} +#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */ + /* Callback function used to retrieve the max frequency from DMI */ static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) { @@ -182,27 +396,6 @@ static int cppc_verify_policy(struct cpufreq_policy_data *policy) return 0; } -static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) -{ - struct cppc_cpudata *cpu_data = policy->driver_data; - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - unsigned int cpu = policy->cpu; - int ret; - - cpu_data->perf_ctrls.desired_perf = caps->lowest_perf; - - ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); - if (ret) - pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", - caps->lowest_perf, cpu, ret); - - /* Remove CPU node from list and free driver data for policy */ - free_cpumask_var(cpu_data->shared_cpu_map); - list_del(&cpu_data->node); - kfree(policy->driver_data); - policy->driver_data = NULL; -} - /* * The PCC subspace describes the rate at which platform can accept commands * on the shared PCC channel (including READs which do not count towards freq @@ -277,6 +470,16 @@ out: return NULL; } +static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy) +{ + struct cppc_cpudata *cpu_data = policy->driver_data; + + list_del(&cpu_data->node); + free_cpumask_var(cpu_data->shared_cpu_map); + kfree(cpu_data); + policy->driver_data = NULL; +} + static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; @@ -330,7 +533,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) default: pr_debug("Unsupported CPU co-ord type: %d\n", policy->shared_type); - return -EFAULT; + ret = -EFAULT; + goto out; } /* @@ -345,13 +549,40 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) cpu_data->perf_ctrls.desired_perf = caps->highest_perf; ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); - if (ret) + if (ret) { pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", caps->highest_perf, cpu, ret); + goto out; + } + cppc_cpufreq_cpu_fie_init(policy); + return 0; + +out: + cppc_cpufreq_put_cpu_data(policy); return ret; } +static int cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + struct cppc_cpudata *cpu_data = policy->driver_data; + struct cppc_perf_caps *caps = &cpu_data->perf_caps; + unsigned int cpu = policy->cpu; + int ret; + + cppc_cpufreq_cpu_fie_exit(policy); + + cpu_data->perf_ctrls.desired_perf = caps->lowest_perf; + + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); + if (ret) + pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", + caps->lowest_perf, cpu, ret); + + cppc_cpufreq_put_cpu_data(policy); + return 0; +} + static inline u64 get_delta(u64 t1, u64 t0) { if (t1 > t0 || t0 > ~(u32)0) @@ -360,28 +591,25 @@ static inline u64 get_delta(u64 t1, u64 t0) return (u32)t1 - (u32)t0; } -static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data, - struct cppc_perf_fb_ctrs fb_ctrs_t0, - struct cppc_perf_fb_ctrs fb_ctrs_t1) +static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, + struct cppc_perf_fb_ctrs *fb_ctrs_t0, + struct cppc_perf_fb_ctrs *fb_ctrs_t1) { u64 delta_reference, delta_delivered; - u64 reference_perf, delivered_perf; + u64 reference_perf; - reference_perf = fb_ctrs_t0.reference_perf; + reference_perf = fb_ctrs_t0->reference_perf; - delta_reference = get_delta(fb_ctrs_t1.reference, - fb_ctrs_t0.reference); - delta_delivered = get_delta(fb_ctrs_t1.delivered, - fb_ctrs_t0.delivered); + delta_reference = get_delta(fb_ctrs_t1->reference, + fb_ctrs_t0->reference); + delta_delivered = get_delta(fb_ctrs_t1->delivered, + fb_ctrs_t0->delivered); - /* Check to avoid divide-by zero */ - if (delta_reference || delta_delivered) - delivered_perf = (reference_perf * delta_delivered) / - delta_reference; - else - delivered_perf = cpu_data->perf_ctrls.desired_perf; + /* Check to avoid divide-by zero and invalid delivered_perf */ + if (!delta_reference || !delta_delivered) + return cpu_data->perf_ctrls.desired_perf; - return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf); + return (reference_perf * delta_delivered) / delta_reference; } static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) @@ -389,6 +617,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); struct cppc_cpudata *cpu_data = policy->driver_data; + u64 delivered_perf; int ret; cpufreq_cpu_put(policy); @@ -403,7 +632,10 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) if (ret) return ret; - return cppc_get_rate_from_fbctrs(cpu_data, fb_ctrs_t0, fb_ctrs_t1); + delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0, + &fb_ctrs_t1); + + return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf); } static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) @@ -451,7 +683,7 @@ static struct cpufreq_driver cppc_cpufreq_driver = { .target = cppc_cpufreq_set_target, .get = cppc_cpufreq_get_rate, .init = cppc_cpufreq_cpu_init, - .stop_cpu = cppc_cpufreq_stop_cpu, + .exit = cppc_cpufreq_cpu_exit, .set_boost = cppc_cpufreq_set_boost, .attr = cppc_cpufreq_attr, .name = "cppc_cpufreq", @@ -504,14 +736,21 @@ static void cppc_check_hisi_workaround(void) static int __init cppc_cpufreq_init(void) { + int ret; + if ((acpi_disabled) || !acpi_cpc_valid()) return -ENODEV; INIT_LIST_HEAD(&cpu_data_list); cppc_check_hisi_workaround(); + cppc_freq_invariance_init(); - return cpufreq_register_driver(&cppc_cpufreq_driver); + ret = cpufreq_register_driver(&cppc_cpufreq_driver); + if (ret) + cppc_freq_invariance_exit(); + + return ret; } static inline void free_cpu_data(void) @@ -529,6 +768,7 @@ static inline void free_cpu_data(void) static void __exit cppc_cpufreq_exit(void) { cpufreq_unregister_driver(&cppc_cpufreq_driver); + cppc_freq_invariance_exit(); free_cpu_data(); } diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 5e07065ec22f..bef7528aecd3 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -15,7 +15,7 @@ * Machines for which the cpufreq device is *always* created, mostly used for * platforms using "operating-points" (V1) property. */ -static const struct of_device_id whitelist[] __initconst = { +static const struct of_device_id allowlist[] __initconst = { { .compatible = "allwinner,sun4i-a10", }, { .compatible = "allwinner,sun5i-a10s", }, { .compatible = "allwinner,sun5i-a13", }, @@ -100,7 +100,7 @@ static const struct of_device_id whitelist[] __initconst = { * Machines for which the cpufreq device is *not* created, mostly used for * platforms using "operating-points-v2" property. */ -static const struct of_device_id blacklist[] __initconst = { +static const struct of_device_id blocklist[] __initconst = { { .compatible = "allwinner,sun50i-h6", }, { .compatible = "arm,vexpress", }, @@ -126,6 +126,7 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "mediatek,mt8173", }, { .compatible = "mediatek,mt8176", }, { .compatible = "mediatek,mt8183", }, + { .compatible = "mediatek,mt8365", }, { .compatible = "mediatek,mt8516", }, { .compatible = "nvidia,tegra20", }, @@ -137,6 +138,7 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "qcom,msm8996", }, { .compatible = "qcom,qcs404", }, { .compatible = "qcom,sc7180", }, + { .compatible = "qcom,sc7280", }, { .compatible = "qcom,sdm845", }, { .compatible = "st,stih407", }, @@ -177,13 +179,13 @@ static int __init cpufreq_dt_platdev_init(void) if (!np) return -ENODEV; - match = of_match_node(whitelist, np); + match = of_match_node(allowlist, np); if (match) { data = match->data; goto create_pdev; } - if (cpu0_node_has_opp_v2_prop() && !of_match_node(blacklist, np)) + if (cpu0_node_has_opp_v2_prop() && !of_match_node(blocklist, np)) goto create_pdev; of_node_put(np); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e872e0ce0011..727f12a9f85b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -527,6 +527,22 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy) } EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); +static unsigned int __resolve_freq(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned int idx; + + target_freq = clamp_val(target_freq, policy->min, policy->max); + + if (!cpufreq_driver->target_index) + return target_freq; + + idx = cpufreq_frequency_table_target(policy, target_freq, relation); + policy->cached_resolved_idx = idx; + policy->cached_target_freq = target_freq; + return policy->freq_table[idx].frequency; +} + /** * cpufreq_driver_resolve_freq - Map a target frequency to a driver-supported * one. @@ -541,22 +557,7 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, unsigned int target_freq) { - target_freq = clamp_val(target_freq, policy->min, policy->max); - policy->cached_target_freq = target_freq; - - if (cpufreq_driver->target_index) { - unsigned int idx; - - idx = cpufreq_frequency_table_target(policy, target_freq, - CPUFREQ_RELATION_L); - policy->cached_resolved_idx = idx; - return policy->freq_table[idx].frequency; - } - - if (cpufreq_driver->resolve_freq) - return cpufreq_driver->resolve_freq(policy, target_freq); - - return target_freq; + return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_L); } EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq); @@ -1617,9 +1618,6 @@ static int cpufreq_offline(unsigned int cpu) policy->cdev = NULL; } - if (cpufreq_driver->stop_cpu) - cpufreq_driver->stop_cpu(policy); - if (has_target()) cpufreq_exit_governor(policy); @@ -2245,13 +2243,11 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { unsigned int old_target_freq = target_freq; - int index; if (cpufreq_disabled()) return -ENODEV; - /* Make sure that target_freq is within supported range */ - target_freq = clamp_val(target_freq, policy->min, policy->max); + target_freq = __resolve_freq(policy, target_freq, relation); pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", policy->cpu, target_freq, relation, old_target_freq); @@ -2272,9 +2268,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (!cpufreq_driver->target_index) return -EINVAL; - index = cpufreq_frequency_table_target(policy, target_freq, relation); - - return __target_index(policy, index); + return __target_index(policy, policy->cached_resolved_idx); } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 6012964df51b..bb4549959b11 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -2532,7 +2532,7 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy) return 0; } -static int intel_pstate_cpu_offline(struct cpufreq_policy *policy) +static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy) { struct cpudata *cpu = all_cpu_data[policy->cpu]; @@ -2577,11 +2577,11 @@ static int intel_pstate_cpu_online(struct cpufreq_policy *policy) return 0; } -static void intel_pstate_stop_cpu(struct cpufreq_policy *policy) +static int intel_pstate_cpu_offline(struct cpufreq_policy *policy) { - pr_debug("CPU %d stopping\n", policy->cpu); - intel_pstate_clear_update_util_hook(policy->cpu); + + return intel_cpufreq_cpu_offline(policy); } static int intel_pstate_cpu_exit(struct cpufreq_policy *policy) @@ -2654,7 +2654,6 @@ static struct cpufreq_driver intel_pstate = { .resume = intel_pstate_resume, .init = intel_pstate_cpu_init, .exit = intel_pstate_cpu_exit, - .stop_cpu = intel_pstate_stop_cpu, .offline = intel_pstate_cpu_offline, .online = intel_pstate_cpu_online, .update_limits = intel_pstate_update_limits, @@ -2956,7 +2955,7 @@ static struct cpufreq_driver intel_cpufreq = { .fast_switch = intel_cpufreq_fast_switch, .init = intel_cpufreq_cpu_init, .exit = intel_cpufreq_cpu_exit, - .offline = intel_pstate_cpu_offline, + .offline = intel_cpufreq_cpu_offline, .online = intel_pstate_cpu_online, .suspend = intel_pstate_suspend, .resume = intel_pstate_resume, diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index f2e491b25b07..87019d5a9547 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -537,6 +537,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = { { .compatible = "mediatek,mt8173", }, { .compatible = "mediatek,mt8176", }, { .compatible = "mediatek,mt8183", }, + { .compatible = "mediatek,mt8365", }, { .compatible = "mediatek,mt8516", }, { } diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index e439b43c19eb..005600cef273 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -875,7 +875,15 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) static int powernv_cpufreq_cpu_exit(struct cpufreq_policy *policy) { - /* timer is deleted in cpufreq_cpu_stop() */ + struct powernv_smp_call_data freq_data; + struct global_pstate_info *gpstates = policy->driver_data; + + freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min); + freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min); + smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1); + if (gpstates) + del_timer_sync(&gpstates->timer); + kfree(policy->driver_data); return 0; @@ -1007,18 +1015,6 @@ static struct notifier_block powernv_cpufreq_opal_nb = { .priority = 0, }; -static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) -{ - struct powernv_smp_call_data freq_data; - struct global_pstate_info *gpstates = policy->driver_data; - - freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min); - freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min); - smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1); - if (gpstates) - del_timer_sync(&gpstates->timer); -} - static unsigned int powernv_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { @@ -1042,7 +1038,6 @@ static struct cpufreq_driver powernv_cpufreq_driver = { .target_index = powernv_cpufreq_target_index, .fast_switch = powernv_fast_switch, .get = powernv_cpufreq_get, - .stop_cpu = powernv_cpufreq_stop_cpu, .attr = powernv_cpu_freq_attr, }; diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index c8a4364ad3c2..ec9a87ca2dbb 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -174,7 +174,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) nr_opp = dev_pm_opp_get_opp_count(cpu_dev); if (nr_opp <= 0) { dev_err(cpu_dev, "%s: No OPPs for this device: %d\n", - __func__, ret); + __func__, nr_opp); ret = -ENODEV; goto out_free_opp; diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index adf91a6e4d7d..c0e7971da2da 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -87,6 +87,18 @@ static const struct spm_reg_data spm_reg_8974_8084_cpu = { .start_index[PM_SLEEP_MODE_SPC] = 3, }; +/* SPM register data for 8226 */ +static const struct spm_reg_data spm_reg_8226_cpu = { + .reg_offset = spm_reg_offset_v2_1, + .spm_cfg = 0x0, + .spm_dly = 0x3C102800, + .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, + 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, + 0x80, 0x10, 0x26, 0x30, 0x0F }, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 5, +}; + static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x20, @@ -259,6 +271,8 @@ static struct spm_driver_data *spm_get_drv(struct platform_device *pdev, } static const struct of_device_id spm_match_table[] = { + { .compatible = "qcom,msm8226-saw2-v2.1-cpu", + .data = &spm_reg_8226_cpu }, { .compatible = "qcom,msm8974-saw2-v2.1-cpu", .data = &spm_reg_8974_8084_cpu }, { .compatible = "qcom,apq8084-saw2-v2.1-cpu", diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index ebcec460c045..51690e73153a 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -267,14 +267,14 @@ config CRYPTO_DEV_NIAGARA2 checksumming, and raw copies. config CRYPTO_DEV_SL3516 - tristate "Stormlink SL3516 crypto offloader" - depends on HAS_IOMEM + tristate "Storlink SL3516 crypto offloader" + depends on ARCH_GEMINI || COMPILE_TEST + depends on HAS_IOMEM && PM select CRYPTO_SKCIPHER select CRYPTO_ENGINE select CRYPTO_ECB select CRYPTO_AES select HW_RANDOM - depends on PM help This option allows you to have support for SL3516 crypto offloader. diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemini/sl3516-ce-cipher.c index b41c2f5fc495..c1c2b1d86663 100644 --- a/drivers/crypto/gemini/sl3516-ce-cipher.c +++ b/drivers/crypto/gemini/sl3516-ce-cipher.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * sl3516-ce-cipher.c - hardware cryptographic offloader for Stormlink SL3516 SoC + * sl3516-ce-cipher.c - hardware cryptographic offloader for Storlink SL3516 SoC * * Copyright (C) 2021 Corentin LABBE * diff --git a/drivers/crypto/gemini/sl3516-ce-core.c b/drivers/crypto/gemini/sl3516-ce-core.c index da6cd529a6c0..b7524b649068 100644 --- a/drivers/crypto/gemini/sl3516-ce-core.c +++ b/drivers/crypto/gemini/sl3516-ce-core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * sl3516-ce-core.c - hardware cryptographic offloader for Stormlink SL3516 SoC + * sl3516-ce-core.c - hardware cryptographic offloader for Storlink SL3516 SoC * * Copyright (C) 2021 Corentin Labbe * diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index d120ce3e34ed..490db7bccf61 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -364,6 +364,9 @@ static void sec_close_sva_prefetch(struct hisi_qm *qm) u32 val; int ret; + if (qm->ver < QM_HW_V3) + return; + val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG); val |= SEC_PREFETCH_DISABLE; writel(val, qm->io_base + SEC_PREFETCH_CFG); diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 35fc5ee70491..98730aab287c 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -31,6 +31,10 @@ #include #include +/* Intermittent includes, delete this after v5.14-rc1 */ +#include +#include + #define MAX_KEYLEN 32 /* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */ diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c index 94b2dba90f0d..31bdb1d76d11 100644 --- a/drivers/crypto/omap-crypto.c +++ b/drivers/crypto/omap-crypto.c @@ -183,8 +183,7 @@ static void omap_crypto_copy_data(struct scatterlist *src, memcpy(dstb, srcb, amt); - if (!PageSlab(sg_page(dst))) - flush_kernel_dcache_page(sg_page(dst)); + flush_dcache_page(sg_page(dst)); kunmap_atomic(srcb); kunmap_atomic(dstb); diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 96b437bfe3de..6f64aa693146 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -406,7 +406,7 @@ static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ret = adf_ctl_ioctl_get_status(fp, cmd, arg); break; default: - pr_err("QAT: Invalid ioctl\n"); + pr_err_ratelimited("QAT: Invalid ioctl %d\n", cmd); ret = -EFAULT; break; } diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index af53778edc7e..aadb720c229b 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -9,7 +9,7 @@ menu "Firmware Drivers" config ARM_SCMI_PROTOCOL tristate "ARM System Control and Management Interface (SCMI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST - depends on MAILBOX + depends on MAILBOX || HAVE_ARM_SMCCC_DISCOVERY help ARM System Control and Management Interface (SCMI) protocol is a set of operating system-independent software interfaces that are @@ -296,6 +296,7 @@ config TURRIS_MOX_RWTM other manufacturing data and also utilize the Entropy Bit Generator for hardware random number generation. +source "drivers/firmware/arm_ffa/Kconfig" source "drivers/firmware/broadcom/Kconfig" source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 523173cbff33..3c2af2e98def 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o +obj-y += arm_ffa/ obj-y += arm_scmi/ obj-y += broadcom/ obj-y += meson/ diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig new file mode 100644 index 000000000000..5e3ae5cf82e8 --- /dev/null +++ b/drivers/firmware/arm_ffa/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +config ARM_FFA_TRANSPORT + tristate "Arm Firmware Framework for Armv8-A" + depends on OF + depends on ARM64 + default n + help + This Firmware Framework(FF) for Arm A-profile processors describes + interfaces that standardize communication between the various + software images which includes communication between images in + the Secure world and Normal world. It also leverages the + virtualization extension to isolate software images provided + by an ecosystem of vendors from each other. + + This driver provides interface for all the client drivers making + use of the features offered by ARM FF-A. + +config ARM_FFA_SMCCC + bool + default ARM_FFA_TRANSPORT + depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile new file mode 100644 index 000000000000..9d9f37523200 --- /dev/null +++ b/drivers/firmware/arm_ffa/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ffa-bus-y = bus.o +ffa-driver-y = driver.o +ffa-transport-$(CONFIG_ARM_FFA_SMCCC) += smccc.o +ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) $(ffa-transport-y) +obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c new file mode 100644 index 000000000000..83166e02b191 --- /dev/null +++ b/drivers/firmware/arm_ffa/bus.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 ARM Ltd. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static int ffa_device_match(struct device *dev, struct device_driver *drv) +{ + const struct ffa_device_id *id_table; + struct ffa_device *ffa_dev; + + id_table = to_ffa_driver(drv)->id_table; + ffa_dev = to_ffa_dev(dev); + + while (!uuid_is_null(&id_table->uuid)) { + /* + * FF-A v1.0 doesn't provide discovery of UUIDs, just the + * partition IDs, so fetch the partitions IDs for this + * id_table UUID and assign the UUID to the device if the + * partition ID matches + */ + if (uuid_is_null(&ffa_dev->uuid)) + ffa_device_match_uuid(ffa_dev, &id_table->uuid); + + if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) + return 1; + id_table++; + } + + return 0; +} + +static int ffa_device_probe(struct device *dev) +{ + struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + if (!ffa_device_match(dev, dev->driver)) + return -ENODEV; + + return ffa_drv->probe(ffa_dev); +} + +static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb", + ffa_dev->vm_id, &ffa_dev->uuid); +} + +static ssize_t partition_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return sprintf(buf, "0x%04x\n", ffa_dev->vm_id); +} +static DEVICE_ATTR_RO(partition_id); + +static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return sprintf(buf, "%pUb\n", &ffa_dev->uuid); +} +static DEVICE_ATTR_RO(uuid); + +static struct attribute *ffa_device_attributes_attrs[] = { + &dev_attr_partition_id.attr, + &dev_attr_uuid.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ffa_device_attributes); + +struct bus_type ffa_bus_type = { + .name = "arm_ffa", + .match = ffa_device_match, + .probe = ffa_device_probe, + .uevent = ffa_device_uevent, + .dev_groups = ffa_device_attributes_groups, +}; +EXPORT_SYMBOL_GPL(ffa_bus_type); + +int ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name) +{ + int ret; + + driver->driver.bus = &ffa_bus_type; + driver->driver.name = driver->name; + driver->driver.owner = owner; + driver->driver.mod_name = mod_name; + + ret = driver_register(&driver->driver); + if (!ret) + pr_debug("registered new ffa driver %s\n", driver->name); + + return ret; +} +EXPORT_SYMBOL_GPL(ffa_driver_register); + +void ffa_driver_unregister(struct ffa_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL_GPL(ffa_driver_unregister); + +static void ffa_release_device(struct device *dev) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + kfree(ffa_dev); +} + +static int __ffa_devices_unregister(struct device *dev, void *data) +{ + ffa_release_device(dev); + + return 0; +} + +static void ffa_devices_unregister(void) +{ + bus_for_each_dev(&ffa_bus_type, NULL, NULL, + __ffa_devices_unregister); +} + +bool ffa_device_is_valid(struct ffa_device *ffa_dev) +{ + bool valid = false; + struct device *dev = NULL; + struct ffa_device *tmp_dev; + + do { + dev = bus_find_next_device(&ffa_bus_type, dev); + tmp_dev = to_ffa_dev(dev); + if (tmp_dev == ffa_dev) { + valid = true; + break; + } + put_device(dev); + } while (dev); + + put_device(dev); + + return valid; +} + +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) +{ + int ret; + struct device *dev; + struct ffa_device *ffa_dev; + + ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); + if (!ffa_dev) + return NULL; + + dev = &ffa_dev->dev; + dev->bus = &ffa_bus_type; + dev->release = ffa_release_device; + dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id); + + ffa_dev->vm_id = vm_id; + uuid_copy(&ffa_dev->uuid, uuid); + + ret = device_register(&ffa_dev->dev); + if (ret) { + dev_err(dev, "unable to register device %s err=%d\n", + dev_name(dev), ret); + put_device(dev); + return NULL; + } + + return ffa_dev; +} +EXPORT_SYMBOL_GPL(ffa_device_register); + +void ffa_device_unregister(struct ffa_device *ffa_dev) +{ + if (!ffa_dev) + return; + + device_unregister(&ffa_dev->dev); +} +EXPORT_SYMBOL_GPL(ffa_device_unregister); + +int arm_ffa_bus_init(void) +{ + return bus_register(&ffa_bus_type); +} + +void arm_ffa_bus_exit(void) +{ + ffa_devices_unregister(); + bus_unregister(&ffa_bus_type); +} diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h new file mode 100644 index 000000000000..d6eccf1fd3f6 --- /dev/null +++ b/drivers/firmware/arm_ffa/common.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 ARM Ltd. + */ + +#ifndef _FFA_COMMON_H +#define _FFA_COMMON_H + +#include +#include +#include + +typedef struct arm_smccc_1_2_regs ffa_value_t; + +typedef void (ffa_fn)(ffa_value_t, ffa_value_t *); + +int arm_ffa_bus_init(void); +void arm_ffa_bus_exit(void); +bool ffa_device_is_valid(struct ffa_device *ffa_dev); +void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid); + +#ifdef CONFIG_ARM_FFA_SMCCC +int __init ffa_transport_init(ffa_fn **invoke_ffa_fn); +#else +static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* _FFA_COMMON_H */ diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c new file mode 100644 index 000000000000..b1edb4b2e94a --- /dev/null +++ b/drivers/firmware/arm_ffa/driver.c @@ -0,0 +1,731 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Arm Firmware Framework for ARMv8-A(FFA) interface driver + * + * The Arm FFA specification[1] describes a software architecture to + * leverages the virtualization extension to isolate software images + * provided by an ecosystem of vendors from each other and describes + * interfaces that standardize communication between the various software + * images including communication between images in the Secure world and + * Normal world. Any Hypervisor could use the FFA interfaces to enable + * communication between VMs it manages. + * + * The Hypervisor a.k.a Partition managers in FFA terminology can assign + * system resources(Memory regions, Devices, CPU cycles) to the partitions + * and manage isolation amongst them. + * + * [1] https://developer.arm.com/docs/den0077/latest + * + * Copyright (C) 2021 ARM Ltd. + */ + +#define DRIVER_NAME "ARM FF-A" +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define FFA_DRIVER_VERSION FFA_VERSION_1_0 + +#define FFA_SMC(calling_convention, func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \ + ARM_SMCCC_OWNER_STANDARD, (func_num)) + +#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num)) +#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num)) + +#define FFA_ERROR FFA_SMC_32(0x60) +#define FFA_SUCCESS FFA_SMC_32(0x61) +#define FFA_INTERRUPT FFA_SMC_32(0x62) +#define FFA_VERSION FFA_SMC_32(0x63) +#define FFA_FEATURES FFA_SMC_32(0x64) +#define FFA_RX_RELEASE FFA_SMC_32(0x65) +#define FFA_RXTX_MAP FFA_SMC_32(0x66) +#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66) +#define FFA_RXTX_UNMAP FFA_SMC_32(0x67) +#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68) +#define FFA_ID_GET FFA_SMC_32(0x69) +#define FFA_MSG_POLL FFA_SMC_32(0x6A) +#define FFA_MSG_WAIT FFA_SMC_32(0x6B) +#define FFA_YIELD FFA_SMC_32(0x6C) +#define FFA_RUN FFA_SMC_32(0x6D) +#define FFA_MSG_SEND FFA_SMC_32(0x6E) +#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F) +#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F) +#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70) +#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70) +#define FFA_MEM_DONATE FFA_SMC_32(0x71) +#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71) +#define FFA_MEM_LEND FFA_SMC_32(0x72) +#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72) +#define FFA_MEM_SHARE FFA_SMC_32(0x73) +#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73) +#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74) +#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74) +#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75) +#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76) +#define FFA_MEM_RECLAIM FFA_SMC_32(0x77) +#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78) +#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79) +#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A) +#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B) +#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C) + +/* + * For some calls it is necessary to use SMC64 to pass or return 64-bit values. + * For such calls FFA_FN_NATIVE(name) will choose the appropriate + * (native-width) function ID. + */ +#ifdef CONFIG_64BIT +#define FFA_FN_NATIVE(name) FFA_FN64_##name +#else +#define FFA_FN_NATIVE(name) FFA_##name +#endif + +/* FFA error codes. */ +#define FFA_RET_SUCCESS (0) +#define FFA_RET_NOT_SUPPORTED (-1) +#define FFA_RET_INVALID_PARAMETERS (-2) +#define FFA_RET_NO_MEMORY (-3) +#define FFA_RET_BUSY (-4) +#define FFA_RET_INTERRUPTED (-5) +#define FFA_RET_DENIED (-6) +#define FFA_RET_RETRY (-7) +#define FFA_RET_ABORTED (-8) + +#define MAJOR_VERSION_MASK GENMASK(30, 16) +#define MINOR_VERSION_MASK GENMASK(15, 0) +#define MAJOR_VERSION(x) ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))) +#define MINOR_VERSION(x) ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))) +#define PACK_VERSION_INFO(major, minor) \ + (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \ + FIELD_PREP(MINOR_VERSION_MASK, (minor))) +#define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0) +#define FFA_MIN_VERSION FFA_VERSION_1_0 + +#define SENDER_ID_MASK GENMASK(31, 16) +#define RECEIVER_ID_MASK GENMASK(15, 0) +#define SENDER_ID(x) ((u16)(FIELD_GET(SENDER_ID_MASK, (x)))) +#define RECEIVER_ID(x) ((u16)(FIELD_GET(RECEIVER_ID_MASK, (x)))) +#define PACK_TARGET_INFO(s, r) \ + (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) + +/** + * FF-A specification mentions explicitly about '4K pages'. This should + * not be confused with the kernel PAGE_SIZE, which is the translation + * granule kernel is configured and may be one among 4K, 16K and 64K. + */ +#define FFA_PAGE_SIZE SZ_4K +/* + * Keeping RX TX buffer size as 4K for now + * 64K may be preferred to keep it min a page in 64K PAGE_SIZE config + */ +#define RXTX_BUFFER_SIZE SZ_4K + +static ffa_fn *invoke_ffa_fn; + +static const int ffa_linux_errmap[] = { + /* better than switch case as long as return value is continuous */ + 0, /* FFA_RET_SUCCESS */ + -EOPNOTSUPP, /* FFA_RET_NOT_SUPPORTED */ + -EINVAL, /* FFA_RET_INVALID_PARAMETERS */ + -ENOMEM, /* FFA_RET_NO_MEMORY */ + -EBUSY, /* FFA_RET_BUSY */ + -EINTR, /* FFA_RET_INTERRUPTED */ + -EACCES, /* FFA_RET_DENIED */ + -EAGAIN, /* FFA_RET_RETRY */ + -ECANCELED, /* FFA_RET_ABORTED */ +}; + +static inline int ffa_to_linux_errno(int errno) +{ + if (errno < FFA_RET_SUCCESS && errno >= -ARRAY_SIZE(ffa_linux_errmap)) + return ffa_linux_errmap[-errno]; + return -EINVAL; +} + +struct ffa_drv_info { + u32 version; + u16 vm_id; + struct mutex rx_lock; /* lock to protect Rx buffer */ + struct mutex tx_lock; /* lock to protect Tx buffer */ + void *rx_buffer; + void *tx_buffer; +}; + +static struct ffa_drv_info *drv_info; + +static int ffa_version_check(u32 *version) +{ + ffa_value_t ver; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION, + }, &ver); + + if (ver.a0 == FFA_RET_NOT_SUPPORTED) { + pr_info("FFA_VERSION returned not supported\n"); + return -EOPNOTSUPP; + } + + if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) { + pr_err("Incompatible version %d.%d found\n", + MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0)); + return -EINVAL; + } + + *version = ver.a0; + pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0), + MINOR_VERSION(ver.a0)); + return 0; +} + +static int ffa_rx_release(void) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_RX_RELEASE, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + /* check for ret.a0 == FFA_RX_RELEASE ? */ + + return 0; +} + +static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_FN_NATIVE(RXTX_MAP), + .a1 = tx_buf, .a2 = rx_buf, .a3 = pg_cnt, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + +static int ffa_rxtx_unmap(u16 vm_id) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0), + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + +/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ +static int +__ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, + struct ffa_partition_info *buffer, int num_partitions) +{ + int count; + ffa_value_t partition_info; + + mutex_lock(&drv_info->rx_lock); + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_PARTITION_INFO_GET, + .a1 = uuid0, .a2 = uuid1, .a3 = uuid2, .a4 = uuid3, + }, &partition_info); + + if (partition_info.a0 == FFA_ERROR) { + mutex_unlock(&drv_info->rx_lock); + return ffa_to_linux_errno((int)partition_info.a2); + } + + count = partition_info.a2; + + if (buffer && count <= num_partitions) + memcpy(buffer, drv_info->rx_buffer, sizeof(*buffer) * count); + + ffa_rx_release(); + + mutex_unlock(&drv_info->rx_lock); + + return count; +} + +/* buffer is allocated and caller must free the same if returned count > 0 */ +static int +ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer) +{ + int count; + u32 uuid0_4[4]; + struct ffa_partition_info *pbuf; + + export_uuid((u8 *)uuid0_4, uuid); + count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], + uuid0_4[3], NULL, 0); + if (count <= 0) + return count; + + pbuf = kcalloc(count, sizeof(*pbuf), GFP_KERNEL); + if (!pbuf) + return -ENOMEM; + + count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], + uuid0_4[3], pbuf, count); + if (count <= 0) + kfree(pbuf); + else + *buffer = pbuf; + + return count; +} + +#define VM_ID_MASK GENMASK(15, 0) +static int ffa_id_get(u16 *vm_id) +{ + ffa_value_t id; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_ID_GET, + }, &id); + + if (id.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)id.a2); + + *vm_id = FIELD_GET(VM_ID_MASK, (id.a2)); + + return 0; +} + +static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, + struct ffa_send_direct_data *data) +{ + u32 req_id, resp_id, src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); + ffa_value_t ret; + + if (mode_32bit) { + req_id = FFA_MSG_SEND_DIRECT_REQ; + resp_id = FFA_MSG_SEND_DIRECT_RESP; + } else { + req_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_REQ); + resp_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_RESP); + } + + invoke_ffa_fn((ffa_value_t){ + .a0 = req_id, .a1 = src_dst_ids, .a2 = 0, + .a3 = data->data0, .a4 = data->data1, .a5 = data->data2, + .a6 = data->data3, .a7 = data->data4, + }, &ret); + + while (ret.a0 == FFA_INTERRUPT) + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_RUN, .a1 = ret.a1, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + if (ret.a0 == resp_id) { + data->data0 = ret.a3; + data->data1 = ret.a4; + data->data2 = ret.a5; + data->data3 = ret.a6; + data->data4 = ret.a7; + return 0; + } + + return -EINVAL; +} + +static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, + u32 frag_len, u32 len, u64 *handle) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = func_id, .a1 = len, .a2 = frag_len, + .a3 = buf, .a4 = buf_sz, + }, &ret); + + while (ret.a0 == FFA_MEM_OP_PAUSE) + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_MEM_OP_RESUME, + .a1 = ret.a1, .a2 = ret.a2, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + if (ret.a0 != FFA_SUCCESS) + return -EOPNOTSUPP; + + if (handle) + *handle = PACK_HANDLE(ret.a2, ret.a3); + + return frag_len; +} + +static int ffa_mem_next_frag(u64 handle, u32 frag_len) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_MEM_FRAG_TX, + .a1 = HANDLE_LOW(handle), .a2 = HANDLE_HIGH(handle), + .a3 = frag_len, + }, &ret); + + while (ret.a0 == FFA_MEM_OP_PAUSE) + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_MEM_OP_RESUME, + .a1 = ret.a1, .a2 = ret.a2, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + if (ret.a0 != FFA_MEM_FRAG_RX) + return -EOPNOTSUPP; + + return ret.a3; +} + +static int +ffa_transmit_fragment(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len, + u32 len, u64 *handle, bool first) +{ + if (!first) + return ffa_mem_next_frag(*handle, frag_len); + + return ffa_mem_first_frag(func_id, buf, buf_sz, frag_len, len, handle); +} + +static u32 ffa_get_num_pages_sg(struct scatterlist *sg) +{ + u32 num_pages = 0; + + do { + num_pages += sg->length / FFA_PAGE_SIZE; + } while ((sg = sg_next(sg))); + + return num_pages; +} + +static int +ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, + struct ffa_mem_ops_args *args) +{ + int rc = 0; + bool first = true; + phys_addr_t addr = 0; + struct ffa_composite_mem_region *composite; + struct ffa_mem_region_addr_range *constituents; + struct ffa_mem_region_attributes *ep_mem_access; + struct ffa_mem_region *mem_region = buffer; + u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg); + + mem_region->tag = args->tag; + mem_region->flags = args->flags; + mem_region->sender_id = drv_info->vm_id; + mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | + FFA_MEM_INNER_SHAREABLE; + ep_mem_access = &mem_region->ep_mem_access[0]; + + for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { + ep_mem_access->receiver = args->attrs[idx].receiver; + ep_mem_access->attrs = args->attrs[idx].attrs; + ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs); + } + mem_region->ep_count = args->nattrs; + + composite = buffer + COMPOSITE_OFFSET(args->nattrs); + composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); + composite->addr_range_cnt = num_entries; + + length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries); + frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0); + if (frag_len > max_fragsize) + return -ENXIO; + + if (!args->use_txbuf) { + addr = virt_to_phys(buffer); + buf_sz = max_fragsize / FFA_PAGE_SIZE; + } + + constituents = buffer + frag_len; + idx = 0; + do { + if (frag_len == max_fragsize) { + rc = ffa_transmit_fragment(func_id, addr, buf_sz, + frag_len, length, + &args->g_handle, first); + if (rc < 0) + return -ENXIO; + + first = false; + idx = 0; + frag_len = 0; + constituents = buffer; + } + + if ((void *)constituents - buffer > max_fragsize) { + pr_err("Memory Region Fragment > Tx Buffer size\n"); + return -EFAULT; + } + + constituents->address = sg_phys(args->sg); + constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE; + constituents++; + frag_len += sizeof(struct ffa_mem_region_addr_range); + } while ((args->sg = sg_next(args->sg))); + + return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len, + length, &args->g_handle, first); +} + +static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args) +{ + int ret; + void *buffer; + + if (!args->use_txbuf) { + buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + } else { + buffer = drv_info->tx_buffer; + mutex_lock(&drv_info->tx_lock); + } + + ret = ffa_setup_and_transmit(func_id, buffer, RXTX_BUFFER_SIZE, args); + + if (args->use_txbuf) + mutex_unlock(&drv_info->tx_lock); + else + free_pages_exact(buffer, RXTX_BUFFER_SIZE); + + return ret < 0 ? ret : 0; +} + +static int ffa_memory_reclaim(u64 g_handle, u32 flags) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_MEM_RECLAIM, + .a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle), + .a3 = flags, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + +static u32 ffa_api_version_get(void) +{ + return drv_info->version; +} + +static int ffa_partition_info_get(const char *uuid_str, + struct ffa_partition_info *buffer) +{ + int count; + uuid_t uuid; + struct ffa_partition_info *pbuf; + + if (uuid_parse(uuid_str, &uuid)) { + pr_err("invalid uuid (%s)\n", uuid_str); + return -ENODEV; + } + + count = ffa_partition_probe(&uuid_null, &pbuf); + if (count <= 0) + return -ENOENT; + + memcpy(buffer, pbuf, sizeof(*pbuf) * count); + kfree(pbuf); + return 0; +} + +static void ffa_mode_32bit_set(struct ffa_device *dev) +{ + dev->mode_32bit = true; +} + +static int ffa_sync_send_receive(struct ffa_device *dev, + struct ffa_send_direct_data *data) +{ + return ffa_msg_send_direct_req(drv_info->vm_id, dev->vm_id, + dev->mode_32bit, data); +} + +static int +ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args) +{ + if (dev->mode_32bit) + return ffa_memory_ops(FFA_MEM_SHARE, args); + + return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args); +} + +static const struct ffa_dev_ops ffa_ops = { + .api_version_get = ffa_api_version_get, + .partition_info_get = ffa_partition_info_get, + .mode_32bit_set = ffa_mode_32bit_set, + .sync_send_receive = ffa_sync_send_receive, + .memory_reclaim = ffa_memory_reclaim, + .memory_share = ffa_memory_share, +}; + +const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) +{ + if (ffa_device_is_valid(dev)) + return &ffa_ops; + + return NULL; +} +EXPORT_SYMBOL_GPL(ffa_dev_ops_get); + +void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) +{ + int count, idx; + struct ffa_partition_info *pbuf, *tpbuf; + + count = ffa_partition_probe(uuid, &pbuf); + if (count <= 0) + return; + + for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) + if (tpbuf->id == ffa_dev->vm_id) + uuid_copy(&ffa_dev->uuid, uuid); + kfree(pbuf); +} + +static void ffa_setup_partitions(void) +{ + int count, idx; + struct ffa_device *ffa_dev; + struct ffa_partition_info *pbuf, *tpbuf; + + count = ffa_partition_probe(&uuid_null, &pbuf); + if (count <= 0) { + pr_info("%s: No partitions found, error %d\n", __func__, count); + return; + } + + for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { + /* Note that the &uuid_null parameter will require + * ffa_device_match() to find the UUID of this partition id + * with help of ffa_device_match_uuid(). Once the FF-A spec + * is updated to provide correct UUID here for each partition + * as part of the discovery API, we need to pass the + * discovered UUID here instead. + */ + ffa_dev = ffa_device_register(&uuid_null, tpbuf->id); + if (!ffa_dev) { + pr_err("%s: failed to register partition ID 0x%x\n", + __func__, tpbuf->id); + continue; + } + + ffa_dev_set_drvdata(ffa_dev, drv_info); + } + kfree(pbuf); +} + +static int __init ffa_init(void) +{ + int ret; + + ret = ffa_transport_init(&invoke_ffa_fn); + if (ret) + return ret; + + ret = arm_ffa_bus_init(); + if (ret) + return ret; + + drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL); + if (!drv_info) { + ret = -ENOMEM; + goto ffa_bus_exit; + } + + ret = ffa_version_check(&drv_info->version); + if (ret) + goto free_drv_info; + + if (ffa_id_get(&drv_info->vm_id)) { + pr_err("failed to obtain VM id for self\n"); + ret = -ENODEV; + goto free_drv_info; + } + + drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + if (!drv_info->rx_buffer) { + ret = -ENOMEM; + goto free_pages; + } + + drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + if (!drv_info->tx_buffer) { + ret = -ENOMEM; + goto free_pages; + } + + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), + RXTX_BUFFER_SIZE / FFA_PAGE_SIZE); + if (ret) { + pr_err("failed to register FFA RxTx buffers\n"); + goto free_pages; + } + + mutex_init(&drv_info->rx_lock); + mutex_init(&drv_info->tx_lock); + + ffa_setup_partitions(); + + return 0; +free_pages: + if (drv_info->tx_buffer) + free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); + free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); +free_drv_info: + kfree(drv_info); +ffa_bus_exit: + arm_ffa_bus_exit(); + return ret; +} +subsys_initcall(ffa_init); + +static void __exit ffa_exit(void) +{ + ffa_rxtx_unmap(drv_info->vm_id); + free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); + free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); + kfree(drv_info); + arm_ffa_bus_exit(); +} +module_exit(ffa_exit); + +MODULE_ALIAS("arm-ffa"); +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("Arm FF-A interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/arm_ffa/smccc.c b/drivers/firmware/arm_ffa/smccc.c new file mode 100644 index 000000000000..4d85bfff0a4e --- /dev/null +++ b/drivers/firmware/arm_ffa/smccc.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 ARM Ltd. + */ + +#include + +#include "common.h" + +static void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res) +{ + arm_smccc_1_2_smc(&args, res); +} + +static void __arm_ffa_fn_hvc(ffa_value_t args, ffa_value_t *res) +{ + arm_smccc_1_2_hvc(&args, res); +} + +int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) +{ + enum arm_smccc_conduit conduit; + + if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) + return -EOPNOTSUPP; + + conduit = arm_smccc_1_1_get_conduit(); + if (conduit == SMCCC_CONDUIT_NONE) { + pr_err("%s: invalid SMCCC conduit\n", __func__); + return -EOPNOTSUPP; + } + + if (conduit == SMCCC_CONDUIT_SMC) + *invoke_ffa_fn = __arm_ffa_fn_smc; + else + *invoke_ffa_fn = __arm_ffa_fn_hvc; + + return 0; +} diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 228bf4a71d23..8685619d38f9 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -331,7 +331,7 @@ struct scmi_desc { }; extern const struct scmi_desc scmi_mailbox_desc; -#ifdef CONFIG_HAVE_ARM_SMCCC +#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY extern const struct scmi_desc scmi_smc_desc; #endif diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 66eb3f0e5daf..66e5e694be7d 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -241,7 +241,6 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle, xfer = &minfo->xfer_block[xfer_id]; xfer->hdr.seq = xfer_id; - reinit_completion(&xfer->done); xfer->transfer_id = atomic_inc_return(&transfer_last_id); return xfer; @@ -335,6 +334,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, return; } + /* rx.len could be shrunk in the sync do_xfer, so reset to maxsz */ + if (msg_type == MSG_TYPE_DELAYED_RESP) + xfer->rx.len = info->desc->max_msg_size; + scmi_dump_header_dbg(dev, &xfer->hdr); info->desc->ops->fetch_response(cinfo, xfer); @@ -429,11 +432,12 @@ static int do_xfer(const struct scmi_protocol_handle *ph, struct scmi_chan_info *cinfo; /* - * Re-instate protocol id here from protocol handle so that cannot be + * Initialise protocol id now from protocol handle to avoid it being * overridden by mistake (or malice) by the protocol code mangling with - * the scmi_xfer structure. + * the scmi_xfer structure prior to this. */ xfer->hdr.protocol_id = pi->proto->id; + reinit_completion(&xfer->done); cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id); if (unlikely(!cinfo)) @@ -505,16 +509,17 @@ static int do_xfer_with_response(const struct scmi_protocol_handle *ph, struct scmi_xfer *xfer) { int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); - const struct scmi_protocol_instance *pi = ph_to_pi(ph); DECLARE_COMPLETION_ONSTACK(async_response); - xfer->hdr.protocol_id = pi->proto->id; - xfer->async_done = &async_response; ret = do_xfer(ph, xfer); - if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout)) - ret = -ETIMEDOUT; + if (!ret) { + if (!wait_for_completion_timeout(xfer->async_done, timeout)) + ret = -ETIMEDOUT; + else if (xfer->hdr.status) + ret = scmi_to_linux_errno(xfer->hdr.status); + } xfer->async_done = NULL; return ret; @@ -561,7 +566,6 @@ static int xfer_get_init(const struct scmi_protocol_handle *ph, xfer->tx.len = tx_size; xfer->rx.len = rx_size ? : info->desc->max_msg_size; xfer->hdr.id = msg_id; - xfer->hdr.protocol_id = pi->proto->id; xfer->hdr.poll_completion = false; *p = xfer; @@ -1567,7 +1571,9 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { +#ifdef CONFIG_MAILBOX { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, +#endif #ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, #endif diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 4626404be541..e3dcb58314ae 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -69,6 +69,9 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, return -ENOMEM; shmem = of_parse_phandle(cdev->of_node, "shmem", idx); + if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) + return -ENXIO; + ret = of_address_to_resource(shmem, 0, &res); of_node_put(shmem); if (ret) { diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c index 9d36d5c0622d..4371fdcd5a73 100644 --- a/drivers/firmware/arm_scmi/scmi_pm_domain.c +++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,27 @@ static int scmi_pd_power_off(struct generic_pm_domain *domain) return scmi_pd_power(domain, false); } +static int scmi_pd_attach_dev(struct generic_pm_domain *pd, struct device *dev) +{ + int ret; + + ret = pm_clk_create(dev); + if (ret) + return ret; + + ret = of_pm_clk_add_clks(dev); + if (ret >= 0) + return 0; + + pm_clk_destroy(dev); + return ret; +} + +static void scmi_pd_detach_dev(struct generic_pm_domain *pd, struct device *dev) +{ + pm_clk_destroy(dev); +} + static int scmi_pm_domain_probe(struct scmi_device *sdev) { int num_domains, i; @@ -102,6 +124,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) scmi_pd->genpd.name = scmi_pd->name; scmi_pd->genpd.power_off = scmi_pd_power_off; scmi_pd->genpd.power_on = scmi_pd_power_on; + scmi_pd->genpd.attach_dev = scmi_pd_attach_dev; + scmi_pd->genpd.detach_dev = scmi_pd_detach_dev; + scmi_pd->genpd.flags = GENPD_FLAG_PM_CLK | + GENPD_FLAG_ACTIVE_WAKEUP; pm_genpd_init(&scmi_pd->genpd, NULL, state == SCMI_POWER_STATE_GENERIC_OFF); diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index fcbe2677f84b..bed5596c7209 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -76,6 +76,9 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, return -ENOMEM; np = of_parse_phandle(cdev->of_node, "shmem", 0); + if (!of_device_is_compatible(np, "arm,scmi-shmem")) + return -ENXIO; + ret = of_address_to_resource(np, 0, &res); of_node_put(np); if (ret) { diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 4ceba5ef7895..ddf0b9ff9e15 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -899,6 +899,14 @@ static const struct of_device_id legacy_scpi_of_match[] = { {}, }; +static const struct of_device_id shmem_of_match[] __maybe_unused = { + { .compatible = "amlogic,meson-gxbb-scp-shmem", }, + { .compatible = "amlogic,meson-axg-scp-shmem", }, + { .compatible = "arm,juno-scp-shmem", }, + { .compatible = "arm,scp-shmem", }, + { } +}; + static int scpi_probe(struct platform_device *pdev) { int count, idx, ret; @@ -935,6 +943,9 @@ static int scpi_probe(struct platform_device *pdev) struct mbox_client *cl = &pchan->cl; struct device_node *shmem = of_parse_phandle(np, "shmem", idx); + if (!of_match_node(shmem_of_match, shmem)) + return -ENXIO; + ret = of_address_to_resource(shmem, 0, &res); of_node_put(shmem); if (ret) { diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index bb9ce3f92931..cb5519568822 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1281,6 +1281,9 @@ static const struct of_device_id qcom_scm_dt_match[] = { SCM_HAS_BUS_CLK) }, { .compatible = "qcom,scm-ipq4019" }, + { .compatible = "qcom,scm-mdm9607", .data = (void *)(SCM_HAS_CORE_CLK | + SCM_HAS_IFACE_CLK | + SCM_HAS_BUS_CLK) }, { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile index 49c87e00fafb..620cf3fdd607 100644 --- a/drivers/firmware/tegra/Makefile +++ b/drivers/firmware/tegra/Makefile @@ -3,6 +3,7 @@ tegra-bpmp-y = bpmp.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_210_SOC) += bpmp-tegra210.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_186_SOC) += bpmp-tegra186.o tegra-bpmp-$(CONFIG_ARCH_TEGRA_194_SOC) += bpmp-tegra186.o +tegra-bpmp-$(CONFIG_ARCH_TEGRA_234_SOC) += bpmp-tegra186.o tegra-bpmp-$(CONFIG_DEBUG_FS) += bpmp-debugfs.o obj-$(CONFIG_TEGRA_BPMP) += tegra-bpmp.o obj-$(CONFIG_TEGRA_IVC) += ivc.o diff --git a/drivers/firmware/tegra/bpmp-private.h b/drivers/firmware/tegra/bpmp-private.h index 54d560c48398..182bfe396516 100644 --- a/drivers/firmware/tegra/bpmp-private.h +++ b/drivers/firmware/tegra/bpmp-private.h @@ -24,7 +24,8 @@ struct tegra_bpmp_ops { }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) extern const struct tegra_bpmp_ops tegra186_bpmp_ops; #endif #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/firmware/tegra/bpmp-tegra210.c b/drivers/firmware/tegra/bpmp-tegra210.c index ae15940a078e..c32754055c60 100644 --- a/drivers/firmware/tegra/bpmp-tegra210.c +++ b/drivers/firmware/tegra/bpmp-tegra210.c @@ -210,7 +210,7 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp) priv->tx_irq_data = irq_get_irq_data(err); if (!priv->tx_irq_data) { dev_err(&pdev->dev, "failed to get IRQ data for TX IRQ\n"); - return err; + return -ENOENT; } err = platform_get_irq_byname(pdev, "rx"); diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 0742a90cb844..5654c5e9862b 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -809,7 +809,8 @@ static const struct dev_pm_ops tegra_bpmp_pm_ops = { }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) static const struct tegra_bpmp_soc tegra186_soc = { .channels = { .cpu_tx = { diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 62f0d1a5dd32..c2d34dc8ba46 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -147,11 +147,14 @@ MOX_ATTR_RO(pubkey, "%s\n", pubkey); static int mox_get_status(enum mbox_cmd cmd, u32 retval) { - if (MBOX_STS_CMD(retval) != cmd || - MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS) + if (MBOX_STS_CMD(retval) != cmd) return -EIO; else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(retval); + else if (MBOX_STS_ERROR(retval) == MBOX_STS_BADCMD) + return -ENOSYS; + else if (MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS) + return -EIO; else return MBOX_STS_VALUE(retval); } @@ -201,11 +204,14 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) return ret; ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval); - if (ret < 0 && ret != -ENODATA) { - return ret; - } else if (ret == -ENODATA) { + if (ret == -ENODATA) { dev_warn(rwtm->dev, "Board does not have manufacturing information burned!\n"); + } else if (ret == -ENOSYS) { + dev_notice(rwtm->dev, + "Firmware does not support the BOARD_INFO command\n"); + } else if (ret < 0) { + return ret; } else { rwtm->serial_number = reply->status[1]; rwtm->serial_number <<= 32; @@ -234,10 +240,13 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) return ret; ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); - if (ret < 0 && ret != -ENODATA) { - return ret; - } else if (ret == -ENODATA) { + if (ret == -ENODATA) { dev_warn(rwtm->dev, "Board has no public key burned!\n"); + } else if (ret == -ENOSYS) { + dev_notice(rwtm->dev, + "Firmware does not support the ECDSA_PUB_KEY command\n"); + } else if (ret < 0) { + return ret; } else { u32 *s = reply->status; @@ -251,6 +260,27 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) return 0; } +static int check_get_random_support(struct mox_rwtm *rwtm) +{ + struct armada_37xx_rwtm_tx_msg msg; + int ret; + + msg.command = MBOX_CMD_GET_RANDOM; + msg.args[0] = 1; + msg.args[1] = rwtm->buf_phys; + msg.args[2] = 4; + + ret = mbox_send_message(rwtm->mbox, &msg); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); + if (ret < 0) + return ret; + + return mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval); +} + static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv; @@ -488,6 +518,13 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) if (ret < 0) dev_warn(dev, "Cannot read board information: %i\n", ret); + ret = check_get_random_support(rwtm); + if (ret < 0) { + dev_notice(dev, + "Firmware does not support the GET_RANDOM command\n"); + goto free_channel; + } + rwtm->hwrng.name = DRIVER_NAME "_hwrng"; rwtm->hwrng.read = mox_hwrng_read; rwtm->hwrng.priv = (unsigned long) rwtm; @@ -505,6 +542,8 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) goto free_channel; } + dev_info(dev, "HWRNG successfully registered\n"); + return 0; free_channel: @@ -530,6 +569,7 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev) static const struct of_device_id turris_mox_rwtm_match[] = { { .compatible = "cznic,turris-mox-rwtm", }, + { .compatible = "marvell,armada-3700-rwtm-firmware", }, { }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 130a9adf09ef..d303e88e3c23 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1369,6 +1369,38 @@ def_value: adev->pm.smu_prv_buffer_size = 0; } +static int amdgpu_device_init_apu_flags(struct amdgpu_device *adev) +{ + if (!(adev->flags & AMD_IS_APU) || + adev->asic_type < CHIP_RAVEN) + return 0; + + switch (adev->asic_type) { + case CHIP_RAVEN: + if (adev->pdev->device == 0x15dd) + adev->apu_flags |= AMD_APU_IS_RAVEN; + if (adev->pdev->device == 0x15d8) + adev->apu_flags |= AMD_APU_IS_PICASSO; + break; + case CHIP_RENOIR: + if ((adev->pdev->device == 0x1636) || + (adev->pdev->device == 0x164c)) + adev->apu_flags |= AMD_APU_IS_RENOIR; + else + adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE; + break; + case CHIP_VANGOGH: + adev->apu_flags |= AMD_APU_IS_VANGOGH; + break; + case CHIP_YELLOW_CARP: + break; + default: + return -EINVAL; + } + + return 0; +} + /** * amdgpu_device_check_arguments - validate module params * @@ -3386,6 +3418,10 @@ int amdgpu_device_init(struct amdgpu_device *adev, mutex_init(&adev->psp.mutex); mutex_init(&adev->notifier_lock); + r = amdgpu_device_init_apu_flags(adev); + if (r) + return r; + r = amdgpu_device_check_arguments(adev); if (r) return r; @@ -4304,6 +4340,7 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: case CHIP_DIMGREY_CAVEFISH: + case CHIP_BEIGE_GOBY: case CHIP_VANGOGH: case CHIP_ALDEBARAN: break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 6f30c525caac..71beb0db0125 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -160,6 +160,7 @@ int amdgpu_smu_pptable_id = -1; * highest. That helps saving some idle power. * DISABLE_FRACTIONAL_PWM (bit 2) disabled by default * PSR (bit 3) disabled by default + * EDP NO POWER SEQUENCING (bit 4) disabled by default */ uint amdgpu_dc_feature_mask = 2; uint amdgpu_dc_debug_mask; @@ -1198,6 +1199,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x73E0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH}, {0x1002, 0x73E1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH}, {0x1002, 0x73E2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH}, + {0x1002, 0x73E3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH}, {0x1002, 0x73FF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH}, /* Aldebaran */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 0174f7817ce2..d0b8d415b63b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -562,6 +562,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) case CHIP_NAVI14: case CHIP_NAVI12: case CHIP_VANGOGH: + case CHIP_YELLOW_CARP: /* Don't enable it by default yet. */ if (amdgpu_tmz < 1) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index d6c54c7f7679..4b153daf283d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -160,7 +160,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked) + bool mmap_locked, void *owner) { struct hmm_range *hmm_range; unsigned long timeout; @@ -185,6 +185,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, hmm_range->hmm_pfns = pfns; hmm_range->start = start; hmm_range->end = start + npages * PAGE_SIZE; + hmm_range->dev_private_owner = owner; /* Assuming 512MB takes maxmium 1 second to fault page address */ timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h index 7f7d37a457c3..14a3c1864085 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h @@ -34,7 +34,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, struct mm_struct *mm, struct page **pages, uint64_t start, uint64_t npages, struct hmm_range **phmm_range, bool readonly, - bool mmap_locked); + bool mmap_locked, void *owner); int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range); #if defined(CONFIG_HMM_MIRROR) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h index 25ee53545837..45295dce5c3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h @@ -93,6 +93,8 @@ struct amdgpu_nbio_funcs { void (*enable_aspm)(struct amdgpu_device *adev, bool enable); void (*program_aspm)(struct amdgpu_device *adev); + void (*apply_lc_spc_mode_wa)(struct amdgpu_device *adev); + void (*apply_l1_link_width_reconfig_wa)(struct amdgpu_device *adev); }; struct amdgpu_nbio { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index cdfc20b0b2eb..3a55f08e00e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -590,10 +590,6 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev, mem->bus.offset += adev->gmc.aper_base; mem->bus.is_iomem = true; - if (adev->gmc.xgmi.connected_to_cpu) - mem->bus.caching = ttm_cached; - else - mem->bus.caching = ttm_write_combined; break; default: return -EINVAL; @@ -695,7 +691,7 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages) readonly = amdgpu_ttm_tt_is_readonly(ttm); r = amdgpu_hmm_range_get_pages(&bo->notifier, mm, pages, start, ttm->num_pages, >t->range, readonly, - true); + true, NULL); out_unlock: mmap_read_unlock(mm); mmput(mm); @@ -923,7 +919,8 @@ static int amdgpu_ttm_backend_bind(struct ttm_device *bdev, bo_mem->mem_type == AMDGPU_PL_OA) return -EINVAL; - if (!amdgpu_gtt_mgr_has_gart_addr(bo_mem)) { + if (bo_mem->mem_type != TTM_PL_TT || + !amdgpu_gtt_mgr_has_gart_addr(bo_mem)) { gtt->offset = AMDGPU_BO_INVALID_OFFSET; return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 436ec246a7da..2fd77c36a1ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -463,6 +463,11 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, if (i == 1) node->base.placement |= TTM_PL_FLAG_CONTIGUOUS; + if (adev->gmc.xgmi.connected_to_cpu) + node->base.bus.caching = ttm_cached; + else + node->base.bus.caching = ttm_write_combined; + atomic64_add(vis_usage, &mgr->vis_usage); *res = &node->base; return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c index 5b90efd6f6d0..3ac505d954c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c @@ -36,9 +36,12 @@ athub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *adev, { uint32_t def, data; + if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) + return; + def = data = RREG32_SOC15(ATHUB, 0, mmATHUB_MISC_CNTL); - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) + if (enable) data |= ATHUB_MISC_CNTL__CG_ENABLE_MASK; else data &= ~ATHUB_MISC_CNTL__CG_ENABLE_MASK; @@ -53,10 +56,13 @@ athub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *adev, { uint32_t def, data; + if (!((adev->cg_flags & AMD_CG_SUPPORT_MC_LS) && + (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))) + return; + def = data = RREG32_SOC15(ATHUB, 0, mmATHUB_MISC_CNTL); - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS) && - (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)) + if (enable) data |= ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK; else data &= ~ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 2d56b60bc058..f5e9c022960b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -5086,47 +5086,44 @@ static void gfx_v10_0_tcp_harvest(struct amdgpu_device *adev) 4 + /* RMI */ 1); /* SQG */ - if (adev->asic_type == CHIP_NAVI10 || - adev->asic_type == CHIP_NAVI14 || - adev->asic_type == CHIP_NAVI12) { - mutex_lock(&adev->grbm_idx_mutex); - for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { - for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { - gfx_v10_0_select_se_sh(adev, i, j, 0xffffffff); - wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev); - /* - * Set corresponding TCP bits for the inactive WGPs in - * GCRD_SA_TARGETS_DISABLE - */ - gcrd_targets_disable_tcp = 0; - /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */ - utcl_invreq_disable = 0; + mutex_lock(&adev->grbm_idx_mutex); + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { + gfx_v10_0_select_se_sh(adev, i, j, 0xffffffff); + wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev); + /* + * Set corresponding TCP bits for the inactive WGPs in + * GCRD_SA_TARGETS_DISABLE + */ + gcrd_targets_disable_tcp = 0; + /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */ + utcl_invreq_disable = 0; - for (k = 0; k < max_wgp_per_sh; k++) { - if (!(wgp_active_bitmap & (1 << k))) { - gcrd_targets_disable_tcp |= 3 << (2 * k); - utcl_invreq_disable |= (3 << (2 * k)) | - (3 << (2 * (max_wgp_per_sh + k))); - } + for (k = 0; k < max_wgp_per_sh; k++) { + if (!(wgp_active_bitmap & (1 << k))) { + gcrd_targets_disable_tcp |= 3 << (2 * k); + gcrd_targets_disable_tcp |= 1 << (k + (max_wgp_per_sh * 2)); + utcl_invreq_disable |= (3 << (2 * k)) | + (3 << (2 * (max_wgp_per_sh + k))); } - - tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE); - /* only override TCP & SQC bits */ - tmp &= 0xffffffff << (4 * max_wgp_per_sh); - tmp |= (utcl_invreq_disable & utcl_invreq_disable_mask); - WREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE, tmp); - - tmp = RREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE); - /* only override TCP bits */ - tmp &= 0xffffffff << (2 * max_wgp_per_sh); - tmp |= (gcrd_targets_disable_tcp & gcrd_targets_disable_mask); - WREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE, tmp); } - } - gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); - mutex_unlock(&adev->grbm_idx_mutex); + tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE); + /* only override TCP & SQC bits */ + tmp &= (0xffffffffU << (4 * max_wgp_per_sh)); + tmp |= (utcl_invreq_disable & utcl_invreq_disable_mask); + WREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE, tmp); + + tmp = RREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE); + /* only override TCP & SQC bits */ + tmp &= (0xffffffffU << (3 * max_wgp_per_sh)); + tmp |= (gcrd_targets_disable_tcp & gcrd_targets_disable_mask); + WREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE, tmp); + } } + + gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); + mutex_unlock(&adev->grbm_idx_mutex); } static void gfx_v10_0_get_tcc_info(struct amdgpu_device *adev) @@ -7404,7 +7401,10 @@ static int gfx_v10_0_hw_init(void *handle) * init golden registers and rlc resume may override some registers, * reconfig them here */ - gfx_v10_0_tcp_harvest(adev); + if (adev->asic_type == CHIP_NAVI10 || + adev->asic_type == CHIP_NAVI14 || + adev->asic_type == CHIP_NAVI12) + gfx_v10_0_tcp_harvest(adev); r = gfx_v10_0_cp_resume(adev); if (r) @@ -7777,6 +7777,9 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade { uint32_t data, def; + if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS))) + return; + /* It is disabled by HW by default */ if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { /* 0 - Disable some blocks' MGCG */ @@ -7791,6 +7794,7 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK | + RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK); if (def != data) @@ -7813,13 +7817,15 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data); } } - } else { + } else if (!enable || !(adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { /* 1 - MGCG_OVERRIDE */ def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); data |= (RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK | - RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK); + RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK | + RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK | + RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK); if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); @@ -7845,22 +7851,34 @@ static void gfx_v10_0_update_3d_clock_gating(struct amdgpu_device *adev, { uint32_t data, def; + if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_3D_CGCG | AMD_CG_SUPPORT_GFX_3D_CGLS))) + return; + /* Enable 3D CGCG/CGLS */ - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)) { + if (enable) { /* write cmd to clear cgcg/cgls ov */ def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); + /* unset CGCG override */ - data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE_MASK; + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG) + data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE_MASK; + /* update CGCG and CGLS override bits */ if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); + /* enable 3Dcgcg FSM(0x0000363f) */ def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D); - data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | - RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK; + data = 0; + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG) + data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | + RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK; + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS) data |= (0x000F << RLC_CGCG_CGLS_CTRL_3D__CGLS_REP_COMPANSAT_DELAY__SHIFT) | RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK; + if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data); @@ -7873,9 +7891,14 @@ static void gfx_v10_0_update_3d_clock_gating(struct amdgpu_device *adev, } else { /* Disable CGCG/CGLS */ def = data = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D); + /* disable cgcg, cgls should be disabled */ - data &= ~(RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK | - RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK); + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG) + data &= ~RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK; + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS) + data &= ~RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK; + /* disable cgcg and cgls in FSM */ if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data); @@ -7887,25 +7910,35 @@ static void gfx_v10_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade { uint32_t def, data; - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) { + if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS))) + return; + + if (enable) { def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); + /* unset CGCG override */ - data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE_MASK; + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG) + data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE_MASK; + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE_MASK; - else - data |= RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE_MASK; + /* update CGCG and CGLS override bits */ if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); /* enable cgcg FSM(0x0000363F) */ def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL); - data = (0x36 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | - RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK; + data = 0; + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG) + data = (0x36 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | + RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK; + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) data |= (0x000F << RLC_CGCG_CGLS_CTRL__CGLS_REP_COMPANSAT_DELAY__SHIFT) | RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK; + if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data); @@ -7917,8 +7950,14 @@ static void gfx_v10_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_CNTL, data); } else { def = data = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL); + /* reset CGCG/CGLS bits */ - data &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK | RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK); + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG) + data &= ~RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK; + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) + data &= ~RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK; + /* disable cgcg and cgls in FSM */ if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data); @@ -7930,7 +7969,10 @@ static void gfx_v10_0_update_fine_grain_clock_gating(struct amdgpu_device *adev, { uint32_t def, data; - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_FGCG)) { + if (!(adev->cg_flags & AMD_CG_SUPPORT_GFX_FGCG)) + return; + + if (enable) { def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); /* unset FGCG override */ data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK; @@ -7961,6 +8003,97 @@ static void gfx_v10_0_update_fine_grain_clock_gating(struct amdgpu_device *adev, } } +static void gfx_v10_0_apply_medium_grain_clock_gating_workaround(struct amdgpu_device *adev) +{ + uint32_t reg_data = 0; + uint32_t reg_idx = 0; + uint32_t i; + + const uint32_t tcp_ctrl_regs[] = { + mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP00_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP01_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP01_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP02_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP02_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP10_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP10_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP11_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP11_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP12_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP12_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP00_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP00_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP01_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP01_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP02_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP02_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP10_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP10_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP11_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP11_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP12_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP12_CU1_TCP_CTRL_REG + }; + + const uint32_t tcp_ctrl_regs_nv12[] = { + mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP00_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP01_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP01_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP02_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP02_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP10_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP10_CU1_TCP_CTRL_REG, + mmCGTS_SA0_WGP11_CU0_TCP_CTRL_REG, + mmCGTS_SA0_WGP11_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP00_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP00_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP01_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP01_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP02_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP02_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP10_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP10_CU1_TCP_CTRL_REG, + mmCGTS_SA1_WGP11_CU0_TCP_CTRL_REG, + mmCGTS_SA1_WGP11_CU1_TCP_CTRL_REG, + }; + + const uint32_t sm_ctlr_regs[] = { + mmCGTS_SA0_QUAD0_SM_CTRL_REG, + mmCGTS_SA0_QUAD1_SM_CTRL_REG, + mmCGTS_SA1_QUAD0_SM_CTRL_REG, + mmCGTS_SA1_QUAD1_SM_CTRL_REG + }; + + if (adev->asic_type == CHIP_NAVI12) { + for (i = 0; i < ARRAY_SIZE(tcp_ctrl_regs_nv12); i++) { + reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG_BASE_IDX] + + tcp_ctrl_regs_nv12[i]; + reg_data = RREG32(reg_idx); + reg_data |= CGTS_SA0_WGP00_CU0_TCP_CTRL_REG__TCPI_LS_OVERRIDE_MASK; + WREG32(reg_idx, reg_data); + } + } else { + for (i = 0; i < ARRAY_SIZE(tcp_ctrl_regs); i++) { + reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG_BASE_IDX] + + tcp_ctrl_regs[i]; + reg_data = RREG32(reg_idx); + reg_data |= CGTS_SA0_WGP00_CU0_TCP_CTRL_REG__TCPI_LS_OVERRIDE_MASK; + WREG32(reg_idx, reg_data); + } + } + + for (i = 0; i < ARRAY_SIZE(sm_ctlr_regs); i++) { + reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_QUAD0_SM_CTRL_REG_BASE_IDX] + + sm_ctlr_regs[i]; + reg_data = RREG32(reg_idx); + reg_data &= ~CGTS_SA0_QUAD0_SM_CTRL_REG__SM_MODE_MASK; + reg_data |= 2 << CGTS_SA0_QUAD0_SM_CTRL_REG__SM_MODE__SHIFT; + WREG32(reg_idx, reg_data); + } +} + static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev, bool enable) { @@ -7977,6 +8110,10 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev, gfx_v10_0_update_3d_clock_gating(adev, enable); /* === CGCG + CGLS === */ gfx_v10_0_update_coarse_grain_clock_gating(adev, enable); + + if ((adev->asic_type >= CHIP_NAVI10) && + (adev->asic_type <= CHIP_NAVI12)) + gfx_v10_0_apply_medium_grain_clock_gating_workaround(adev); } else { /* CGCG/CGLS should be disabled before MGCG/MGLS * === CGCG + CGLS === @@ -9324,17 +9461,22 @@ static void gfx_v10_0_set_user_wgp_inactive_bitmap_per_sh(struct amdgpu_device * static u32 gfx_v10_0_get_wgp_active_bitmap_per_sh(struct amdgpu_device *adev) { - u32 data, wgp_bitmask; - data = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG); - data |= RREG32_SOC15(GC, 0, mmGC_USER_SHADER_ARRAY_CONFIG); + u32 disabled_mask = + ~amdgpu_gfx_create_bitmask(adev->gfx.config.max_cu_per_sh >> 1); + u32 efuse_setting = 0; + u32 vbios_setting = 0; - data &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK; - data >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT; + efuse_setting = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG); + efuse_setting &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK; + efuse_setting >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT; - wgp_bitmask = - amdgpu_gfx_create_bitmask(adev->gfx.config.max_cu_per_sh >> 1); + vbios_setting = RREG32_SOC15(GC, 0, mmGC_USER_SHADER_ARRAY_CONFIG); + vbios_setting &= GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK; + vbios_setting >>= GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT; - return (~data) & wgp_bitmask; + disabled_mask |= efuse_setting | vbios_setting; + + return (~disabled_mask); } static u32 gfx_v10_0_get_cu_active_bitmap_per_sh(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c index 7a15e669b68d..5793977953cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c @@ -90,45 +90,56 @@ static void hdp_v5_0_update_mem_power_gating(struct amdgpu_device *adev, RC_MEM_POWER_SD_EN, 0); WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl); - /* only one clock gating mode (LS/DS/SD) can be enabled */ - if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) { - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - IPH_MEM_POWER_LS_EN, enable); - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - RC_MEM_POWER_LS_EN, enable); - } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) { - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - IPH_MEM_POWER_DS_EN, enable); - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - RC_MEM_POWER_DS_EN, enable); - } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) { - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - IPH_MEM_POWER_SD_EN, enable); - /* RC should not use shut down mode, fallback to ds */ - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, - HDP_MEM_POWER_CTRL, - RC_MEM_POWER_DS_EN, enable); + /* Already disabled above. The actions below are for "enabled" only */ + if (enable) { + /* only one clock gating mode (LS/DS/SD) can be enabled */ + if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) { + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + IPH_MEM_POWER_LS_EN, 1); + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + RC_MEM_POWER_LS_EN, 1); + } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) { + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + IPH_MEM_POWER_DS_EN, 1); + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + RC_MEM_POWER_DS_EN, 1); + } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) { + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + IPH_MEM_POWER_SD_EN, 1); + /* RC should not use shut down mode, fallback to ds or ls if allowed */ + if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + RC_MEM_POWER_DS_EN, 1); + else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, + HDP_MEM_POWER_CTRL, + RC_MEM_POWER_LS_EN, 1); + } + + /* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to + * be set for SRAM LS/DS/SD */ + if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS | + AMD_CG_SUPPORT_HDP_SD)) { + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL, + IPH_MEM_POWER_CTRL_EN, 1); + hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL, + RC_MEM_POWER_CTRL_EN, 1); + WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl); + } } - /* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to - * be set for SRAM LS/DS/SD */ - if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS | - AMD_CG_SUPPORT_HDP_SD)) { - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL, - IPH_MEM_POWER_CTRL_EN, 1); - hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL, - RC_MEM_POWER_CTRL_EN, 1); - } - - WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl); - - /* restore IPH & RC clock override after clock/power mode changing */ - WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl1); + /* disable IPH & RC clock override after clock/power mode changing */ + hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL, + IPH_MEM_CLK_SOFT_OVERRIDE, 0); + hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL, + RC_MEM_CLK_SOFT_OVERRIDE, 0); + WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl); } static void hdp_v5_0_update_medium_grain_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c index f7e93bbc4e15..7ded6b2f058e 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c @@ -568,6 +568,9 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad { uint32_t def, data, def1, data1; + if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) + return; + switch (adev->asic_type) { case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: @@ -582,7 +585,7 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad break; } - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) { + if (enable) { data |= MM_ATC_L2_MISC_CG__ENABLE_MASK; data1 &= ~(DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK | @@ -627,6 +630,9 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade { uint32_t def, data; + if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_LS)) + return; + switch (adev->asic_type) { case CHIP_SIENNA_CICHLID: case CHIP_NAVY_FLOUNDER: @@ -639,7 +645,7 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade break; } - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS)) + if (enable) data |= MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK; else data &= ~MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c index 05ddec7ba7e2..7b79eeaa88aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c @@ -51,6 +51,8 @@ #define mmBIF_MMSCH1_DOORBELL_RANGE 0x01d8 #define mmBIF_MMSCH1_DOORBELL_RANGE_BASE_IDX 2 +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 + static void nbio_v2_3_remap_hdp_registers(struct amdgpu_device *adev) { WREG32_SOC15(NBIO, 0, mmREMAP_HDP_MEM_FLUSH_CNTL, @@ -218,8 +220,11 @@ static void nbio_v2_3_update_medium_grain_clock_gating(struct amdgpu_device *ade { uint32_t def, data; + if (!(adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG)) + return; + def = data = RREG32_PCIE(smnCPM_CONTROL); - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG)) { + if (enable) { data |= (CPM_CONTROL__LCLK_DYN_GATE_ENABLE_MASK | CPM_CONTROL__TXCLK_DYN_GATE_ENABLE_MASK | CPM_CONTROL__TXCLK_LCNT_GATE_ENABLE_MASK | @@ -244,8 +249,11 @@ static void nbio_v2_3_update_medium_grain_light_sleep(struct amdgpu_device *adev { uint32_t def, data; + if (!(adev->cg_flags & AMD_CG_SUPPORT_BIF_LS)) + return; + def = data = RREG32_PCIE(smnPCIE_CNTL2); - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_LS)) { + if (enable) { data |= (PCIE_CNTL2__SLV_MEM_LS_EN_MASK | PCIE_CNTL2__MST_MEM_LS_EN_MASK | PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK); @@ -463,6 +471,43 @@ static void nbio_v2_3_program_aspm(struct amdgpu_device *adev) WREG32_PCIE(smnPCIE_LC_CNTL3, data); } +static void nbio_v2_3_apply_lc_spc_mode_wa(struct amdgpu_device *adev) +{ + uint32_t reg_data = 0; + uint32_t link_width = 0; + + if (!((adev->asic_type >= CHIP_NAVI10) && + (adev->asic_type <= CHIP_NAVI12))) + return; + + reg_data = RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL); + link_width = (reg_data & PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; + + /* + * Program PCIE_LC_CNTL6.LC_SPC_MODE_8GT to 0x2 (4 symbols per clock data) + * if link_width is 0x3 (x4) + */ + if (0x3 == link_width) { + reg_data = RREG32_PCIE(smnPCIE_LC_CNTL6); + reg_data &= ~PCIE_LC_CNTL6__LC_SPC_MODE_8GT_MASK; + reg_data |= (0x2 << PCIE_LC_CNTL6__LC_SPC_MODE_8GT__SHIFT); + WREG32_PCIE(smnPCIE_LC_CNTL6, reg_data); + } +} + +static void nbio_v2_3_apply_l1_link_width_reconfig_wa(struct amdgpu_device *adev) +{ + uint32_t reg_data = 0; + + if (adev->asic_type != CHIP_NAVI10) + return; + + reg_data = RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL); + reg_data |= PCIE_LC_LINK_WIDTH_CNTL__LC_L1_RECONFIG_EN_MASK; + WREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL, reg_data); +} + const struct amdgpu_nbio_funcs nbio_v2_3_funcs = { .get_hdp_flush_req_offset = nbio_v2_3_get_hdp_flush_req_offset, .get_hdp_flush_done_offset = nbio_v2_3_get_hdp_flush_done_offset, @@ -484,4 +529,6 @@ const struct amdgpu_nbio_funcs nbio_v2_3_funcs = { .remap_hdp_registers = nbio_v2_3_remap_hdp_registers, .enable_aspm = nbio_v2_3_enable_aspm, .program_aspm = nbio_v2_3_program_aspm, + .apply_lc_spc_mode_wa = nbio_v2_3_apply_lc_spc_mode_wa, + .apply_l1_link_width_reconfig_wa = nbio_v2_3_apply_l1_link_width_reconfig_wa, }; diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 455d0425787c..94a2c0742ee5 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -64,6 +64,13 @@ #include "smuio_v11_0.h" #include "smuio_v11_0_6.h" +#define codec_info_build(type, width, height, level) \ + .codec_type = type,\ + .max_width = width,\ + .max_height = height,\ + .max_pixels_per_frame = height * width,\ + .max_level = level, + static const struct amd_ip_funcs nv_common_ip_funcs; /* Navi */ @@ -309,6 +316,23 @@ static struct amdgpu_video_codecs sriov_sc_video_codecs_decode = .codec_array = sriov_sc_video_codecs_decode_array, }; +/* Beige Goby*/ +static const struct amdgpu_video_codec_info bg_video_codecs_decode_array[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs bg_video_codecs_decode = { + .codec_count = ARRAY_SIZE(bg_video_codecs_decode_array), + .codec_array = bg_video_codecs_decode_array, +}; + +static const struct amdgpu_video_codecs bg_video_codecs_encode = { + .codec_count = 0, + .codec_array = NULL, +}; + static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, const struct amdgpu_video_codecs **codecs) { @@ -335,6 +359,12 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, else *codecs = &sc_video_codecs_decode; return 0; + case CHIP_BEIGE_GOBY: + if (encode) + *codecs = &bg_video_codecs_encode; + else + *codecs = &bg_video_codecs_decode; + return 0; case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_NAVI12: @@ -1275,7 +1305,6 @@ static int nv_common_early_init(void *handle) break; case CHIP_VANGOGH: - adev->apu_flags |= AMD_APU_IS_VANGOGH; adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS | AMD_CG_SUPPORT_GFX_CP_LS | @@ -1411,6 +1440,12 @@ static int nv_common_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (adev->nbio.funcs->apply_lc_spc_mode_wa) + adev->nbio.funcs->apply_lc_spc_mode_wa(adev); + + if (adev->nbio.funcs->apply_l1_link_width_reconfig_wa) + adev->nbio.funcs->apply_l1_link_width_reconfig_wa(adev); + /* enable pcie gen2/3 link */ nv_pcie_gen3_enable(adev); /* enable aspm */ diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index ae5464e2535a..8931000dcd41 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -144,7 +144,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4_1[] = { SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC0_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_IB_CNTL, 0x800f0111, 0x00000100), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000), - SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0), + SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003e0), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x00000000) }; @@ -288,7 +288,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4_3[] = { SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_POWER_CNTL, 0x003fff07, 0x40000051), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC0_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000), - SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0), + SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003e0), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x03fbe1fe) }; @@ -1896,8 +1896,11 @@ static int sdma_v4_0_late_init(void *handle) sdma_v4_0_setup_ulv(adev); - if (adev->sdma.funcs && adev->sdma.funcs->reset_ras_error_count) - adev->sdma.funcs->reset_ras_error_count(adev); + if (!amdgpu_persistent_edc_harvesting_supported(adev)) { + if (adev->sdma.funcs && + adev->sdma.funcs->reset_ras_error_count) + adev->sdma.funcs->reset_ras_error_count(adev); + } if (adev->sdma.funcs && adev->sdma.funcs->ras_late_init) return adev->sdma.funcs->ras_late_init(adev, &ih_info); diff --git a/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c b/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c index e9c474c217ec..b6f1322f908c 100644 --- a/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c @@ -43,9 +43,12 @@ static void smuio_v11_0_update_rom_clock_gating(struct amdgpu_device *adev, bool if (adev->flags & AMD_IS_APU) return; + if (!(adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG)) + return; + def = data = RREG32_SOC15(SMUIO, 0, mmCGTT_ROM_CLK_CTRL0); - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG)) + if (enable) data &= ~(CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK | CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK); else diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index de85577c9cfd..b02436401d46 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1360,10 +1360,7 @@ static int soc15_common_early_init(void *handle) break; case CHIP_RAVEN: adev->asic_funcs = &soc15_asic_funcs; - if (adev->pdev->device == 0x15dd) - adev->apu_flags |= AMD_APU_IS_RAVEN; - if (adev->pdev->device == 0x15d8) - adev->apu_flags |= AMD_APU_IS_PICASSO; + if (adev->rev_id >= 0x8) adev->apu_flags |= AMD_APU_IS_RAVEN2; @@ -1455,11 +1452,6 @@ static int soc15_common_early_init(void *handle) break; case CHIP_RENOIR: adev->asic_funcs = &soc15_asic_funcs; - if ((adev->pdev->device == 0x1636) || - (adev->pdev->device == 0x164c)) - adev->apu_flags |= AMD_APU_IS_RENOIR; - else - adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE; if (adev->apu_flags & AMD_APU_IS_RENOIR) adev->external_rev_id = adev->rev_id + 0x91; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 2660f03e63a7..dab290a4d19d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -218,7 +218,8 @@ svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn) struct page *page; page = pfn_to_page(pfn); - page->zone_device_data = prange; + svm_range_bo_ref(prange->svm_bo); + page->zone_device_data = prange->svm_bo; get_page(page); lock_page(page); } @@ -293,15 +294,13 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange, for (i = j = 0; i < npages; i++) { struct page *spage; - dst[i] = cursor.start + (j << PAGE_SHIFT); - migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); - svm_migrate_get_vram_page(prange, migrate->dst[i]); - - migrate->dst[i] = migrate_pfn(migrate->dst[i]); - migrate->dst[i] |= MIGRATE_PFN_LOCKED; - - if (migrate->src[i] & MIGRATE_PFN_VALID) { - spage = migrate_pfn_to_page(migrate->src[i]); + spage = migrate_pfn_to_page(migrate->src[i]); + if (spage && !is_zone_device_page(spage)) { + dst[i] = cursor.start + (j << PAGE_SHIFT); + migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]); + svm_migrate_get_vram_page(prange, migrate->dst[i]); + migrate->dst[i] = migrate_pfn(migrate->dst[i]); + migrate->dst[i] |= MIGRATE_PFN_LOCKED; src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE, DMA_TO_DEVICE); r = dma_mapping_error(dev, src[i]); @@ -355,6 +354,20 @@ out_free_vram_pages: } } +#ifdef DEBUG_FORCE_MIXED_DOMAINS + for (i = 0, j = 0; i < npages; i += 4, j++) { + if (j & 1) + continue; + svm_migrate_put_vram_page(adev, dst[i]); + migrate->dst[i] = 0; + svm_migrate_put_vram_page(adev, dst[i + 1]); + migrate->dst[i + 1] = 0; + svm_migrate_put_vram_page(adev, dst[i + 2]); + migrate->dst[i + 2] = 0; + svm_migrate_put_vram_page(adev, dst[i + 3]); + migrate->dst[i + 3] = 0; + } +#endif out: return r; } @@ -365,20 +378,20 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, uint64_t end) { uint64_t npages = (end - start) >> PAGE_SHIFT; + struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; struct migrate_vma migrate; dma_addr_t *scratch; size_t size; void *buf; int r = -ENOMEM; - int retry = 0; memset(&migrate, 0, sizeof(migrate)); migrate.vma = vma; migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_SYSTEM; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -390,7 +403,6 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange, migrate.dst = migrate.src + npages; scratch = (dma_addr_t *)(migrate.dst + npages); -retry: r = migrate_vma_setup(&migrate); if (r) { pr_debug("failed %d prepare migrate svms 0x%p [0x%lx 0x%lx]\n", @@ -398,17 +410,9 @@ retry: goto out_free; } if (migrate.cpages != npages) { - pr_debug("collect 0x%lx/0x%llx pages, retry\n", migrate.cpages, + pr_debug("Partial migration. 0x%lx/0x%llx pages can be migrated\n", + migrate.cpages, npages); - migrate_vma_finalize(&migrate); - if (retry++ >= 3) { - r = -ENOMEM; - pr_debug("failed %d migrate svms 0x%p [0x%lx 0x%lx]\n", - r, prange->svms, prange->start, prange->last); - goto out_free; - } - - goto retry; } if (migrate.cpages) { @@ -425,6 +429,12 @@ retry: out_free: kvfree(buf); out: + if (!r) { + pdd = svm_range_get_pdd_by_adev(prange, adev); + if (pdd) + WRITE_ONCE(pdd->page_in, pdd->page_in + migrate.cpages); + } + return r; } @@ -464,7 +474,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, prange->start, prange->last, best_loc); /* FIXME: workaround for page locking bug with invalid pages */ - svm_range_prefault(prange, mm); + svm_range_prefault(prange, mm, SVM_ADEV_PGMAP_OWNER(adev)); start = prange->start << PAGE_SHIFT; end = (prange->last + 1) << PAGE_SHIFT; @@ -493,15 +503,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, static void svm_migrate_page_free(struct page *page) { - /* Keep this function to avoid warning */ + struct svm_range_bo *svm_bo = page->zone_device_data; + + if (svm_bo) { + pr_debug("svm_bo ref left: %d\n", kref_read(&svm_bo->kref)); + svm_range_bo_unref(svm_bo); + } } static int svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, struct migrate_vma *migrate, struct dma_fence **mfence, - dma_addr_t *scratch) + dma_addr_t *scratch, uint64_t npages) { - uint64_t npages = migrate->cpages; struct device *dev = adev->dev; uint64_t *src; dma_addr_t *dst; @@ -518,15 +532,23 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, src = (uint64_t *)(scratch + npages); dst = scratch; - for (i = 0, j = 0; i < npages; i++, j++, addr += PAGE_SIZE) { + for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) { struct page *spage; spage = migrate_pfn_to_page(migrate->src[i]); - if (!spage) { - pr_debug("failed get spage svms 0x%p [0x%lx 0x%lx]\n", + if (!spage || !is_zone_device_page(spage)) { + pr_debug("invalid page. Could be in CPU already svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start, prange->last); - r = -ENOMEM; - goto out_oom; + if (j) { + r = svm_migrate_copy_memory_gart(adev, dst + i - j, + src + i - j, j, + FROM_VRAM_TO_RAM, + mfence); + if (r) + goto out_oom; + j = 0; + } + continue; } src[i] = svm_migrate_addr(adev, spage); if (i > 0 && src[i] != src[i - 1] + PAGE_SIZE) { @@ -559,6 +581,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, migrate->dst[i] = migrate_pfn(page_to_pfn(dpage)); migrate->dst[i] |= MIGRATE_PFN_LOCKED; + j++; } r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j, @@ -581,6 +604,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, struct vm_area_struct *vma, uint64_t start, uint64_t end) { uint64_t npages = (end - start) >> PAGE_SHIFT; + struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; struct migrate_vma migrate; dma_addr_t *scratch; @@ -593,7 +617,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, migrate.start = start; migrate.end = end; migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; - migrate.pgmap_owner = adev; + migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev); size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t); size *= npages; @@ -616,7 +640,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, if (migrate.cpages) { r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, - scratch); + scratch, npages); migrate_vma_pages(&migrate); svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(&migrate); @@ -630,6 +654,12 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange, out_free: kvfree(buf); out: + if (!r) { + pdd = svm_range_get_pdd_by_adev(prange, adev); + if (pdd) + WRITE_ONCE(pdd->page_out, + pdd->page_out + migrate.cpages); + } return r; } @@ -859,7 +889,7 @@ int svm_migrate_init(struct amdgpu_device *adev) pgmap->range.start = res->start; pgmap->range.end = res->end; pgmap->ops = &svm_migrate_pgmap_ops; - pgmap->owner = adev; + pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev); pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE; r = devm_memremap_pages(adev->dev, pgmap); if (IS_ERR(r)) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 6dc22fa1e555..3426743ed228 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -730,6 +730,15 @@ struct kfd_process_device { * number of CU's a device has along with number of other competing processes */ struct attribute attr_cu_occupancy; + + /* sysfs counters for GPU retry fault and page migration tracking */ + struct kobject *kobj_counters; + struct attribute attr_faults; + struct attribute attr_page_in; + struct attribute attr_page_out; + uint64_t faults; + uint64_t page_in; + uint64_t page_out; }; #define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 09b98a83f670..21ec8a18cad2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -416,6 +416,29 @@ static ssize_t kfd_procfs_stats_show(struct kobject *kobj, return 0; } +static ssize_t kfd_sysfs_counters_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct kfd_process_device *pdd; + + if (!strcmp(attr->name, "faults")) { + pdd = container_of(attr, struct kfd_process_device, + attr_faults); + return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->faults)); + } + if (!strcmp(attr->name, "page_in")) { + pdd = container_of(attr, struct kfd_process_device, + attr_page_in); + return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_in)); + } + if (!strcmp(attr->name, "page_out")) { + pdd = container_of(attr, struct kfd_process_device, + attr_page_out); + return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_out)); + } + return 0; +} + static struct attribute attr_queue_size = { .name = "size", .mode = KFD_SYSFS_FILE_MODE @@ -451,13 +474,18 @@ static const struct sysfs_ops procfs_stats_ops = { .show = kfd_procfs_stats_show, }; -static struct attribute *procfs_stats_attrs[] = { - NULL -}; - static struct kobj_type procfs_stats_type = { .sysfs_ops = &procfs_stats_ops, - .default_attrs = procfs_stats_attrs, + .release = kfd_procfs_kobj_release, +}; + +static const struct sysfs_ops sysfs_counters_ops = { + .show = kfd_sysfs_counters_show, +}; + +static struct kobj_type sysfs_counters_type = { + .sysfs_ops = &sysfs_counters_ops, + .release = kfd_procfs_kobj_release, }; int kfd_procfs_add_queue(struct queue *q) @@ -484,34 +512,31 @@ int kfd_procfs_add_queue(struct queue *q) return 0; } -static int kfd_sysfs_create_file(struct kfd_process *p, struct attribute *attr, +static void kfd_sysfs_create_file(struct kobject *kobj, struct attribute *attr, char *name) { - int ret = 0; + int ret; - if (!p || !attr || !name) - return -EINVAL; + if (!kobj || !attr || !name) + return; attr->name = name; attr->mode = KFD_SYSFS_FILE_MODE; sysfs_attr_init(attr); - ret = sysfs_create_file(p->kobj, attr); - - return ret; + ret = sysfs_create_file(kobj, attr); + if (ret) + pr_warn("Create sysfs %s/%s failed %d", kobj->name, name, ret); } -static int kfd_procfs_add_sysfs_stats(struct kfd_process *p) +static void kfd_procfs_add_sysfs_stats(struct kfd_process *p) { - int ret = 0; + int ret; int i; char stats_dir_filename[MAX_SYSFS_FILENAME_LEN]; - if (!p) - return -EINVAL; - - if (!p->kobj) - return -EFAULT; + if (!p || !p->kobj) + return; /* * Create sysfs files for each GPU: @@ -521,63 +546,87 @@ static int kfd_procfs_add_sysfs_stats(struct kfd_process *p) */ for (i = 0; i < p->n_pdds; i++) { struct kfd_process_device *pdd = p->pdds[i]; - struct kobject *kobj_stats; snprintf(stats_dir_filename, MAX_SYSFS_FILENAME_LEN, "stats_%u", pdd->dev->id); - kobj_stats = kfd_alloc_struct(kobj_stats); - if (!kobj_stats) - return -ENOMEM; + pdd->kobj_stats = kfd_alloc_struct(pdd->kobj_stats); + if (!pdd->kobj_stats) + return; - ret = kobject_init_and_add(kobj_stats, - &procfs_stats_type, - p->kobj, - stats_dir_filename); + ret = kobject_init_and_add(pdd->kobj_stats, + &procfs_stats_type, + p->kobj, + stats_dir_filename); if (ret) { pr_warn("Creating KFD proc/stats_%s folder failed", - stats_dir_filename); - kobject_put(kobj_stats); - goto err; + stats_dir_filename); + kobject_put(pdd->kobj_stats); + pdd->kobj_stats = NULL; + return; } - pdd->kobj_stats = kobj_stats; - pdd->attr_evict.name = "evicted_ms"; - pdd->attr_evict.mode = KFD_SYSFS_FILE_MODE; - sysfs_attr_init(&pdd->attr_evict); - ret = sysfs_create_file(kobj_stats, &pdd->attr_evict); - if (ret) - pr_warn("Creating eviction stats for gpuid %d failed", - (int)pdd->dev->id); - + kfd_sysfs_create_file(pdd->kobj_stats, &pdd->attr_evict, + "evicted_ms"); /* Add sysfs file to report compute unit occupancy */ - if (pdd->dev->kfd2kgd->get_cu_occupancy != NULL) { - pdd->attr_cu_occupancy.name = "cu_occupancy"; - pdd->attr_cu_occupancy.mode = KFD_SYSFS_FILE_MODE; - sysfs_attr_init(&pdd->attr_cu_occupancy); - ret = sysfs_create_file(kobj_stats, - &pdd->attr_cu_occupancy); - if (ret) - pr_warn("Creating %s failed for gpuid: %d", - pdd->attr_cu_occupancy.name, - (int)pdd->dev->id); - } + if (pdd->dev->kfd2kgd->get_cu_occupancy) + kfd_sysfs_create_file(pdd->kobj_stats, + &pdd->attr_cu_occupancy, + "cu_occupancy"); } -err: - return ret; } - -static int kfd_procfs_add_sysfs_files(struct kfd_process *p) +static void kfd_procfs_add_sysfs_counters(struct kfd_process *p) { int ret = 0; int i; + char counters_dir_filename[MAX_SYSFS_FILENAME_LEN]; - if (!p) - return -EINVAL; + if (!p || !p->kobj) + return; - if (!p->kobj) - return -EFAULT; + /* + * Create sysfs files for each GPU which supports SVM + * - proc//counters_/ + * - proc//counters_/faults + * - proc//counters_/page_in + * - proc//counters_/page_out + */ + for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) { + struct kfd_process_device *pdd = p->pdds[i]; + struct kobject *kobj_counters; + + snprintf(counters_dir_filename, MAX_SYSFS_FILENAME_LEN, + "counters_%u", pdd->dev->id); + kobj_counters = kfd_alloc_struct(kobj_counters); + if (!kobj_counters) + return; + + ret = kobject_init_and_add(kobj_counters, &sysfs_counters_type, + p->kobj, counters_dir_filename); + if (ret) { + pr_warn("Creating KFD proc/%s folder failed", + counters_dir_filename); + kobject_put(kobj_counters); + return; + } + + pdd->kobj_counters = kobj_counters; + kfd_sysfs_create_file(kobj_counters, &pdd->attr_faults, + "faults"); + kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_in, + "page_in"); + kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_out, + "page_out"); + } +} + +static void kfd_procfs_add_sysfs_files(struct kfd_process *p) +{ + int i; + + if (!p || !p->kobj) + return; /* * Create sysfs files for each GPU: @@ -589,20 +638,14 @@ static int kfd_procfs_add_sysfs_files(struct kfd_process *p) snprintf(pdd->vram_filename, MAX_SYSFS_FILENAME_LEN, "vram_%u", pdd->dev->id); - ret = kfd_sysfs_create_file(p, &pdd->attr_vram, pdd->vram_filename); - if (ret) - pr_warn("Creating vram usage for gpu id %d failed", - (int)pdd->dev->id); + kfd_sysfs_create_file(p->kobj, &pdd->attr_vram, + pdd->vram_filename); snprintf(pdd->sdma_filename, MAX_SYSFS_FILENAME_LEN, "sdma_%u", pdd->dev->id); - ret = kfd_sysfs_create_file(p, &pdd->attr_sdma, pdd->sdma_filename); - if (ret) - pr_warn("Creating sdma usage for gpu id %d failed", - (int)pdd->dev->id); + kfd_sysfs_create_file(p->kobj, &pdd->attr_sdma, + pdd->sdma_filename); } - - return ret; } void kfd_procfs_del_queue(struct queue *q) @@ -800,28 +843,17 @@ struct kfd_process *kfd_create_process(struct file *filep) goto out; } - process->attr_pasid.name = "pasid"; - process->attr_pasid.mode = KFD_SYSFS_FILE_MODE; - sysfs_attr_init(&process->attr_pasid); - ret = sysfs_create_file(process->kobj, &process->attr_pasid); - if (ret) - pr_warn("Creating pasid for pid %d failed", - (int)process->lead_thread->pid); + kfd_sysfs_create_file(process->kobj, &process->attr_pasid, + "pasid"); process->kobj_queues = kobject_create_and_add("queues", process->kobj); if (!process->kobj_queues) pr_warn("Creating KFD proc/queues folder failed"); - ret = kfd_procfs_add_sysfs_stats(process); - if (ret) - pr_warn("Creating sysfs stats dir for pid %d failed", - (int)process->lead_thread->pid); - - ret = kfd_procfs_add_sysfs_files(process); - if (ret) - pr_warn("Creating sysfs usage file for pid %d failed", - (int)process->lead_thread->pid); + kfd_procfs_add_sysfs_stats(process); + kfd_procfs_add_sysfs_files(process); + kfd_procfs_add_sysfs_counters(process); } out: if (!IS_ERR(process)) @@ -964,6 +996,50 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) p->n_pdds = 0; } +static void kfd_process_remove_sysfs(struct kfd_process *p) +{ + struct kfd_process_device *pdd; + int i; + + if (!p->kobj) + return; + + sysfs_remove_file(p->kobj, &p->attr_pasid); + kobject_del(p->kobj_queues); + kobject_put(p->kobj_queues); + p->kobj_queues = NULL; + + for (i = 0; i < p->n_pdds; i++) { + pdd = p->pdds[i]; + + sysfs_remove_file(p->kobj, &pdd->attr_vram); + sysfs_remove_file(p->kobj, &pdd->attr_sdma); + + sysfs_remove_file(pdd->kobj_stats, &pdd->attr_evict); + if (pdd->dev->kfd2kgd->get_cu_occupancy) + sysfs_remove_file(pdd->kobj_stats, + &pdd->attr_cu_occupancy); + kobject_del(pdd->kobj_stats); + kobject_put(pdd->kobj_stats); + pdd->kobj_stats = NULL; + } + + for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) { + pdd = p->pdds[i]; + + sysfs_remove_file(pdd->kobj_counters, &pdd->attr_faults); + sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_in); + sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_out); + kobject_del(pdd->kobj_counters); + kobject_put(pdd->kobj_counters); + pdd->kobj_counters = NULL; + } + + kobject_del(p->kobj); + kobject_put(p->kobj); + p->kobj = NULL; +} + /* No process locking is needed in this function, because the process * is not findable any more. We must assume that no other thread is * using it any more, otherwise we couldn't safely free the process @@ -973,33 +1049,7 @@ static void kfd_process_wq_release(struct work_struct *work) { struct kfd_process *p = container_of(work, struct kfd_process, release_work); - int i; - - /* Remove the procfs files */ - if (p->kobj) { - sysfs_remove_file(p->kobj, &p->attr_pasid); - kobject_del(p->kobj_queues); - kobject_put(p->kobj_queues); - p->kobj_queues = NULL; - - for (i = 0; i < p->n_pdds; i++) { - struct kfd_process_device *pdd = p->pdds[i]; - - sysfs_remove_file(p->kobj, &pdd->attr_vram); - sysfs_remove_file(p->kobj, &pdd->attr_sdma); - sysfs_remove_file(p->kobj, &pdd->attr_evict); - if (pdd->dev->kfd2kgd->get_cu_occupancy != NULL) - sysfs_remove_file(p->kobj, &pdd->attr_cu_occupancy); - kobject_del(pdd->kobj_stats); - kobject_put(pdd->kobj_stats); - pdd->kobj_stats = NULL; - } - - kobject_del(p->kobj); - kobject_put(p->kobj); - p->kobj = NULL; - } - + kfd_process_remove_sysfs(p); kfd_iommu_unbind_process(p); kfd_process_free_outstanding_kfd_bos(p); 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 95a6c36cea4c..243dd1efcdbf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -153,6 +153,7 @@ void pqm_uninit(struct process_queue_manager *pqm) if (pqn->q && pqn->q->gws) amdgpu_amdkfd_remove_gws_from_process(pqm->process->kgd_process_info, pqn->q->gws); + kfd_procfs_del_queue(pqn->q); uninit_queue(pqn->q); list_del(&pqn->process_queue_list); kfree(pqn); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index dff1011dd7ee..9a71d8919bd6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -119,28 +119,40 @@ static void svm_range_remove_notifier(struct svm_range *prange) } static int -svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr, - unsigned long *hmm_pfns, uint64_t npages) +svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, + unsigned long *hmm_pfns, uint32_t gpuidx) { enum dma_data_direction dir = DMA_BIDIRECTIONAL; - dma_addr_t *addr = *dma_addr; + dma_addr_t *addr = prange->dma_addr[gpuidx]; + struct device *dev = adev->dev; struct page *page; int i, r; if (!addr) { - addr = kvmalloc_array(npages, sizeof(*addr), + addr = kvmalloc_array(prange->npages, sizeof(*addr), GFP_KERNEL | __GFP_ZERO); if (!addr) return -ENOMEM; - *dma_addr = addr; + prange->dma_addr[gpuidx] = addr; } - for (i = 0; i < npages; i++) { + for (i = 0; i < prange->npages; i++) { if (WARN_ONCE(addr[i] && !dma_mapping_error(dev, addr[i]), "leaking dma mapping\n")) dma_unmap_page(dev, addr[i], PAGE_SIZE, dir); page = hmm_pfn_to_page(hmm_pfns[i]); + if (is_zone_device_page(page)) { + struct amdgpu_device *bo_adev = + amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev); + + addr[i] = (hmm_pfns[i] << PAGE_SHIFT) + + bo_adev->vm_manager.vram_base_offset - + bo_adev->kfd.dev->pgmap.range.start; + addr[i] |= SVM_RANGE_VRAM_DOMAIN; + pr_debug("vram address detected: 0x%llx\n", addr[i]); + continue; + } addr[i] = dma_map_page(dev, page, 0, PAGE_SIZE, dir); r = dma_mapping_error(dev, addr[i]); if (r) { @@ -175,8 +187,7 @@ svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap, } adev = (struct amdgpu_device *)pdd->dev->kgd; - r = svm_range_dma_map_dev(adev->dev, &prange->dma_addr[gpuidx], - hmm_pfns, prange->npages); + r = svm_range_dma_map_dev(adev, prange, hmm_pfns, gpuidx); if (r) break; } @@ -301,14 +312,6 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo) return true; } -static struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) -{ - if (svm_bo) - kref_get(&svm_bo->kref); - - return svm_bo; -} - static void svm_range_bo_release(struct kref *kref) { struct svm_range_bo *svm_bo; @@ -347,7 +350,7 @@ static void svm_range_bo_release(struct kref *kref) kfree(svm_bo); } -static void svm_range_bo_unref(struct svm_range_bo *svm_bo) +void svm_range_bo_unref(struct svm_range_bo *svm_bo) { if (!svm_bo) return; @@ -564,6 +567,24 @@ svm_range_get_adev_by_id(struct svm_range *prange, uint32_t gpu_id) return (struct amdgpu_device *)pdd->dev->kgd; } +struct kfd_process_device * +svm_range_get_pdd_by_adev(struct svm_range *prange, struct amdgpu_device *adev) +{ + struct kfd_process *p; + int32_t gpu_idx, gpuid; + int r; + + p = container_of(prange->svms, struct kfd_process, svms); + + r = kfd_process_gpuid_from_kgd(p, adev, &gpuid, &gpu_idx); + if (r) { + pr_debug("failed to get device id by adev %p\n", adev); + return NULL; + } + + return kfd_process_device_from_gpuidx(p, gpu_idx); +} + static int svm_range_bo_validate(void *param, struct amdgpu_bo *bo) { struct ttm_operation_ctx ctx = { false, false }; @@ -1002,21 +1023,22 @@ svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, } static uint64_t -svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) +svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange, + int domain) { struct amdgpu_device *bo_adev; uint32_t flags = prange->flags; uint32_t mapping_flags = 0; uint64_t pte_flags; - bool snoop = !prange->ttm_res; + bool snoop = (domain != SVM_RANGE_VRAM_DOMAIN); bool coherent = flags & KFD_IOCTL_SVM_FLAG_COHERENT; - if (prange->svm_bo && prange->ttm_res) + if (domain == SVM_RANGE_VRAM_DOMAIN) bo_adev = amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev); switch (adev->asic_type) { case CHIP_ARCTURUS: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1032,7 +1054,7 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) } break; case CHIP_ALDEBARAN: - if (prange->svm_bo && prange->ttm_res) { + if (domain == SVM_RANGE_VRAM_DOMAIN) { if (bo_adev == adev) { mapping_flags |= coherent ? AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW; @@ -1062,14 +1084,14 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange) mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE; pte_flags = AMDGPU_PTE_VALID; - pte_flags |= prange->ttm_res ? 0 : AMDGPU_PTE_SYSTEM; + pte_flags |= (domain == SVM_RANGE_VRAM_DOMAIN) ? 0 : AMDGPU_PTE_SYSTEM; pte_flags |= snoop ? AMDGPU_PTE_SNOOPED : 0; pte_flags |= amdgpu_gem_va_map_flags(adev, mapping_flags); pr_debug("svms 0x%p [0x%lx 0x%lx] vram %d PTE 0x%llx mapping 0x%x\n", prange->svms, prange->start, prange->last, - prange->ttm_res ? 1:0, pte_flags, mapping_flags); + (domain == SVM_RANGE_VRAM_DOMAIN) ? 1:0, pte_flags, mapping_flags); return pte_flags; } @@ -1140,31 +1162,41 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_bo_va bo_va; bool table_freed = false; uint64_t pte_flags; + unsigned long last_start; + int last_domain; int r = 0; + int64_t i; pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start, prange->last); - if (prange->svm_bo && prange->ttm_res) { + if (prange->svm_bo && prange->ttm_res) bo_va.is_xgmi = amdgpu_xgmi_same_hive(adev, bo_adev); - prange->mapping.bo_va = &bo_va; - } - prange->mapping.start = prange->start; - prange->mapping.last = prange->last; - prange->mapping.offset = prange->ttm_res ? prange->offset : 0; - pte_flags = svm_range_get_pte_flags(adev, prange); + last_start = prange->start; + for (i = 0; i < prange->npages; i++) { + last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN; + dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN; + if ((prange->start + i) < prange->last && + last_domain == (dma_addr[i + 1] & SVM_RANGE_VRAM_DOMAIN)) + continue; - r = amdgpu_vm_bo_update_mapping(adev, bo_adev, vm, false, false, NULL, - prange->mapping.start, - prange->mapping.last, pte_flags, - prange->mapping.offset, - prange->ttm_res, - dma_addr, &vm->last_update, - &table_freed); - if (r) { - pr_debug("failed %d to map to gpu 0x%lx\n", r, prange->start); - goto out; + pr_debug("Mapping range [0x%lx 0x%llx] on domain: %s\n", + last_start, prange->start + i, last_domain ? "GPU" : "CPU"); + pte_flags = svm_range_get_pte_flags(adev, prange, last_domain); + r = amdgpu_vm_bo_update_mapping(adev, bo_adev, vm, false, false, NULL, + last_start, + prange->start + i, pte_flags, + last_start - prange->start, + NULL, + dma_addr, + &vm->last_update, + &table_freed); + if (r) { + pr_debug("failed %d to map to gpu 0x%lx\n", r, prange->start); + goto out; + } + last_start = prange->start + i + 1; } r = amdgpu_vm_update_pdes(adev, vm, false); @@ -1185,7 +1217,6 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, p->pasid, TLB_FLUSH_LEGACY); } out: - prange->mapping.bo_va = NULL; return r; } @@ -1319,6 +1350,17 @@ static void svm_range_unreserve_bos(struct svm_validate_context *ctx) ttm_eu_backoff_reservation(&ctx->ticket, &ctx->validate_list); } +static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx) +{ + struct kfd_process_device *pdd; + struct amdgpu_device *adev; + + pdd = kfd_process_device_from_gpuidx(p, gpuidx); + adev = (struct amdgpu_device *)pdd->dev->kgd; + + return SVM_ADEV_PGMAP_OWNER(adev); +} + /* * Validation+GPU mapping with concurrent invalidation (MMU notifiers) * @@ -1349,6 +1391,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm, { struct svm_validate_context ctx; struct hmm_range *hmm_range; + struct kfd_process *p; + void *owner; + int32_t idx; int r = 0; ctx.process = container_of(prange->svms, struct kfd_process, svms); @@ -1394,33 +1439,38 @@ static int svm_range_validate_and_map(struct mm_struct *mm, svm_range_reserve_bos(&ctx); - if (!prange->actual_loc) { - r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL, - prange->start << PAGE_SHIFT, - prange->npages, &hmm_range, - false, true); - if (r) { - pr_debug("failed %d to get svm range pages\n", r); - goto unreserve_out; + p = container_of(prange->svms, struct kfd_process, svms); + owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap, + MAX_GPU_INSTANCE)); + for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) { + if (kfd_svm_page_owner(p, idx) != owner) { + owner = NULL; + break; } - - r = svm_range_dma_map(prange, ctx.bitmap, - hmm_range->hmm_pfns); - if (r) { - pr_debug("failed %d to dma map range\n", r); - goto unreserve_out; - } - - prange->validated_once = true; + } + r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL, + prange->start << PAGE_SHIFT, + prange->npages, &hmm_range, + false, true, owner); + if (r) { + pr_debug("failed %d to get svm range pages\n", r); + goto unreserve_out; } + r = svm_range_dma_map(prange, ctx.bitmap, + hmm_range->hmm_pfns); + if (r) { + pr_debug("failed %d to dma map range\n", r); + goto unreserve_out; + } + + prange->validated_once = true; + svm_range_lock(prange); - if (!prange->actual_loc) { - if (amdgpu_hmm_range_get_pages_done(hmm_range)) { - pr_debug("hmm update the range, need validate again\n"); - r = -EAGAIN; - goto unlock_out; - } + if (amdgpu_hmm_range_get_pages_done(hmm_range)) { + pr_debug("hmm update the range, need validate again\n"); + r = -EAGAIN; + goto unlock_out; } if (!list_empty(&prange->child_list)) { pr_debug("range split by unmap in parallel, validate again\n"); @@ -1572,6 +1622,7 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm, unsigned long start, unsigned long last) { struct svm_range_list *svms = prange->svms; + struct svm_range *pchild; struct kfd_process *p; int r = 0; @@ -1583,7 +1634,19 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm, if (!p->xnack_enabled) { int evicted_ranges; - atomic_inc(&prange->invalid); + list_for_each_entry(pchild, &prange->child_list, child_list) { + mutex_lock_nested(&pchild->lock, 1); + if (pchild->start <= last && pchild->last >= start) { + pr_debug("increment pchild invalid [0x%lx 0x%lx]\n", + pchild->start, pchild->last); + atomic_inc(&pchild->invalid); + } + mutex_unlock(&pchild->lock); + } + + if (prange->start <= last && prange->last >= start) + atomic_inc(&prange->invalid); + evicted_ranges = atomic_inc_return(&svms->evicted_ranges); if (evicted_ranges != 1) return r; @@ -1600,7 +1663,6 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm, schedule_delayed_work(&svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); } else { - struct svm_range *pchild; unsigned long s, l; pr_debug("invalidate unmap svms 0x%p [0x%lx 0x%lx] from GPUs\n", @@ -2311,6 +2373,27 @@ static bool svm_range_skip_recover(struct svm_range *prange) return false; } +static void +svm_range_count_fault(struct amdgpu_device *adev, struct kfd_process *p, + struct svm_range *prange, int32_t gpuidx) +{ + struct kfd_process_device *pdd; + + if (gpuidx == MAX_GPU_INSTANCE) + /* fault is on different page of same range + * or fault is skipped to recover later + */ + pdd = svm_range_get_pdd_by_adev(prange, adev); + else + /* fault recovered + * or fault cannot recover because GPU no access on the range + */ + pdd = kfd_process_device_from_gpuidx(p, gpuidx); + + if (pdd) + WRITE_ONCE(pdd->faults, pdd->faults + 1); +} + int svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint64_t addr) @@ -2320,7 +2403,8 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, struct svm_range *prange; struct kfd_process *p; uint64_t timestamp; - int32_t best_loc, gpuidx; + int32_t best_loc; + int32_t gpuidx = MAX_GPU_INSTANCE; bool write_locked = false; int r = 0; @@ -2440,6 +2524,9 @@ out_unlock_range: out_unlock_svms: mutex_unlock(&svms->lock); mmap_read_unlock(mm); + + svm_range_count_fault(adev, p, prange, gpuidx); + mmput(mm); out: kfd_unref_process(p); @@ -2662,7 +2749,8 @@ out: /* FIXME: This is a workaround for page locking bug when some pages are * invalid during migration to VRAM */ -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner) { struct hmm_range *hmm_range; int r; @@ -2673,7 +2761,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm) r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL, prange->start << PAGE_SHIFT, prange->npages, &hmm_range, - false, true); + false, true, owner); if (!r) { amdgpu_hmm_range_get_pages_done(hmm_range); prange->validated_once = true; @@ -2718,16 +2806,6 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, best_loc == prange->actual_loc) return 0; - /* - * Prefetch to GPU without host access flag, set actual_loc to gpu, then - * validate on gpu and map to gpus will be handled afterwards. - */ - if (best_loc && !prange->actual_loc && - !(prange->flags & KFD_IOCTL_SVM_FLAG_HOST_ACCESS)) { - prange->actual_loc = best_loc; - return 0; - } - if (!best_loc) { r = svm_migrate_vram_to_ram(prange, mm); *migrated = !r; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 0c0fc399395e..3fc1fd8b4fbc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -35,6 +35,10 @@ #include "amdgpu.h" #include "kfd_priv.h" +#define SVM_RANGE_VRAM_DOMAIN (1UL << 0) +#define SVM_ADEV_PGMAP_OWNER(adev)\ + ((adev)->hive ? (void *)(adev)->hive : (void *)(adev)) + struct svm_range_bo { struct amdgpu_bo *bo; struct kref kref; @@ -110,7 +114,6 @@ struct svm_range { struct list_head update_list; struct list_head remove_list; struct list_head insert_list; - struct amdgpu_bo_va_mapping mapping; uint64_t npages; dma_addr_t *dma_addr[MAX_GPU_INSTANCE]; struct ttm_resource *ttm_res; @@ -147,6 +150,14 @@ static inline void svm_range_unlock(struct svm_range *prange) mutex_unlock(&prange->lock); } +static inline struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo) +{ + if (svm_bo) + kref_get(&svm_bo->kref); + + return svm_bo; +} + int svm_range_list_init(struct kfd_process *p); void svm_range_list_fini(struct kfd_process *p); int svm_ioctl(struct kfd_process *p, enum kfd_ioctl_svm_op op, uint64_t start, @@ -173,13 +184,17 @@ void schedule_deferred_list_work(struct svm_range_list *svms); void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr, unsigned long offset, unsigned long npages); void svm_range_free_dma_mappings(struct svm_range *prange); -void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm); +void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm, + void *owner); +struct kfd_process_device * +svm_range_get_pdd_by_adev(struct svm_range *prange, struct amdgpu_device *adev); /* SVM API and HMM page migration work together, device memory type * is initialized to not 0 when page migration register device memory. */ #define KFD_IS_SVM_API_SUPPORTED(dev) ((dev)->pgmap.type != 0) +void svm_range_bo_unref(struct svm_range_bo *svm_bo); #else struct kfd_process; 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 b5b5ccf0ed71..01e1062dc235 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1160,6 +1160,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (amdgpu_dc_feature_mask & DC_DISABLE_FRACTIONAL_PWM_MASK) init_data.flags.disable_fractional_pwm = true; + if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING) + init_data.flags.edp_no_power_sequencing = true; + init_data.flags.power_down_display_on_boot = true; INIT_LIST_HEAD(&adev->dm.da_list); @@ -10118,7 +10121,7 @@ static int validate_overlay(struct drm_atomic_state *state) int i; struct drm_plane *plane; struct drm_plane_state *new_plane_state; - struct drm_plane_state *primary_state, *cursor_state, *overlay_state = NULL; + struct drm_plane_state *primary_state, *overlay_state = NULL; /* Check if primary plane is contained inside overlay */ for_each_new_plane_in_state_reverse(state, plane, new_plane_state, i) { @@ -10148,14 +10151,6 @@ static int validate_overlay(struct drm_atomic_state *state) if (!primary_state->crtc) return 0; - /* check if cursor plane is enabled */ - cursor_state = drm_atomic_get_plane_state(state, overlay_state->crtc->cursor); - if (IS_ERR(cursor_state)) - return PTR_ERR(cursor_state); - - if (drm_atomic_plane_disabling(plane->state, cursor_state)) - return 0; - /* Perform the bounds check to ensure the overlay plane covers the primary */ if (primary_state->crtc_x < overlay_state->crtc_x || primary_state->crtc_y < overlay_state->crtc_y || diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5101a4f8f69f..45640f1c26c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -297,6 +297,7 @@ struct dc_config { bool allow_seamless_boot_optimization; bool power_down_display_on_boot; bool edp_not_connected; + bool edp_no_power_sequencing; bool force_enum_edp; bool forced_clocks; bool allow_lttpr_non_transparent_mode; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 2938caaa2299..62d595ded866 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1022,8 +1022,20 @@ void dce110_edp_backlight_control( /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ panel_instance = link->panel_cntl->inst; - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) - edp_receiver_ready_T7(link); + + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { + if (!link->dc->config.edp_no_power_sequencing) + /* + * Sometimes, DP receiver chip power-controlled externally by an + * Embedded Controller could be treated and used as eDP, + * if it drives mobile display. In this case, + * we shouldn't be doing power-sequencing, hence we can skip + * waiting for T7-ready. + */ + edp_receiver_ready_T7(link); + else + DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); + } if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { @@ -1048,8 +1060,19 @@ void dce110_edp_backlight_control( dc_link_backlight_enable_aux(link, enable); /*edp 1.2*/ - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) - edp_add_delay_for_T9(link); + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { + if (!link->dc->config.edp_no_power_sequencing) + /* + * Sometimes, DP receiver chip power-controlled externally by an + * Embedded Controller could be treated and used as eDP, + * if it drives mobile display. In this case, + * we shouldn't be doing power-sequencing, hence we can skip + * waiting for T9-ready. + */ + edp_add_delay_for_T9(link); + else + DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); + } if (!enable && link->dpcd_sink_ext_caps.bits.oled) msleep(OLED_PRE_T11_DELAY); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile index 5dcdc5a858fe..4bab97acb155 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -28,6 +28,7 @@ endif CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mhard-float endif +ifdef CONFIG_X86 ifdef IS_OLD_GCC # Stack alignment mismatch, proceed with caution. # GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3 @@ -36,6 +37,7 @@ CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mpreferred-stack-boundary=4 else CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -msse2 endif +endif AMD_DAL_DCN31 = $(addprefix $(AMDDALPATH)/dc/dcn31/,$(DCN31)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index d34024fd798a..45862167e6ce 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -50,6 +50,10 @@ dml_ccflags += -msse2 endif endif +ifneq ($(CONFIG_FRAME_WARN),0) +frame_warn_flag := -Wframe-larger-than=2048 +endif + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) ifdef CONFIG_DRM_AMD_DC_DCN @@ -60,9 +64,9 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) -Wframe-larger-than=2048 +CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) -Wframe-larger-than=2048 +CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index 5f245bde54ff..a2a4fbeb83f8 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -119,7 +119,7 @@ bool dal_irq_service_set( dal_irq_service_ack(irq_service, source); - if (info->funcs->set) + if (info->funcs && info->funcs->set) return info->funcs->set(irq_service, info, enable); dal_irq_service_set_generic(irq_service, info, enable); @@ -153,7 +153,7 @@ bool dal_irq_service_ack( return false; } - if (info->funcs->ack) + if (info->funcs && info->funcs->ack) return info->funcs->ack(irq_service, info); dal_irq_service_ack_generic(irq_service, info); diff --git a/drivers/gpu/drm/amd/display/dc/irq_types.h b/drivers/gpu/drm/amd/display/dc/irq_types.h index 5f9346622301..1139b9eb9f6f 100644 --- a/drivers/gpu/drm/amd/display/dc/irq_types.h +++ b/drivers/gpu/drm/amd/display/dc/irq_types.h @@ -165,7 +165,7 @@ enum irq_type }; #define DAL_VALID_IRQ_SRC_NUM(src) \ - ((src) <= DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID) + ((src) < DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID) /* Number of Page Flip IRQ Sources. */ #define DAL_PFLIP_IRQ_SRC_NUM \ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 8c886ece71f6..973de346410d 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -352,3 +352,63 @@ uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub) { return REG_READ(DMCUB_TIMER_CURRENT); } + +void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) +{ + uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; + uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; + + if (!dmub || !diag_data) + return; + + memset(diag_data, 0, sizeof(*diag_data)); + + diag_data->dmcub_version = dmub->fw_version; + + diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + + diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + + diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + + diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); + diag_data->is_dmcub_enabled = is_dmub_enabled; + + REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); + diag_data->is_dmcub_soft_reset = is_soft_reset; + + REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); + diag_data->is_dmcub_secure_reset = is_sec_reset; + + REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); + diag_data->is_traceport_en = is_traceport_enabled; + + REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); + diag_data->is_cw0_enabled = is_cw0_enabled; + + REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); + diag_data->is_cw6_enabled = is_cw6_enabled; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h index 2829c3e9a310..9456a6a2d518 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h @@ -36,6 +36,9 @@ struct dmub_srv; DMUB_SR(DMCUB_CNTL) \ DMUB_SR(DMCUB_CNTL2) \ DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX0_SIZE) \ + DMUB_SR(DMCUB_INBOX0_RPTR) \ + DMUB_SR(DMCUB_INBOX0_WPTR) \ DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ DMUB_SR(DMCUB_INBOX1_SIZE) \ DMUB_SR(DMCUB_INBOX1_RPTR) \ @@ -103,11 +106,15 @@ struct dmub_srv; DMUB_SR(DMCUB_SCRATCH14) \ DMUB_SR(DMCUB_SCRATCH15) \ DMUB_SR(DMCUB_GPINT_DATAIN1) \ + DMUB_SR(DMCUB_GPINT_DATAOUT) \ DMUB_SR(CC_DC_PIPE_DIS) \ DMUB_SR(MMHUBBUB_SOFT_RESET) \ DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ DMUB_SR(DCN_VM_FB_OFFSET) \ - DMUB_SR(DMCUB_TIMER_CURRENT) + DMUB_SR(DMCUB_TIMER_CURRENT) \ + DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \ + DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \ + DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR) #define DMUB_DCN31_FIELDS() \ DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ @@ -115,6 +122,7 @@ struct dmub_srv; DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \ DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \ @@ -138,11 +146,13 @@ struct dmub_srv; DMUB_SF(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \ DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \ DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \ - DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) + DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \ + DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR) struct dmub_srv_dcn31_reg_offset { #define DMUB_SR(reg) uint32_t reg; DMUB_DCN31_REGS() + DMCUB_INTERNAL_REGS() #undef DMUB_SR }; @@ -227,4 +237,6 @@ void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub); +void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data); + #endif /* _DMUB_DCN31_H_ */ 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 fd7e996ab1d7..2bdbd7406f56 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -208,6 +208,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) break; case DMUB_ASIC_DCN31: + dmub->regs_dcn31 = &dmub_srv_dcn31_regs; funcs->reset = dmub_dcn31_reset; funcs->reset_release = dmub_dcn31_reset_release; funcs->backdoor_load = dmub_dcn31_backdoor_load; @@ -231,9 +232,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr; funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr; - if (asic == DMUB_ASIC_DCN31) { - dmub->regs_dcn31 = &dmub_srv_dcn31_regs; - } + funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data; funcs->get_current_time = dmub_dcn31_get_current_time; diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 332b0df53e52..ff1d3d4a6488 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -223,10 +223,12 @@ enum amd_harvest_ip_mask { }; enum DC_FEATURE_MASK { - DC_FBC_MASK = 0x1, - DC_MULTI_MON_PP_MCLK_SWITCH_MASK = 0x2, - DC_DISABLE_FRACTIONAL_PWM_MASK = 0x4, - DC_PSR_MASK = 0x8, + //Default value can be found at "uint amdgpu_dc_feature_mask" + DC_FBC_MASK = (1 << 0), //0x1, disabled by default + DC_MULTI_MON_PP_MCLK_SWITCH_MASK = (1 << 1), //0x2, enabled by default + DC_DISABLE_FRACTIONAL_PWM_MASK = (1 << 2), //0x4, disabled by default + DC_PSR_MASK = (1 << 3), //0x8, disabled by default + DC_EDP_NO_POWER_SEQUENCING = (1 << 4), //0x10, disabled by default }; enum DC_DEBUG_MASK { diff --git a/drivers/gpu/drm/amd/include/navi10_enum.h b/drivers/gpu/drm/amd/include/navi10_enum.h index d5ead9680c6e..84bcb96f76ea 100644 --- a/drivers/gpu/drm/amd/include/navi10_enum.h +++ b/drivers/gpu/drm/amd/include/navi10_enum.h @@ -430,7 +430,7 @@ ARRAY_2D_DEPTH = 0x00000001, */ typedef enum ENUM_NUM_SIMD_PER_CU { -NUM_SIMD_PER_CU = 0x00000004, +NUM_SIMD_PER_CU = 0x00000002, } ENUM_NUM_SIMD_PER_CU; /* diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index a276ebad47e6..769f58d5ae1a 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2902,14 +2902,15 @@ static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev, return sprintf(buf, "%i\n", 0); } -static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, - struct device_attribute *attr, - char *buf) + +static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev, + struct device_attribute *attr, + char *buf, + enum pp_power_limit_level pp_limit_level) { struct amdgpu_device *adev = dev_get_drvdata(dev); const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; enum pp_power_type power_type = to_sensor_dev_attr(attr)->index; - enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_MAX; uint32_t limit; ssize_t size; int r; @@ -2919,17 +2920,17 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; + if ( !(pp_funcs && pp_funcs->get_power_limit)) + return -ENODATA; + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); if (r < 0) { pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; } - if (pp_funcs && pp_funcs->get_power_limit) - r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, - pp_limit_level, power_type); - else - r = -ENODATA; + r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, + pp_limit_level, power_type); if (!r) size = sysfs_emit(buf, "%u\n", limit * 1000000); @@ -2942,85 +2943,31 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, return size; } + +static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_MAX); + +} + static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev, struct device_attribute *attr, char *buf) { - struct amdgpu_device *adev = dev_get_drvdata(dev); - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - enum pp_power_type power_type = to_sensor_dev_attr(attr)->index; - enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_CURRENT; - uint32_t limit; - ssize_t size; - int r; + return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_CURRENT); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (r < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return r; - } - - if (pp_funcs && pp_funcs->get_power_limit) - r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, - pp_limit_level, power_type); - else - r = -ENODATA; - - if (!r) - size = sysfs_emit(buf, "%u\n", limit * 1000000); - else - size = sysfs_emit(buf, "\n"); - - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - - return size; } static ssize_t amdgpu_hwmon_show_power_cap_default(struct device *dev, struct device_attribute *attr, char *buf) { - struct amdgpu_device *adev = dev_get_drvdata(dev); - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - enum pp_power_type power_type = to_sensor_dev_attr(attr)->index; - enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_DEFAULT; - uint32_t limit; - ssize_t size; - int r; + return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_DEFAULT); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (r < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return r; - } - - if (pp_funcs && pp_funcs->get_power_limit) - r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, - pp_limit_level, power_type); - else - r = -ENODATA; - - if (!r) - size = sysfs_emit(buf, "%u\n", limit * 1000000); - else - size = sysfs_emit(buf, "\n"); - - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - - return size; } + static ssize_t amdgpu_hwmon_show_power_label(struct device *dev, struct device_attribute *attr, 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 cb375f1beebd..ebe672142808 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1453,10 +1453,14 @@ static int smu_hw_fini(void *handle) if (smu->is_apu) { smu_powergate_sdma(&adev->smu, true); - smu_dpm_set_vcn_enable(smu, false); - smu_dpm_set_jpeg_enable(smu, false); } + smu_dpm_set_vcn_enable(smu, false); + smu_dpm_set_jpeg_enable(smu, false); + + adev->vcn.cur_state = AMD_PG_STATE_GATE; + adev->jpeg.cur_state = AMD_PG_STATE_GATE; + if (!smu->pm_enabled) return 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 7664334d8144..18a1ffdca227 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -189,10 +189,11 @@ err0_out: static int yellow_carp_system_features_control(struct smu_context *smu, bool en) { struct smu_feature *feature = &smu->smu_feature; + struct amdgpu_device *adev = smu->adev; uint32_t feature_mask[2]; int ret = 0; - if (!en) + if (!en && !adev->in_s0ix) ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); bitmap_zero(feature->enabled, feature->feature_num); diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index ebe9dccf2d83..0b8648396fb2 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -352,6 +352,7 @@ static struct drm_framebuffer *psb_user_framebuffer_create const struct drm_mode_fb_cmd2 *cmd) { struct drm_gem_object *obj; + struct drm_framebuffer *fb; /* * Find the GEM object and thus the gtt range object that is @@ -362,7 +363,11 @@ static struct drm_framebuffer *psb_user_framebuffer_create return ERR_PTR(-ENOENT); /* Let the core code do all the work */ - return psb_framebuffer_create(dev, cmd, obj); + fb = psb_framebuffer_create(dev, cmd, obj); + if (IS_ERR(fb)) + drm_gem_object_put(obj); + + return fb; } static int psbfb_probe(struct drm_fb_helper *fb_helper, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 390869bd6b63..be716b56e8e0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1791,10 +1791,23 @@ static struct intel_shared_dpll *dg1_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(i915, encoder->port); + enum intel_dpll_id id; + u32 val; - return _cnl_ddi_get_pll(i915, DG1_DPCLKA_CFGCR0(phy), - DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), - DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)); + val = intel_de_read(i915, DG1_DPCLKA_CFGCR0(phy)); + val &= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + val >>= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); + id = val; + + /* + * _DG1_DPCLKA0_CFGCR0 maps between DPLL 0 and 1 with one bit for phy A + * and B while _DG1_DPCLKA1_CFGCR0 maps between DPLL 2 and 3 with one + * bit for phy C and D. + */ + if (phy >= PHY_C) + id += DPLL_ID_DG1_DPLL2; + + return intel_get_shared_dpll_by_id(i915, id); } static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 5c9222283044..6cc03b9e4321 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2868,7 +2868,7 @@ static int intel_dp_vsc_sdp_unpack(struct drm_dp_vsc_sdp *vsc, if (size < sizeof(struct dp_sdp)) return -EINVAL; - memset(vsc, 0, size); + memset(vsc, 0, sizeof(*vsc)); if (sdp->sdp_header.HB0 != 0) return -EINVAL; diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 9ceddfbb1687..7f03df236613 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1279,7 +1279,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) return true; /* Waiting to drain ELSP? */ - synchronize_hardirq(to_pci_dev(engine->i915->drm.dev)->irq); + intel_synchronize_hardirq(engine->i915); intel_engine_flush_submission(engine); /* ELSP is empty, but there are ready requests? E.g. after reset */ diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c index 0c423f096e2b..37d74d4ed59b 100644 --- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c @@ -184,8 +184,11 @@ static int xcs_resume(struct intel_engine_cs *engine) ENGINE_TRACE(engine, "ring:{HEAD:%04x, TAIL:%04x}\n", ring->head, ring->tail); - /* Double check the ring is empty & disabled before we resume */ - synchronize_hardirq(engine->i915->drm.irq); + /* + * Double check the ring is empty & disabled before we resume. Called + * from atomic context during PCI probe, so _hardirq(). + */ + intel_synchronize_hardirq(engine->i915); if (!stop_ring(engine)) goto err; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 850b499c71c8..73de45472f60 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a11bdb667241..c03943198089 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -33,7 +33,6 @@ #include #include -#include #include "display/intel_de.h" #include "display/intel_display_types.h" @@ -4564,10 +4563,6 @@ void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv) bool intel_irqs_enabled(struct drm_i915_private *dev_priv) { - /* - * We only use drm_irq_uninstall() at unload and VT switch, so - * this is the only thing we need to check. - */ return dev_priv->runtime_pm.irqs_enabled; } @@ -4575,3 +4570,8 @@ void intel_synchronize_irq(struct drm_i915_private *i915) { synchronize_irq(to_pci_dev(i915->drm.dev)->irq); } + +void intel_synchronize_hardirq(struct drm_i915_private *i915) +{ + synchronize_hardirq(to_pci_dev(i915->drm.dev)->irq); +} diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index db34d5dbe402..e43b6734f21b 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -94,6 +94,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv); void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv); bool intel_irqs_enabled(struct drm_i915_private *dev_priv); void intel_synchronize_irq(struct drm_i915_private *i915); +void intel_synchronize_hardirq(struct drm_i915_private *i915); int intel_get_crtc_scanline(struct intel_crtc *crtc); void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e915ec034c98..94fde5ca26ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -10513,7 +10513,6 @@ enum skl_power_gate { #define _DG1_DPCLKA1_CFGCR0 0x16C280 #define _DG1_DPCLKA_PHY_IDX(phy) ((phy) % 2) #define _DG1_DPCLKA_PLL_IDX(pll) ((pll) % 2) -#define _DG1_PHY_DPLL_MAP(phy) ((phy) >= PHY_C ? DPLL_ID_DG1_DPLL2 : DPLL_ID_DG1_DPLL0) #define DG1_DPCLKA_CFGCR0(phy) _MMIO_PHY((phy) / 2, \ _DG1_DPCLKA_CFGCR0, \ _DG1_DPCLKA1_CFGCR0) @@ -10521,8 +10520,6 @@ enum skl_power_gate { #define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy) (_DG1_DPCLKA_PHY_IDX(phy) * 2) #define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll, phy) (_DG1_DPCLKA_PLL_IDX(pll) << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) #define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy) (0x3 << DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) -#define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy) \ - (((clk_sel) >> DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) + _DG1_PHY_DPLL_MAP(phy)) /* ADLS Clocks */ #define _ADLS_DPCLKA_CFGCR0 0x164280 diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 406681317419..573154268d43 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1325,6 +1325,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, /* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */ if (obj->import_attach) { DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n"); + drm_gem_object_put(obj); return ERR_PTR(-EINVAL); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 8cd135fa6dcd..5c23b77cb81a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -374,13 +374,13 @@ radeon_pci_shutdown(struct pci_dev *pdev) if (radeon_device_is_virtual()) radeon_pci_remove(pdev); -#ifdef CONFIG_PPC64 +#if defined(CONFIG_PPC64) || defined(CONFIG_MACH_LOONGSON64) /* * Some adapters need to be suspended before a * shutdown occurs in order to prevent an error - * during kexec. - * Make this power specific becauase it breaks - * some non-power boards. + * during kexec, shutdown or reboot. + * Make this power and Loongson specific because + * it breaks some other boards. */ radeon_suspend_kms(pci_get_drvdata(pdev), true, true, false); #endif diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index bfaaa3c969a3..56ede9d63b12 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -49,23 +49,23 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo); * function are calling it. */ -static void radeon_update_memory_usage(struct radeon_bo *bo, - unsigned mem_type, int sign) +static void radeon_update_memory_usage(struct ttm_buffer_object *bo, + unsigned int mem_type, int sign) { - struct radeon_device *rdev = bo->rdev; + struct radeon_device *rdev = radeon_get_rdev(bo->bdev); switch (mem_type) { case TTM_PL_TT: if (sign > 0) - atomic64_add(bo->tbo.base.size, &rdev->gtt_usage); + atomic64_add(bo->base.size, &rdev->gtt_usage); else - atomic64_sub(bo->tbo.base.size, &rdev->gtt_usage); + atomic64_sub(bo->base.size, &rdev->gtt_usage); break; case TTM_PL_VRAM: if (sign > 0) - atomic64_add(bo->tbo.base.size, &rdev->vram_usage); + atomic64_add(bo->base.size, &rdev->vram_usage); else - atomic64_sub(bo->tbo.base.size, &rdev->vram_usage); + atomic64_sub(bo->base.size, &rdev->vram_usage); break; } } @@ -76,8 +76,6 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo) bo = container_of(tbo, struct radeon_bo, tbo); - radeon_update_memory_usage(bo, bo->tbo.resource->mem_type, -1); - mutex_lock(&bo->rdev->gem.mutex); list_del_init(&bo->list); mutex_unlock(&bo->rdev->gem.mutex); @@ -727,24 +725,21 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, } void radeon_bo_move_notify(struct ttm_buffer_object *bo, - bool evict, + unsigned int old_type, struct ttm_resource *new_mem) { struct radeon_bo *rbo; + radeon_update_memory_usage(bo, old_type, -1); + if (new_mem) + radeon_update_memory_usage(bo, new_mem->mem_type, 1); + if (!radeon_ttm_bo_is_radeon_bo(bo)) return; rbo = container_of(bo, struct radeon_bo, tbo); radeon_bo_check_tiling(rbo, 0, 1); radeon_vm_bo_invalidate(rbo->rdev, rbo); - - /* update statistics */ - if (!new_mem) - return; - - radeon_update_memory_usage(rbo, bo->resource->mem_type, -1); - radeon_update_memory_usage(rbo, new_mem->mem_type, 1); } vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 1739c6a142cd..1afc7992ef91 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -161,7 +161,7 @@ extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo, extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, bool force_drop); extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, - bool evict, + unsigned int old_type, struct ttm_resource *new_mem); extern vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index ad2a5a791bba..a06d4cc2fb1c 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -199,7 +199,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, struct ttm_resource *old_mem = bo->resource; struct radeon_device *rdev; struct radeon_bo *rbo; - int r; + int r, old_type; if (new_mem->mem_type == TTM_PL_TT) { r = radeon_ttm_tt_bind(bo->bdev, bo->ttm, new_mem); @@ -216,6 +216,9 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, if (WARN_ON_ONCE(rbo->tbo.pin_count > 0)) return -EINVAL; + /* Save old type for statistics update */ + old_type = old_mem->mem_type; + rdev = radeon_get_rdev(bo->bdev); if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { ttm_bo_move_null(bo, new_mem); @@ -261,7 +264,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, out: /* update statistics */ atomic64_add(bo->base.size, &rdev->num_bytes_moved); - radeon_bo_move_notify(bo, evict, new_mem); + radeon_bo_move_notify(bo, old_type, new_mem); return 0; } @@ -682,7 +685,11 @@ bool radeon_ttm_tt_is_readonly(struct radeon_device *rdev, static void radeon_bo_delete_mem_notify(struct ttm_buffer_object *bo) { - radeon_bo_move_notify(bo, false, NULL); + unsigned int old_type = TTM_PL_SYSTEM; + + if (bo->resource) + old_type = bo->resource->mem_type; + radeon_bo_move_notify(bo, old_type, NULL); } static struct ttm_device_funcs radeon_bo_driver = { diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index 53e13476e831..3874d15b0e9b 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -44,6 +44,15 @@ config HWSPINLOCK_STM32 If unsure, say N. +config HWSPINLOCK_SUN6I + tristate "SUN6I Hardware Spinlock device" + depends on ARCH_SUNXI || COMPILE_TEST + help + Say y here to support the SUN6I Hardware Spinlock device which can be + found in most of the sun6i compatible Allwinner SoCs. + + If unsure, say N. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on ARCH_U8500 || COMPILE_TEST diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 1f8dd6f5814f..a0f16c9aaa82 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_SUN6I) += sun6i_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/sun6i_hwspinlock.c b/drivers/hwspinlock/sun6i_hwspinlock.c new file mode 100644 index 000000000000..c2d314588046 --- /dev/null +++ b/drivers/hwspinlock/sun6i_hwspinlock.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * sun6i_hwspinlock.c - hardware spinlock driver for sun6i compatible Allwinner SoCs + * Copyright (C) 2020 Wilken Gottwalt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +#define DRIVER_NAME "sun6i_hwspinlock" + +#define SPINLOCK_BASE_ID 0 /* there is only one hwspinlock device per SoC */ +#define SPINLOCK_SYSSTATUS_REG 0x0000 +#define SPINLOCK_LOCK_REGN 0x0100 +#define SPINLOCK_NOTTAKEN 0 + +struct sun6i_hwspinlock_data { + struct hwspinlock_device *bank; + struct reset_control *reset; + struct clk *ahb_clk; + struct dentry *debugfs; + int nlocks; +}; + +#ifdef CONFIG_DEBUG_FS + +static int hwlocks_supported_show(struct seq_file *seqf, void *unused) +{ + struct sun6i_hwspinlock_data *priv = seqf->private; + + seq_printf(seqf, "%d\n", priv->nlocks); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(hwlocks_supported); + +static void sun6i_hwspinlock_debugfs_init(struct sun6i_hwspinlock_data *priv) +{ + priv->debugfs = debugfs_create_dir(DRIVER_NAME, NULL); + debugfs_create_file("supported", 0444, priv->debugfs, priv, &hwlocks_supported_fops); +} + +#else + +static void sun6i_hwspinlock_debugfs_init(struct sun6i_hwspinlock_data *priv) +{ +} + +#endif + +static int sun6i_hwspinlock_trylock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + return (readl(lock_addr) == SPINLOCK_NOTTAKEN); +} + +static void sun6i_hwspinlock_unlock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + writel(SPINLOCK_NOTTAKEN, lock_addr); +} + +static const struct hwspinlock_ops sun6i_hwspinlock_ops = { + .trylock = sun6i_hwspinlock_trylock, + .unlock = sun6i_hwspinlock_unlock, +}; + +static void sun6i_hwspinlock_disable(void *data) +{ + struct sun6i_hwspinlock_data *priv = data; + + debugfs_remove_recursive(priv->debugfs); + clk_disable_unprepare(priv->ahb_clk); + reset_control_assert(priv->reset); +} + +static int sun6i_hwspinlock_probe(struct platform_device *pdev) +{ + struct sun6i_hwspinlock_data *priv; + struct hwspinlock *hwlock; + void __iomem *io_base; + u32 num_banks; + int err, i; + + io_base = devm_platform_ioremap_resource(pdev, SPINLOCK_BASE_ID); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ahb_clk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(priv->ahb_clk)) { + err = PTR_ERR(priv->ahb_clk); + dev_err(&pdev->dev, "unable to get AHB clock (%d)\n", err); + return err; + } + + priv->reset = devm_reset_control_get(&pdev->dev, "ahb"); + if (IS_ERR(priv->reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset), + "unable to get reset control\n"); + + err = reset_control_deassert(priv->reset); + if (err) { + dev_err(&pdev->dev, "deassert reset control failure (%d)\n", err); + return err; + } + + err = clk_prepare_enable(priv->ahb_clk); + if (err) { + dev_err(&pdev->dev, "unable to prepare AHB clk (%d)\n", err); + goto clk_fail; + } + + /* + * bit 28 and 29 represents the hwspinlock setup + * + * every datasheet (A64, A80, A83T, H3, H5, H6 ...) says the default value is 0x1 and 0x1 + * to 0x4 represent 32, 64, 128 and 256 locks + * but later datasheets (H5, H6) say 00, 01, 10, 11 represent 32, 64, 128 and 256 locks, + * but that would mean H5 and H6 have 64 locks, while their datasheets talk about 32 locks + * all the time, not a single mentioning of 64 locks + * the 0x4 value is also not representable by 2 bits alone, so some datasheets are not + * correct + * one thing have all in common, default value of the sysstatus register is 0x10000000, + * which results in bit 28 being set + * this is the reason 0x1 is considered being 32 locks and bit 30 is taken into account + * verified on H2+ (datasheet 0x1 = 32 locks) and H5 (datasheet 01 = 64 locks) + */ + num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28; + switch (num_banks) { + case 1 ... 4: + priv->nlocks = 1 << (4 + num_banks); + break; + default: + err = -EINVAL; + dev_err(&pdev->dev, "unsupported hwspinlock setup (%d)\n", num_banks); + goto bank_fail; + } + + priv->bank = devm_kzalloc(&pdev->dev, struct_size(priv->bank, lock, priv->nlocks), + GFP_KERNEL); + if (!priv->bank) { + err = -ENOMEM; + goto bank_fail; + } + + for (i = 0; i < priv->nlocks; ++i) { + hwlock = &priv->bank->lock[i]; + hwlock->priv = io_base + SPINLOCK_LOCK_REGN + sizeof(u32) * i; + } + + /* failure of debugfs is considered non-fatal */ + sun6i_hwspinlock_debugfs_init(priv); + if (IS_ERR(priv->debugfs)) + priv->debugfs = NULL; + + err = devm_add_action_or_reset(&pdev->dev, sun6i_hwspinlock_disable, priv); + if (err) { + dev_err(&pdev->dev, "failed to add hwspinlock disable action\n"); + goto bank_fail; + } + + platform_set_drvdata(pdev, priv); + + return devm_hwspin_lock_register(&pdev->dev, priv->bank, &sun6i_hwspinlock_ops, + SPINLOCK_BASE_ID, priv->nlocks); + +bank_fail: + clk_disable_unprepare(priv->ahb_clk); +clk_fail: + reset_control_assert(priv->reset); + + return err; +} + +static const struct of_device_id sun6i_hwspinlock_ids[] = { + { .compatible = "allwinner,sun6i-a31-hwspinlock", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun6i_hwspinlock_ids); + +static struct platform_driver sun6i_hwspinlock_driver = { + .probe = sun6i_hwspinlock_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = sun6i_hwspinlock_ids, + }, +}; +module_platform_driver(sun6i_hwspinlock_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SUN6I hardware spinlock driver"); +MODULE_AUTHOR("Wilken Gottwalt "); diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 3f2226928fe0..5b37ffe5ad5b 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -1379,6 +1379,8 @@ static void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master) case IBIR_TYPE_MR: WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR)); + break; + default: break; } diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 1f6ba4221817..879e5a64acaf 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -195,7 +195,7 @@ struct svc_i3c_master { }; /** - * struct svc_i3c_i3c_dev_data - Device specific data + * struct svc_i3c_i2c_dev_data - Device specific data * @index: Index in the master tables corresponding to this device * @ibi: IBI slot index in the master structure * @ibi_pool: IBI pool associated to this device @@ -1448,7 +1448,6 @@ static int svc_i3c_master_remove(struct platform_device *pdev) if (ret) return ret; - free_irq(master->irq, master); clk_disable_unprepare(master->pclk); clk_disable_unprepare(master->fclk); clk_disable_unprepare(master->sclk); diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index ec0e861f185f..5baebf62df33 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -4,7 +4,6 @@ # menu "Input device support" - depends on !UML config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 4761795cb49f..5a2c2fb3217d 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -4,6 +4,7 @@ # config GAMEPORT tristate "Gameport support" + depends on !UML help Gameport support is for the standard 15-pin PC gameport. If you have a joystick, gamepad, gameport card, a soundcard with a gameport diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 7dfe8ea90923..3b23078bc7b5 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -4,6 +4,7 @@ # menuconfig INPUT_JOYSTICK bool "Joysticks/Gamepads" + depends on !UML help If you have a joystick, 6dof controller, gamepad, steering wheel, weapon control system or something like that you can say Y here diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index fac91ea14f17..8e9672deb1eb 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -660,6 +660,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) fallthrough; case 45: /* Ambiguous packet length */ if (j <= 40) { /* ID length less or eq 40 -> FSP */ + fallthrough; case 43: sw->type = SW_ID_FSP; break; diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c index 136872e77195..9f465e146799 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c @@ -211,7 +211,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu) if (of_property_read_bool(np, "calxeda,smmu-secure-config-access")) smmu->impl = &calxeda_impl; - if (of_device_is_compatible(np, "nvidia,tegra194-smmu")) + if (of_device_is_compatible(np, "nvidia,tegra194-smmu") || + of_device_is_compatible(np, "nvidia,tegra186-smmu")) return nvidia_smmu_impl_init(smmu); smmu = qcom_smmu_impl_init(smmu); diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c index 29117444e5a0..01e9b50b10a1 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c @@ -7,6 +7,8 @@ #include #include +#include + #include "arm-smmu.h" /* @@ -15,18 +17,32 @@ * interleaved IOVA accesses across them and translates accesses from * non-isochronous HW devices. * Third one is used for translating accesses from isochronous HW devices. + * + * In addition, the SMMU driver needs to coordinate with the memory controller + * driver to ensure that the right SID override is programmed for any given + * memory client. This is necessary to allow for use-case such as seamlessly + * handing over the display controller configuration from the firmware to the + * kernel. + * * This implementation supports programming of the two instances that must - * be programmed identically. - * The third instance usage is through standard arm-smmu driver itself and - * is out of scope of this implementation. + * be programmed identically and takes care of invoking the memory controller + * driver for SID override programming after devices have been attached to an + * SMMU instance. */ -#define NUM_SMMU_INSTANCES 2 +#define MAX_SMMU_INSTANCES 2 struct nvidia_smmu { - struct arm_smmu_device smmu; - void __iomem *bases[NUM_SMMU_INSTANCES]; + struct arm_smmu_device smmu; + void __iomem *bases[MAX_SMMU_INSTANCES]; + unsigned int num_instances; + struct tegra_mc *mc; }; +static inline struct nvidia_smmu *to_nvidia_smmu(struct arm_smmu_device *smmu) +{ + return container_of(smmu, struct nvidia_smmu, smmu); +} + static inline void __iomem *nvidia_smmu_page(struct arm_smmu_device *smmu, unsigned int inst, int page) { @@ -47,9 +63,10 @@ static u32 nvidia_smmu_read_reg(struct arm_smmu_device *smmu, static void nvidia_smmu_write_reg(struct arm_smmu_device *smmu, int page, int offset, u32 val) { + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); unsigned int i; - for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + for (i = 0; i < nvidia->num_instances; i++) { void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset; writel_relaxed(val, reg); @@ -67,9 +84,10 @@ static u64 nvidia_smmu_read_reg64(struct arm_smmu_device *smmu, static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu, int page, int offset, u64 val) { + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); unsigned int i; - for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + for (i = 0; i < nvidia->num_instances; i++) { void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset; writeq_relaxed(val, reg); @@ -79,6 +97,7 @@ static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu, static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, int sync, int status) { + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); unsigned int delay; arm_smmu_writel(smmu, page, sync, 0); @@ -90,7 +109,7 @@ static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, u32 val = 0; unsigned int i; - for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + for (i = 0; i < nvidia->num_instances; i++) { void __iomem *reg; reg = nvidia_smmu_page(smmu, i, page) + status; @@ -112,9 +131,10 @@ static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, static int nvidia_smmu_reset(struct arm_smmu_device *smmu) { + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); unsigned int i; - for (i = 0; i < NUM_SMMU_INSTANCES; i++) { + for (i = 0; i < nvidia->num_instances; i++) { u32 val; void __iomem *reg = nvidia_smmu_page(smmu, i, ARM_SMMU_GR0) + ARM_SMMU_GR0_sGFSR; @@ -157,8 +177,9 @@ static irqreturn_t nvidia_smmu_global_fault(int irq, void *dev) unsigned int inst; irqreturn_t ret = IRQ_NONE; struct arm_smmu_device *smmu = dev; + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); - for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) { + for (inst = 0; inst < nvidia->num_instances; inst++) { irqreturn_t irq_ret; irq_ret = nvidia_smmu_global_fault_inst(irq, smmu, inst); @@ -202,11 +223,13 @@ static irqreturn_t nvidia_smmu_context_fault(int irq, void *dev) struct arm_smmu_device *smmu; struct iommu_domain *domain = dev; struct arm_smmu_domain *smmu_domain; + struct nvidia_smmu *nvidia; smmu_domain = container_of(domain, struct arm_smmu_domain, domain); smmu = smmu_domain->smmu; + nvidia = to_nvidia_smmu(smmu); - for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) { + for (inst = 0; inst < nvidia->num_instances; inst++) { irqreturn_t irq_ret; /* @@ -224,6 +247,17 @@ static irqreturn_t nvidia_smmu_context_fault(int irq, void *dev) return ret; } +static void nvidia_smmu_probe_finalize(struct arm_smmu_device *smmu, struct device *dev) +{ + struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu); + int err; + + err = tegra_mc_probe_device(nvidia->mc, dev); + if (err < 0) + dev_err(smmu->dev, "memory controller probe failed for %s: %d\n", + dev_name(dev), err); +} + static const struct arm_smmu_impl nvidia_smmu_impl = { .read_reg = nvidia_smmu_read_reg, .write_reg = nvidia_smmu_write_reg, @@ -233,6 +267,11 @@ static const struct arm_smmu_impl nvidia_smmu_impl = { .tlb_sync = nvidia_smmu_tlb_sync, .global_fault = nvidia_smmu_global_fault, .context_fault = nvidia_smmu_context_fault, + .probe_finalize = nvidia_smmu_probe_finalize, +}; + +static const struct arm_smmu_impl nvidia_smmu_single_impl = { + .probe_finalize = nvidia_smmu_probe_finalize, }; struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu) @@ -241,23 +280,36 @@ struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu) struct device *dev = smmu->dev; struct nvidia_smmu *nvidia_smmu; struct platform_device *pdev = to_platform_device(dev); + unsigned int i; nvidia_smmu = devm_krealloc(dev, smmu, sizeof(*nvidia_smmu), GFP_KERNEL); if (!nvidia_smmu) return ERR_PTR(-ENOMEM); + nvidia_smmu->mc = devm_tegra_memory_controller_get(dev); + if (IS_ERR(nvidia_smmu->mc)) + return ERR_CAST(nvidia_smmu->mc); + /* Instance 0 is ioremapped by arm-smmu.c. */ nvidia_smmu->bases[0] = smmu->base; + nvidia_smmu->num_instances++; - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) - return ERR_PTR(-ENODEV); + for (i = 1; i < MAX_SMMU_INSTANCES; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) + break; - nvidia_smmu->bases[1] = devm_ioremap_resource(dev, res); - if (IS_ERR(nvidia_smmu->bases[1])) - return ERR_CAST(nvidia_smmu->bases[1]); + nvidia_smmu->bases[i] = devm_ioremap_resource(dev, res); + if (IS_ERR(nvidia_smmu->bases[i])) + return ERR_CAST(nvidia_smmu->bases[i]); - nvidia_smmu->smmu.impl = &nvidia_smmu_impl; + nvidia_smmu->num_instances++; + } + + if (nvidia_smmu->num_instances == 1) + nvidia_smmu->smmu.impl = &nvidia_smmu_single_impl; + else + nvidia_smmu->smmu.impl = &nvidia_smmu_impl; return &nvidia_smmu->smmu; } diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 1e98dc63ad13..0a281833f611 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -376,9 +376,9 @@ static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup, if (client->swgroup != swgroup) continue; - value = smmu_readl(smmu, client->smmu.reg); - value |= BIT(client->smmu.bit); - smmu_writel(smmu, value, client->smmu.reg); + value = smmu_readl(smmu, client->regs.smmu.reg); + value |= BIT(client->regs.smmu.bit); + smmu_writel(smmu, value, client->regs.smmu.reg); } } @@ -404,9 +404,9 @@ static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup, if (client->swgroup != swgroup) continue; - value = smmu_readl(smmu, client->smmu.reg); - value &= ~BIT(client->smmu.bit); - smmu_writel(smmu, value, client->smmu.reg); + value = smmu_readl(smmu, client->regs.smmu.reg); + value &= ~BIT(client->regs.smmu.bit); + smmu_writel(smmu, value, client->regs.smmu.reg); } } @@ -1042,9 +1042,9 @@ static int tegra_smmu_clients_show(struct seq_file *s, void *data) const struct tegra_mc_client *client = &smmu->soc->clients[i]; const char *status; - value = smmu_readl(smmu, client->smmu.reg); + value = smmu_readl(smmu, client->regs.smmu.reg); - if (value & BIT(client->smmu.bit)) + if (value & BIT(client->regs.smmu.bit)) status = "yes"; else status = "no"; diff --git a/drivers/irqchip/irq-mips-cpu.c b/drivers/irqchip/irq-mips-cpu.c index 0bbb0b2d0dd5..0c7ae71a0af0 100644 --- a/drivers/irqchip/irq-mips-cpu.c +++ b/drivers/irqchip/irq-mips-cpu.c @@ -127,7 +127,6 @@ static struct irq_chip mips_mt_cpu_irq_controller = { asmlinkage void __weak plat_irq_dispatch(void) { unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM; - unsigned int virq; int irq; if (!pending) { @@ -137,12 +136,15 @@ asmlinkage void __weak plat_irq_dispatch(void) pending >>= CAUSEB_IP; while (pending) { + struct irq_domain *d; + irq = fls(pending) - 1; if (IS_ENABLED(CONFIG_GENERIC_IRQ_IPI) && irq < 2) - virq = irq_linear_revmap(ipi_domain, irq); + d = ipi_domain; else - virq = irq_linear_revmap(irq_domain, irq); - do_IRQ(virq); + d = irq_domain; + + do_domain_IRQ(d, irq); pending &= ~BIT(irq); } } diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index b146e069bf5b..54c7092cc61d 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -169,8 +169,8 @@ static void gic_handle_shared_int(bool chained) generic_handle_domain_irq(gic_irq_domain, GIC_SHARED_TO_HWIRQ(intr)); else - do_IRQ(irq_find_mapping(gic_irq_domain, - GIC_SHARED_TO_HWIRQ(intr))); + do_domain_IRQ(gic_irq_domain, + GIC_SHARED_TO_HWIRQ(intr)); } } @@ -320,8 +320,8 @@ static void gic_handle_local_int(bool chained) generic_handle_domain_irq(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(intr)); else - do_IRQ(irq_find_mapping(gic_irq_domain, - GIC_LOCAL_TO_HWIRQ(intr))); + do_domain_IRQ(gic_irq_domain, + GIC_LOCAL_TO_HWIRQ(intr)); } } diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c index 34c4b4ffacd1..1d9bb28d13e5 100644 --- a/drivers/irqchip/irq-pic32-evic.c +++ b/drivers/irqchip/irq-pic32-evic.c @@ -42,11 +42,10 @@ static void __iomem *evic_base; asmlinkage void __weak plat_irq_dispatch(void) { - unsigned int irq, hwirq; + unsigned int hwirq; hwirq = readl(evic_base + REG_INTSTAT) & 0xFF; - irq = irq_linear_revmap(evic_irq_domain, hwirq); - do_IRQ(irq); + do_domain_IRQ(evic_irq_domain, hwirq); } static struct evic_chip_data *irqd_to_priv(struct irq_data *data) diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index 14386d0b5f57..c267283b01fd 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -600,8 +600,10 @@ static int atmel_ebi_probe(struct platform_device *pdev) child); ret = atmel_ebi_dev_disable(ebi, child); - if (ret) + if (ret) { + of_node_put(child); return ret; + } } } diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index f7825eef5894..762d0c0f0716 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -41,7 +41,6 @@ * @node: node in the device list * @base: base address of memory-mapped IO registers. * @dev: device pointer. - * @addressing table with addressing information from the spec * @regs_cache: An array of 'struct emif_regs' that stores * calculated register values for different * frequencies, to avoid re-calculating them on @@ -61,7 +60,6 @@ struct emif_data { unsigned long irq_state; void __iomem *base; struct device *dev; - const struct lpddr2_addressing *addressing; struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES]; struct emif_regs *curr_regs; struct emif_platform_data *plat_data; @@ -72,7 +70,6 @@ struct emif_data { static struct emif_data *emif1; static DEFINE_SPINLOCK(emif_lock); static unsigned long irq_state; -static u32 t_ck; /* DDR clock period in ps */ static LIST_HEAD(device_list); #ifdef CONFIG_DEBUG_FS @@ -169,15 +166,6 @@ static inline void __exit emif_debugfs_exit(struct emif_data *emif) } #endif -/* - * Calculate the period of DDR clock from frequency value - */ -static void set_ddr_clk_period(u32 freq) -{ - /* Divide 10^12 by frequency to get period in ps */ - t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq); -} - /* * Get bus width used by EMIF. Note that this may be different from the * bus width of the DDR devices used. For instance two 16-bit DDR devices @@ -196,19 +184,6 @@ static u32 get_emif_bus_width(struct emif_data *emif) return width; } -/* - * Get the CL from SDRAM_CONFIG register - */ -static u32 get_cl(struct emif_data *emif) -{ - u32 cl; - void __iomem *base = emif->base; - - cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT; - - return cl; -} - static void set_lpmode(struct emif_data *emif, u8 lpmode) { u32 temp; @@ -328,203 +303,6 @@ static const struct lpddr2_addressing *get_addressing_table( return &lpddr2_jedec_addressing_table[index]; } -/* - * Find the the right timing table from the array of timing - * tables of the device using DDR clock frequency - */ -static const struct lpddr2_timings *get_timings_table(struct emif_data *emif, - u32 freq) -{ - u32 i, min, max, freq_nearest; - const struct lpddr2_timings *timings = NULL; - const struct lpddr2_timings *timings_arr = emif->plat_data->timings; - struct device *dev = emif->dev; - - /* Start with a very high frequency - 1GHz */ - freq_nearest = 1000000000; - - /* - * Find the timings table such that: - * 1. the frequency range covers the required frequency(safe) AND - * 2. the max_freq is closest to the required frequency(optimal) - */ - for (i = 0; i < emif->plat_data->timings_arr_size; i++) { - max = timings_arr[i].max_freq; - min = timings_arr[i].min_freq; - if ((freq >= min) && (freq <= max) && (max < freq_nearest)) { - freq_nearest = max; - timings = &timings_arr[i]; - } - } - - if (!timings) - dev_err(dev, "%s: couldn't find timings for - %dHz\n", - __func__, freq); - - dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n", - __func__, freq, freq_nearest); - - return timings; -} - -static u32 get_sdram_ref_ctrl_shdw(u32 freq, - const struct lpddr2_addressing *addressing) -{ - u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi; - - /* Scale down frequency and t_refi to avoid overflow */ - freq_khz = freq / 1000; - t_refi = addressing->tREFI_ns / 100; - - /* - * refresh rate to be set is 'tREFI(in us) * freq in MHz - * division by 10000 to account for change in units - */ - val = t_refi * freq_khz / 10000; - ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT; - - return ref_ctrl_shdw; -} - -static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings, - const struct lpddr2_min_tck *min_tck, - const struct lpddr2_addressing *addressing) -{ - u32 tim1 = 0, val = 0; - - val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1; - tim1 |= val << T_WTR_SHIFT; - - if (addressing->num_banks == B8) - val = DIV_ROUND_UP(timings->tFAW, t_ck*4); - else - val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck)); - tim1 |= (val - 1) << T_RRD_SHIFT; - - val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1; - tim1 |= val << T_RC_SHIFT; - - val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck)); - tim1 |= (val - 1) << T_RAS_SHIFT; - - val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1; - tim1 |= val << T_WR_SHIFT; - - val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1; - tim1 |= val << T_RCD_SHIFT; - - val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1; - tim1 |= val << T_RP_SHIFT; - - return tim1; -} - -static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings, - const struct lpddr2_min_tck *min_tck, - const struct lpddr2_addressing *addressing) -{ - u32 tim1 = 0, val = 0; - - val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1; - tim1 = val << T_WTR_SHIFT; - - /* - * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps - * to tFAW for de-rating - */ - if (addressing->num_banks == B8) { - val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1; - } else { - val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck); - val = max(min_tck->tRRD, val) - 1; - } - tim1 |= val << T_RRD_SHIFT; - - val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck); - tim1 |= (val - 1) << T_RC_SHIFT; - - val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck); - val = max(min_tck->tRASmin, val) - 1; - tim1 |= val << T_RAS_SHIFT; - - val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1; - tim1 |= val << T_WR_SHIFT; - - val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck)); - tim1 |= (val - 1) << T_RCD_SHIFT; - - val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck)); - tim1 |= (val - 1) << T_RP_SHIFT; - - return tim1; -} - -static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings, - const struct lpddr2_min_tck *min_tck, - const struct lpddr2_addressing *addressing, - u32 type) -{ - u32 tim2 = 0, val = 0; - - val = min_tck->tCKE - 1; - tim2 |= val << T_CKE_SHIFT; - - val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1; - tim2 |= val << T_RTP_SHIFT; - - /* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */ - val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1; - tim2 |= val << T_XSNR_SHIFT; - - /* XSRD same as XSNR for LPDDR2 */ - tim2 |= val << T_XSRD_SHIFT; - - val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1; - tim2 |= val << T_XP_SHIFT; - - return tim2; -} - -static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings, - const struct lpddr2_min_tck *min_tck, - const struct lpddr2_addressing *addressing, - u32 type, u32 ip_rev, u32 derated) -{ - u32 tim3 = 0, val = 0, t_dqsck; - - val = timings->tRAS_max_ns / addressing->tREFI_ns - 1; - val = val > 0xF ? 0xF : val; - tim3 |= val << T_RAS_MAX_SHIFT; - - val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1; - tim3 |= val << T_RFC_SHIFT; - - t_dqsck = (derated == EMIF_DERATED_TIMINGS) ? - timings->tDQSCK_max_derated : timings->tDQSCK_max; - if (ip_rev == EMIF_4D5) - val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1; - else - val = DIV_ROUND_UP(t_dqsck, t_ck) - 1; - - tim3 |= val << T_TDQSCKMAX_SHIFT; - - val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1; - tim3 |= val << ZQ_ZQCS_SHIFT; - - val = DIV_ROUND_UP(timings->tCKESR, t_ck); - val = max(min_tck->tCKESR, val) - 1; - tim3 |= val << T_CKESR_SHIFT; - - if (ip_rev == EMIF_4D5) { - tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT; - - val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1; - tim3 |= val << T_PDLL_UL_SHIFT; - } - - return tim3; -} - static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing, bool cs1_used, bool cal_resistors_per_cs) { @@ -589,117 +367,6 @@ static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing, return alert; } -static u32 get_read_idle_ctrl_shdw(u8 volt_ramp) -{ - u32 idle = 0, val = 0; - - /* - * Maximum value in normal conditions and increased frequency - * when voltage is ramping - */ - if (volt_ramp) - val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1; - else - val = 0x1FF; - - /* - * READ_IDLE_CTRL register in EMIF4D has same offset and fields - * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts - */ - idle |= val << DLL_CALIB_INTERVAL_SHIFT; - idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT; - - return idle; -} - -static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp) -{ - u32 calib = 0, val = 0; - - if (volt_ramp == DDR_VOLTAGE_RAMPING) - val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1; - else - val = 0; /* Disabled when voltage is stable */ - - calib |= val << DLL_CALIB_INTERVAL_SHIFT; - calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT; - - return calib; -} - -static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings, - u32 freq, u8 RL) -{ - u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0; - - val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1; - phy |= val << READ_LATENCY_SHIFT_4D; - - if (freq <= 100000000) - val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY; - else if (freq <= 200000000) - val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY; - else - val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY; - - phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D; - - return phy; -} - -static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl) -{ - u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay; - - /* - * DLL operates at 266 MHz. If DDR frequency is near 266 MHz, - * half-delay is not needed else set half-delay - */ - if (freq >= 265000000 && freq < 267000000) - half_delay = 0; - else - half_delay = 1; - - phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5; - phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS, - t_ck) - 1) << READ_LATENCY_SHIFT_4D5); - - return phy; -} - -static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void) -{ - u32 fifo_we_slave_ratio; - - fifo_we_slave_ratio = DIV_ROUND_CLOSEST( - EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck); - - return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 | - fifo_we_slave_ratio << 22; -} - -static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void) -{ - u32 fifo_we_slave_ratio; - - fifo_we_slave_ratio = DIV_ROUND_CLOSEST( - EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck); - - return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 | - fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23; -} - -static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void) -{ - u32 fifo_we_slave_ratio; - - fifo_we_slave_ratio = DIV_ROUND_CLOSEST( - EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck); - - return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 | - fifo_we_slave_ratio << 13; -} - static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) { u32 pwr_mgmt_ctrl = 0, timeout; @@ -821,51 +488,6 @@ static void get_temperature_level(struct emif_data *emif) emif->temperature_level = temperature_level; } -/* - * Program EMIF shadow registers that are not dependent on temperature - * or voltage - */ -static void setup_registers(struct emif_data *emif, struct emif_regs *regs) -{ - void __iomem *base = emif->base; - - writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW); - writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW); - writel(regs->pwr_mgmt_ctrl_shdw, - base + EMIF_POWER_MANAGEMENT_CTRL_SHDW); - - /* Settings specific for EMIF4D5 */ - if (emif->plat_data->ip_rev != EMIF_4D5) - return; - writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW); - writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW); - writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW); -} - -/* - * When voltage ramps dll calibration and forced read idle should - * happen more often - */ -static void setup_volt_sensitive_regs(struct emif_data *emif, - struct emif_regs *regs, u32 volt_state) -{ - u32 calib_ctrl; - void __iomem *base = emif->base; - - /* - * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as - * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_* - * is an alias of the respective read_idle_ctrl_shdw_* (members of - * a union). So, the below code takes care of both cases - */ - if (volt_state == DDR_VOLTAGE_RAMPING) - calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp; - else - calib_ctrl = regs->dll_calib_ctrl_shdw_normal; - - writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW); -} - /* * setup_temperature_sensitive_regs() - set the timings for temperature * sensitive registers. This happens once at initialisation time based @@ -1508,7 +1130,6 @@ static int __init_or_module emif_probe(struct platform_device *pdev) } list_add(&emif->node, &device_list); - emif->addressing = get_addressing_table(emif->plat_data->device_info); /* Save pointers to each other in emif and device structures */ emif->dev = &pdev->dev; @@ -1563,305 +1184,6 @@ static void emif_shutdown(struct platform_device *pdev) disable_and_clear_all_interrupts(emif); } -static int get_emif_reg_values(struct emif_data *emif, u32 freq, - struct emif_regs *regs) -{ - u32 ip_rev, phy_type; - u32 cl, type; - const struct lpddr2_timings *timings; - const struct lpddr2_min_tck *min_tck; - const struct ddr_device_info *device_info; - const struct lpddr2_addressing *addressing; - struct emif_data *emif_for_calc; - struct device *dev; - - dev = emif->dev; - /* - * If the devices on this EMIF instance is duplicate of EMIF1, - * use EMIF1 details for the calculation - */ - emif_for_calc = emif->duplicate ? emif1 : emif; - timings = get_timings_table(emif_for_calc, freq); - addressing = emif_for_calc->addressing; - if (!timings || !addressing) { - dev_err(dev, "%s: not enough data available for %dHz", - __func__, freq); - return -1; - } - - device_info = emif_for_calc->plat_data->device_info; - type = device_info->type; - ip_rev = emif_for_calc->plat_data->ip_rev; - phy_type = emif_for_calc->plat_data->phy_type; - - min_tck = emif_for_calc->plat_data->min_tck; - - set_ddr_clk_period(freq); - - regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing); - regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck, - addressing); - regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck, - addressing, type); - regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck, - addressing, type, ip_rev, EMIF_NORMAL_TIMINGS); - - cl = get_cl(emif); - - if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) { - regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d( - timings, freq, cl); - } else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) { - regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl); - regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5(); - regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5(); - regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5(); - } else { - return -1; - } - - /* Only timeout values in pwr_mgmt_ctrl_shdw register */ - regs->pwr_mgmt_ctrl_shdw = - get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) & - (CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK); - - if (ip_rev & EMIF_4D) { - regs->read_idle_ctrl_shdw_normal = - get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE); - - regs->read_idle_ctrl_shdw_volt_ramp = - get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING); - } else if (ip_rev & EMIF_4D5) { - regs->dll_calib_ctrl_shdw_normal = - get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE); - - regs->dll_calib_ctrl_shdw_volt_ramp = - get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING); - } - - if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) { - regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4, - addressing); - - regs->sdram_tim1_shdw_derated = - get_sdram_tim_1_shdw_derated(timings, min_tck, - addressing); - - regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings, - min_tck, addressing, type, ip_rev, - EMIF_DERATED_TIMINGS); - } - - regs->freq = freq; - - return 0; -} - -/* - * get_regs() - gets the cached emif_regs structure for a given EMIF instance - * given frequency(freq): - * - * As an optimisation, every EMIF instance other than EMIF1 shares the - * register cache with EMIF1 if the devices connected on this instance - * are same as that on EMIF1(indicated by the duplicate flag) - * - * If we do not have an entry corresponding to the frequency given, we - * allocate a new entry and calculate the values - * - * Upon finding the right reg dump, save it in curr_regs. It can be - * directly used for thermal de-rating and voltage ramping changes. - */ -static struct emif_regs *get_regs(struct emif_data *emif, u32 freq) -{ - int i; - struct emif_regs **regs_cache; - struct emif_regs *regs = NULL; - struct device *dev; - - dev = emif->dev; - if (emif->curr_regs && emif->curr_regs->freq == freq) { - dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq); - return emif->curr_regs; - } - - if (emif->duplicate) - regs_cache = emif1->regs_cache; - else - regs_cache = emif->regs_cache; - - for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) { - if (regs_cache[i]->freq == freq) { - regs = regs_cache[i]; - dev_dbg(dev, - "%s: reg dump found in reg cache for %u Hz\n", - __func__, freq); - break; - } - } - - /* - * If we don't have an entry for this frequency in the cache create one - * and calculate the values - */ - if (!regs) { - regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC); - if (!regs) - return NULL; - - if (get_emif_reg_values(emif, freq, regs)) { - devm_kfree(emif->dev, regs); - return NULL; - } - - /* - * Now look for an un-used entry in the cache and save the - * newly created struct. If there are no free entries - * over-write the last entry - */ - for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) - ; - - if (i >= EMIF_MAX_NUM_FREQUENCIES) { - dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n", - __func__); - i = EMIF_MAX_NUM_FREQUENCIES - 1; - devm_kfree(emif->dev, regs_cache[i]); - } - regs_cache[i] = regs; - } - - return regs; -} - -static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state) -{ - dev_dbg(emif->dev, "%s: voltage notification : %d", __func__, - volt_state); - - if (!emif->curr_regs) { - dev_err(emif->dev, - "%s: volt-notify before registers are ready: %d\n", - __func__, volt_state); - return; - } - - setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state); -} - -/* - * TODO: voltage notify handling should be hooked up to - * regulator framework as soon as the necessary support - * is available in mainline kernel. This function is un-used - * right now. - */ -static void __attribute__((unused)) volt_notify_handling(u32 volt_state) -{ - struct emif_data *emif; - - spin_lock_irqsave(&emif_lock, irq_state); - - list_for_each_entry(emif, &device_list, node) - do_volt_notify_handling(emif, volt_state); - do_freq_update(); - - spin_unlock_irqrestore(&emif_lock, irq_state); -} - -static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq) -{ - struct emif_regs *regs; - - regs = get_regs(emif, new_freq); - if (!regs) - return; - - emif->curr_regs = regs; - - /* - * Update the shadow registers: - * Temperature and voltage-ramp sensitive settings are also configured - * in terms of DDR cycles. So, we need to update them too when there - * is a freq change - */ - dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz", - __func__, new_freq); - setup_registers(emif, regs); - setup_temperature_sensitive_regs(emif, regs); - setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE); - - /* - * Part of workaround for errata i728. See do_freq_update() - * for more details - */ - if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) - set_lpmode(emif, EMIF_LP_MODE_DISABLE); -} - -/* - * TODO: frequency notify handling should be hooked up to - * clock framework as soon as the necessary support is - * available in mainline kernel. This function is un-used - * right now. - */ -static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq) -{ - struct emif_data *emif; - - /* - * NOTE: we are taking the spin-lock here and releases it - * only in post-notifier. This doesn't look good and - * Sparse complains about it, but this seems to be - * un-avoidable. We need to lock a sequence of events - * that is split between EMIF and clock framework. - * - * 1. EMIF driver updates EMIF timings in shadow registers in the - * frequency pre-notify callback from clock framework - * 2. clock framework sets up the registers for the new frequency - * 3. clock framework initiates a hw-sequence that updates - * the frequency EMIF timings synchronously. - * - * All these 3 steps should be performed as an atomic operation - * vis-a-vis similar sequence in the EMIF interrupt handler - * for temperature events. Otherwise, there could be race - * conditions that could result in incorrect EMIF timings for - * a given frequency - */ - spin_lock_irqsave(&emif_lock, irq_state); - - list_for_each_entry(emif, &device_list, node) - do_freq_pre_notify_handling(emif, new_freq); -} - -static void do_freq_post_notify_handling(struct emif_data *emif) -{ - /* - * Part of workaround for errata i728. See do_freq_update() - * for more details - */ - if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) - set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH); -} - -/* - * TODO: frequency notify handling should be hooked up to - * clock framework as soon as the necessary support is - * available in mainline kernel. This function is un-used - * right now. - */ -static void __attribute__((unused)) freq_post_notify_handling(void) -{ - struct emif_data *emif; - - list_for_each_entry(emif, &device_list, node) - do_freq_post_notify_handling(emif); - - /* - * Lock is done in pre-notify handler. See freq_pre_notify_handling() - * for more details - */ - spin_unlock_irqrestore(&emif_lock, irq_state); -} - #if defined(CONFIG_OF) static const struct of_device_id emif_of_match[] = { { .compatible = "ti,emif-4d" }, diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index 89f99b5b6450..d062c2f8250f 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -97,7 +97,6 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev) iounmap(ctrl->gregs); dev_set_drvdata(&dev->dev, NULL); - kfree(ctrl); return 0; } @@ -209,7 +208,8 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) dev_info(&dev->dev, "Freescale Integrated Flash Controller\n"); - fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL); + fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev), + GFP_KERNEL); if (!fsl_ifc_ctrl_dev) return -ENOMEM; @@ -219,8 +219,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0); if (!fsl_ifc_ctrl_dev->gregs) { dev_err(&dev->dev, "failed to get memory region\n"); - ret = -ENODEV; - goto err; + return -ENODEV; } if (of_property_read_bool(dev->dev.of_node, "little-endian")) { @@ -295,6 +294,7 @@ err_irq: free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev); irq_dispose_mapping(fsl_ifc_ctrl_dev->irq); err: + iounmap(fsl_ifc_ctrl_dev->gregs); return ret; } diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index 925d856663ac..f84b98278745 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -116,6 +116,7 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) break; } if (!match) { + err = -ENODEV; dev_err(&adev->dev, "no matching children\n"); goto disable_mem_clk; } diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index 4d5758c419c5..ffec26a99313 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -1048,16 +1048,19 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) if (ret) { dev_err(dev, "could not retrieve reg property: %d\n", ret); + of_node_put(child); return ret; } if (bank >= FMC2_MAX_BANKS) { dev_err(dev, "invalid reg value: %d\n", bank); + of_node_put(child); return -EINVAL; } if (ebi->bank_assigned & BIT(bank)) { dev_err(dev, "bank already assigned: %d\n", bank); + of_node_put(child); return -EINVAL; } @@ -1066,6 +1069,7 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) if (ret) { dev_err(dev, "setup chip select %d failed: %d\n", bank, ret); + of_node_put(child); return ret; } } diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index a70967a56e52..f9bae36c03a3 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -2,16 +2,18 @@ config TEGRA_MC bool "NVIDIA Tegra Memory Controller support" default y - depends on ARCH_TEGRA + depends on ARCH_TEGRA || (COMPILE_TEST && COMMON_CLK) select INTERCONNECT help This driver supports the Memory Controller (MC) hardware found on NVIDIA Tegra SoCs. +if TEGRA_MC + config TEGRA20_EMC tristate "NVIDIA Tegra20 External Memory Controller driver" default y - depends on TEGRA_MC && ARCH_TEGRA_2x_SOC + depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST select DEVFREQ_GOV_SIMPLE_ONDEMAND select PM_DEVFREQ help @@ -23,7 +25,7 @@ config TEGRA20_EMC config TEGRA30_EMC tristate "NVIDIA Tegra30 External Memory Controller driver" default y - depends on TEGRA_MC && ARCH_TEGRA_3x_SOC + depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST select PM_OPP help This driver is for the External Memory Controller (EMC) found on @@ -34,8 +36,8 @@ config TEGRA30_EMC config TEGRA124_EMC tristate "NVIDIA Tegra124 External Memory Controller driver" default y - depends on TEGRA_MC && ARCH_TEGRA_124_SOC - select TEGRA124_CLK_EMC + depends on ARCH_TEGRA_124_SOC || COMPILE_TEST + select TEGRA124_CLK_EMC if ARCH_TEGRA select PM_OPP help This driver is for the External Memory Controller (EMC) found on @@ -45,14 +47,16 @@ config TEGRA124_EMC config TEGRA210_EMC_TABLE bool - depends on ARCH_TEGRA_210_SOC + depends on ARCH_TEGRA_210_SOC || COMPILE_TEST config TEGRA210_EMC tristate "NVIDIA Tegra210 External Memory Controller driver" - depends on TEGRA_MC && ARCH_TEGRA_210_SOC + depends on ARCH_TEGRA_210_SOC || COMPILE_TEST select TEGRA210_EMC_TABLE help This driver is for the External Memory Controller (EMC) found on Tegra210 chips. The EMC controls the external DRAM on the board. This driver is required to change memory timings / clock rate for external memory. + +endif diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index 6c1a2ecc6628..c992e87782d2 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -7,6 +7,8 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o tegra-mc-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra124.o tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o +tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o +tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o obj-$(CONFIG_TEGRA_MC) += tegra-mc.o @@ -15,7 +17,7 @@ obj-$(CONFIG_TEGRA30_EMC) += tegra30-emc.o obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o -obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o tegra186-emc.o -obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra186-emc.o +obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o +obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index e58c3e5baea0..3c5aae7abf35 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -39,7 +39,13 @@ static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_210_SOC { .compatible = "nvidia,tegra210-mc", .data = &tegra210_mc_soc }, #endif - { } +#ifdef CONFIG_ARCH_TEGRA_186_SOC + { .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc }, +#endif +#ifdef CONFIG_ARCH_TEGRA_194_SOC + { .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc }, +#endif + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); @@ -91,6 +97,15 @@ struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev) } EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get); +int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev) +{ + if (mc->soc->ops && mc->soc->ops->probe_device) + return mc->soc->ops->probe_device(mc, dev); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra_mc_probe_device); + static int tegra_mc_block_dma_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { @@ -299,38 +314,6 @@ static int tegra_mc_reset_setup(struct tegra_mc *mc) return 0; } -static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) -{ - unsigned long long tick; - unsigned int i; - u32 value; - - /* compute the number of MC clock cycles per tick */ - tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); - do_div(tick, NSEC_PER_SEC); - - value = mc_readl(mc, MC_EMEM_ARB_CFG); - value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; - value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); - mc_writel(mc, value, MC_EMEM_ARB_CFG); - - /* write latency allowance defaults */ - for (i = 0; i < mc->soc->num_clients; i++) { - const struct tegra_mc_la *la = &mc->soc->clients[i].la; - u32 value; - - value = mc_readl(mc, la->reg); - value &= ~(la->mask << la->shift); - value |= (la->def & la->mask) << la->shift; - mc_writel(mc, value, la->reg); - } - - /* latch new values */ - mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); - - return 0; -} - int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) { unsigned int i; @@ -368,6 +351,43 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc) } EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count); +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ + defined(CONFIG_ARCH_TEGRA_114_SOC) || \ + defined(CONFIG_ARCH_TEGRA_124_SOC) || \ + defined(CONFIG_ARCH_TEGRA_132_SOC) || \ + defined(CONFIG_ARCH_TEGRA_210_SOC) +static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) +{ + unsigned long long tick; + unsigned int i; + u32 value; + + /* compute the number of MC clock cycles per tick */ + tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); + do_div(tick, NSEC_PER_SEC); + + value = mc_readl(mc, MC_EMEM_ARB_CFG); + value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; + value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); + mc_writel(mc, value, MC_EMEM_ARB_CFG); + + /* write latency allowance defaults */ + for (i = 0; i < mc->soc->num_clients; i++) { + const struct tegra_mc_client *client = &mc->soc->clients[i]; + u32 value; + + value = mc_readl(mc, client->regs.la.reg); + value &= ~(client->regs.la.mask << client->regs.la.shift); + value |= (client->regs.la.def & client->regs.la.mask) << client->regs.la.shift; + mc_writel(mc, value, client->regs.la.reg); + } + + /* latch new values */ + mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); + + return 0; +} + static int load_one_timing(struct tegra_mc *mc, struct tegra_mc_timing *timing, struct device_node *node) @@ -459,27 +479,35 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) return 0; } -static const char *const status_names[32] = { - [ 1] = "External interrupt", - [ 6] = "EMEM address decode error", - [ 7] = "GART page fault", - [ 8] = "Security violation", - [ 9] = "EMEM arbitration error", - [10] = "Page fault", - [11] = "Invalid APB ASID update", - [12] = "VPR violation", - [13] = "Secure carveout violation", - [16] = "MTS carveout violation", -}; +int tegra30_mc_probe(struct tegra_mc *mc) +{ + int err; -static const char *const error_names[8] = { - [2] = "EMEM decode error", - [3] = "TrustZone violation", - [4] = "Carveout violation", - [6] = "SMMU translation error", -}; + mc->clk = devm_clk_get_optional(mc->dev, "mc"); + if (IS_ERR(mc->clk)) { + dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk)); + return PTR_ERR(mc->clk); + } -static irqreturn_t tegra_mc_irq(int irq, void *data) + /* ensure that debug features are disabled */ + mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG); + + err = tegra_mc_setup_latency_allowance(mc); + if (err < 0) { + dev_err(mc->dev, "failed to setup latency allowance: %d\n", err); + return err; + } + + err = tegra_mc_setup_timings(mc); + if (err < 0) { + dev_err(mc->dev, "failed to setup timings: %d\n", err); + return err; + } + + return 0; +} + +static irqreturn_t tegra30_mc_handle_irq(int irq, void *data) { struct tegra_mc *mc = data; unsigned long status; @@ -491,7 +519,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data) return IRQ_NONE; for_each_set_bit(bit, &status, 32) { - const char *error = status_names[bit] ?: "unknown"; + const char *error = tegra_mc_status_names[bit] ?: "unknown"; const char *client = "unknown", *desc; const char *direction, *secure; phys_addr_t addr = 0; @@ -531,7 +559,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data) type = (value & MC_ERR_STATUS_TYPE_MASK) >> MC_ERR_STATUS_TYPE_SHIFT; - desc = error_names[type]; + desc = tegra_mc_error_names[type]; switch (value & MC_ERR_STATUS_TYPE_MASK) { case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: @@ -576,78 +604,31 @@ static irqreturn_t tegra_mc_irq(int irq, void *data) return IRQ_HANDLED; } -static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) -{ - struct tegra_mc *mc = data; - unsigned long status; - unsigned int bit; +const struct tegra_mc_ops tegra30_mc_ops = { + .probe = tegra30_mc_probe, + .handle_irq = tegra30_mc_handle_irq, +}; +#endif - /* mask all interrupts to avoid flooding */ - status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; - if (!status) - return IRQ_NONE; +const char *const tegra_mc_status_names[32] = { + [ 1] = "External interrupt", + [ 6] = "EMEM address decode error", + [ 7] = "GART page fault", + [ 8] = "Security violation", + [ 9] = "EMEM arbitration error", + [10] = "Page fault", + [11] = "Invalid APB ASID update", + [12] = "VPR violation", + [13] = "Secure carveout violation", + [16] = "MTS carveout violation", +}; - for_each_set_bit(bit, &status, 32) { - const char *direction = "read", *secure = ""; - const char *error = status_names[bit]; - const char *client, *desc; - phys_addr_t addr; - u32 value, reg; - u8 id, type; - - switch (BIT(bit)) { - case MC_INT_DECERR_EMEM: - reg = MC_DECERR_EMEM_OTHERS_STATUS; - value = mc_readl(mc, reg); - - id = value & mc->soc->client_id_mask; - desc = error_names[2]; - - if (value & BIT(31)) - direction = "write"; - break; - - case MC_INT_INVALID_GART_PAGE: - reg = MC_GART_ERROR_REQ; - value = mc_readl(mc, reg); - - id = (value >> 1) & mc->soc->client_id_mask; - desc = error_names[2]; - - if (value & BIT(0)) - direction = "write"; - break; - - case MC_INT_SECURITY_VIOLATION: - reg = MC_SECURITY_VIOLATION_STATUS; - value = mc_readl(mc, reg); - - id = value & mc->soc->client_id_mask; - type = (value & BIT(30)) ? 4 : 3; - desc = error_names[type]; - secure = "secure "; - - if (value & BIT(31)) - direction = "write"; - break; - - default: - continue; - } - - client = mc->soc->clients[id].name; - addr = mc_readl(mc, reg + sizeof(u32)); - - dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", - client, secure, direction, &addr, error, - desc); - } - - /* clear interrupts */ - mc_writel(mc, status, MC_INTSTATUS); - - return IRQ_HANDLED; -} +const char *const tegra_mc_error_names[8] = { + [2] = "EMEM decode error", + [3] = "TrustZone violation", + [4] = "Carveout violation", + [6] = "SMMU translation error", +}; /* * Memory Controller (MC) has few Memory Clients that are issuing memory @@ -748,7 +729,6 @@ static int tegra_mc_probe(struct platform_device *pdev) { struct resource *res; struct tegra_mc *mc; - void *isr; u64 mask; int err; @@ -777,69 +757,37 @@ static int tegra_mc_probe(struct platform_device *pdev) if (IS_ERR(mc->regs)) return PTR_ERR(mc->regs); - mc->clk = devm_clk_get(&pdev->dev, "mc"); - if (IS_ERR(mc->clk)) { - dev_err(&pdev->dev, "failed to get MC clock: %ld\n", - PTR_ERR(mc->clk)); - return PTR_ERR(mc->clk); - } - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - if (mc->soc == &tegra20_mc_soc) { - isr = tegra20_mc_irq; - } else -#endif - { - /* ensure that debug features are disabled */ - mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG); - - err = tegra_mc_setup_latency_allowance(mc); - if (err < 0) { - dev_err(&pdev->dev, - "failed to setup latency allowance: %d\n", - err); - return err; - } - - isr = tegra_mc_irq; - - err = tegra_mc_setup_timings(mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to setup timings: %d\n", - err); - return err; - } - } - - mc->irq = platform_get_irq(pdev, 0); - if (mc->irq < 0) - return mc->irq; - - WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); - - mc_writel(mc, mc->soc->intmask, MC_INTMASK); - - err = devm_request_irq(&pdev->dev, mc->irq, isr, 0, - dev_name(&pdev->dev), mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, - err); - return err; - } - mc->debugfs.root = debugfs_create_dir("mc", NULL); - if (mc->soc->init) { - err = mc->soc->init(mc); + if (mc->soc->ops && mc->soc->ops->probe) { + err = mc->soc->ops->probe(mc); if (err < 0) - dev_err(&pdev->dev, "failed to initialize SoC driver: %d\n", - err); + return err; } - err = tegra_mc_reset_setup(mc); - if (err < 0) - dev_err(&pdev->dev, "failed to register reset controller: %d\n", - err); + if (mc->soc->ops && mc->soc->ops->handle_irq) { + mc->irq = platform_get_irq(pdev, 0); + if (mc->irq < 0) + return mc->irq; + + WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); + + mc_writel(mc, mc->soc->intmask, MC_INTMASK); + + err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0, + dev_name(&pdev->dev), mc); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, + err); + return err; + } + } + + if (mc->soc->reset_ops) { + err = tegra_mc_reset_setup(mc); + if (err < 0) + dev_err(&pdev->dev, "failed to register reset controller: %d\n", err); + } err = tegra_mc_interconnect_setup(mc); if (err < 0) @@ -867,37 +815,28 @@ static int tegra_mc_probe(struct platform_device *pdev) return 0; } -static int tegra_mc_suspend(struct device *dev) +static int __maybe_unused tegra_mc_suspend(struct device *dev) { struct tegra_mc *mc = dev_get_drvdata(dev); - int err; - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_suspend(mc->gart); - if (err) - return err; - } + if (mc->soc->ops && mc->soc->ops->suspend) + return mc->soc->ops->suspend(mc); return 0; } -static int tegra_mc_resume(struct device *dev) +static int __maybe_unused tegra_mc_resume(struct device *dev) { struct tegra_mc *mc = dev_get_drvdata(dev); - int err; - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_resume(mc->gart); - if (err) - return err; - } + if (mc->soc->ops && mc->soc->ops->resume) + return mc->soc->ops->resume(mc); return 0; } static const struct dev_pm_ops tegra_mc_pm_ops = { - .suspend = tegra_mc_suspend, - .resume = tegra_mc_resume, + SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) }; static struct platform_driver tegra_mc_driver = { diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 1ee34f0da4f7..1e492989c363 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -129,6 +129,31 @@ extern const struct tegra_mc_soc tegra132_mc_soc; extern const struct tegra_mc_soc tegra210_mc_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_186_SOC +extern const struct tegra_mc_soc tegra186_mc_soc; +#endif + +#ifdef CONFIG_ARCH_TEGRA_194_SOC +extern const struct tegra_mc_soc tegra194_mc_soc; +#endif + +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ + defined(CONFIG_ARCH_TEGRA_114_SOC) || \ + defined(CONFIG_ARCH_TEGRA_124_SOC) || \ + defined(CONFIG_ARCH_TEGRA_132_SOC) || \ + defined(CONFIG_ARCH_TEGRA_210_SOC) +int tegra30_mc_probe(struct tegra_mc *mc); +extern const struct tegra_mc_ops tegra30_mc_ops; +#endif + +#if defined(CONFIG_ARCH_TEGRA_186_SOC) || \ + defined(CONFIG_ARCH_TEGRA_194_SOC) +extern const struct tegra_mc_ops tegra186_mc_ops; +#endif + +extern const char * const tegra_mc_status_names[32]; +extern const char * const tegra_mc_error_names[8]; + /* * These IDs are for internal use of Tegra ICC drivers. The ID numbers are * chosen such that they don't conflict with the device-tree ICC node IDs. diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index ed376ba2d2fe..41350570c815 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -15,883 +15,1013 @@ static const struct tegra_mc_client tegra114_mc_clients[] = { .id = 0x00, .name = "ptcr", .swgroup = TEGRA_SWGROUP_PTC, - .la = { - .reg = 0x34c, - .shift = 0, - .mask = 0xff, - .def = 0x0, + .regs = { + .la = { + .reg = 0x34c, + .shift = 0, + .mask = 0xff, + .def = 0x0, + }, }, }, { .id = 0x01, .name = "display0a", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 1, - }, - .la = { - .reg = 0x2e8, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 1, + }, + .la = { + .reg = 0x2e8, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x02, .name = "display0ab", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 2, - }, - .la = { - .reg = 0x2f4, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 2, + }, + .la = { + .reg = 0x2f4, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x03, .name = "display0b", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 3, - }, - .la = { - .reg = 0x2e8, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 3, + }, + .la = { + .reg = 0x2e8, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x04, .name = "display0bb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 4, - }, - .la = { - .reg = 0x2f4, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 4, + }, + .la = { + .reg = 0x2f4, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x05, .name = "display0c", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 5, - }, - .la = { - .reg = 0x2ec, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 5, + }, + .la = { + .reg = 0x2ec, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x06, .name = "display0cb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 6, - }, - .la = { - .reg = 0x2f8, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 6, + }, + .la = { + .reg = 0x2f8, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, }, { .id = 0x09, .name = "eppup", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x228, - .bit = 9, - }, - .la = { - .reg = 0x300, - .shift = 0, - .mask = 0xff, - .def = 0x33, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 9, + }, + .la = { + .reg = 0x300, + .shift = 0, + .mask = 0xff, + .def = 0x33, + }, }, }, { .id = 0x0a, .name = "g2pr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 10, - }, - .la = { - .reg = 0x308, - .shift = 0, - .mask = 0xff, - .def = 0x09, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 10, + }, + .la = { + .reg = 0x308, + .shift = 0, + .mask = 0xff, + .def = 0x09, + }, }, }, { .id = 0x0b, .name = "g2sr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 11, - }, - .la = { - .reg = 0x308, - .shift = 16, - .mask = 0xff, - .def = 0x09, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 11, + }, + .la = { + .reg = 0x308, + .shift = 16, + .mask = 0xff, + .def = 0x09, + }, }, }, { .id = 0x0f, .name = "avpcarm7r", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x228, - .bit = 15, - }, - .la = { - .reg = 0x2e4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 15, + }, + .la = { + .reg = 0x2e4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x10, .name = "displayhc", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 16, - }, - .la = { - .reg = 0x2f0, - .shift = 0, - .mask = 0xff, - .def = 0x68, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 16, + }, + .la = { + .reg = 0x2f0, + .shift = 0, + .mask = 0xff, + .def = 0x68, + }, }, }, { .id = 0x11, .name = "displayhcb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 17, - }, - .la = { - .reg = 0x2fc, - .shift = 0, - .mask = 0xff, - .def = 0x68, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 17, + }, + .la = { + .reg = 0x2fc, + .shift = 0, + .mask = 0xff, + .def = 0x68, + }, }, }, { .id = 0x12, .name = "fdcdrd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x228, - .bit = 18, - }, - .la = { - .reg = 0x334, - .shift = 0, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 18, + }, + .la = { + .reg = 0x334, + .shift = 0, + .mask = 0xff, + .def = 0x0c, + }, }, }, { .id = 0x13, .name = "fdcdrd2", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x228, - .bit = 19, - }, - .la = { - .reg = 0x33c, - .shift = 0, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 19, + }, + .la = { + .reg = 0x33c, + .shift = 0, + .mask = 0xff, + .def = 0x0c, + }, }, }, { .id = 0x14, .name = "g2dr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 20, - }, - .la = { - .reg = 0x30c, - .shift = 0, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 20, + }, + .la = { + .reg = 0x30c, + .shift = 0, + .mask = 0xff, + .def = 0x0a, + }, }, }, { .id = 0x15, .name = "hdar", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x228, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x16, .name = "host1xdmar", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 22, - }, - .la = { - .reg = 0x310, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 22, + }, + .la = { + .reg = 0x310, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, }, { .id = 0x17, .name = "host1xr", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 23, - }, - .la = { - .reg = 0x310, - .shift = 16, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 23, + }, + .la = { + .reg = 0x310, + .shift = 16, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x18, .name = "idxsrd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x228, - .bit = 24, - }, - .la = { - .reg = 0x334, - .shift = 16, - .mask = 0xff, - .def = 0x0b, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 24, + }, + .la = { + .reg = 0x334, + .shift = 16, + .mask = 0xff, + .def = 0x0b, + }, }, }, { .id = 0x1c, .name = "msencsrd", .swgroup = TEGRA_SWGROUP_MSENC, - .smmu = { - .reg = 0x228, - .bit = 28, - }, - .la = { - .reg = 0x328, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 28, + }, + .la = { + .reg = 0x328, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x1d, .name = "ppcsahbdmar", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 29, - }, - .la = { - .reg = 0x344, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 29, + }, + .la = { + .reg = 0x344, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x1e, .name = "ppcsahbslvr", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 30, - }, - .la = { - .reg = 0x344, - .shift = 16, - .mask = 0xff, - .def = 0xe8, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 30, + }, + .la = { + .reg = 0x344, + .shift = 16, + .mask = 0xff, + .def = 0xe8, + }, }, }, { .id = 0x20, .name = "texl2srd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x22c, - .bit = 0, - }, - .la = { - .reg = 0x338, - .shift = 0, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 0, + }, + .la = { + .reg = 0x338, + .shift = 0, + .mask = 0xff, + .def = 0x0c, + }, }, }, { .id = 0x22, .name = "vdebsevr", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 2, - }, - .la = { - .reg = 0x354, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 2, + }, + .la = { + .reg = 0x354, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x23, .name = "vdember", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 3, - }, - .la = { - .reg = 0x354, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 3, + }, + .la = { + .reg = 0x354, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x24, .name = "vdemcer", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 4, - }, - .la = { - .reg = 0x358, - .shift = 0, - .mask = 0xff, - .def = 0xb8, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 4, + }, + .la = { + .reg = 0x358, + .shift = 0, + .mask = 0xff, + .def = 0xb8, + }, }, }, { .id = 0x25, .name = "vdetper", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 5, - }, - .la = { - .reg = 0x358, - .shift = 16, - .mask = 0xff, - .def = 0xee, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 5, + }, + .la = { + .reg = 0x358, + .shift = 16, + .mask = 0xff, + .def = 0xee, + }, }, }, { .id = 0x26, .name = "mpcorelpr", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x324, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x27, .name = "mpcorer", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x320, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x28, .name = "eppu", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 8, - }, - .la = { - .reg = 0x300, - .shift = 16, - .mask = 0xff, - .def = 0x33, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 8, + }, + .la = { + .reg = 0x300, + .shift = 16, + .mask = 0xff, + .def = 0x33, + }, }, }, { .id = 0x29, .name = "eppv", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 9, - }, - .la = { - .reg = 0x304, - .shift = 0, - .mask = 0xff, - .def = 0x6c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 9, + }, + .la = { + .reg = 0x304, + .shift = 0, + .mask = 0xff, + .def = 0x6c, + }, }, }, { .id = 0x2a, .name = "eppy", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 10, - }, - .la = { - .reg = 0x304, - .shift = 16, - .mask = 0xff, - .def = 0x6c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 10, + }, + .la = { + .reg = 0x304, + .shift = 16, + .mask = 0xff, + .def = 0x6c, + }, }, }, { .id = 0x2b, .name = "msencswr", .swgroup = TEGRA_SWGROUP_MSENC, - .smmu = { - .reg = 0x22c, - .bit = 11, - }, - .la = { - .reg = 0x328, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 11, + }, + .la = { + .reg = 0x328, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x2c, .name = "viwsb", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 12, - }, - .la = { - .reg = 0x364, - .shift = 0, - .mask = 0xff, - .def = 0x47, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 12, + }, + .la = { + .reg = 0x364, + .shift = 0, + .mask = 0xff, + .def = 0x47, + }, }, }, { .id = 0x2d, .name = "viwu", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 13, - }, - .la = { - .reg = 0x368, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 13, + }, + .la = { + .reg = 0x368, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x2e, .name = "viwv", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 14, - }, - .la = { - .reg = 0x368, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 14, + }, + .la = { + .reg = 0x368, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x2f, .name = "viwy", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 15, - }, - .la = { - .reg = 0x36c, - .shift = 0, - .mask = 0xff, - .def = 0x47, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 15, + }, + .la = { + .reg = 0x36c, + .shift = 0, + .mask = 0xff, + .def = 0x47, + }, }, }, { .id = 0x30, .name = "g2dw", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x22c, - .bit = 16, - }, - .la = { - .reg = 0x30c, - .shift = 16, - .mask = 0xff, - .def = 0x9, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 16, + }, + .la = { + .reg = 0x30c, + .shift = 16, + .mask = 0xff, + .def = 0x9, + }, }, }, { .id = 0x32, .name = "avpcarm7w", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x22c, - .bit = 18, - }, - .la = { - .reg = 0x2e4, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 18, + }, + .la = { + .reg = 0x2e4, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, }, { .id = 0x33, .name = "fdcdwr", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x22c, - .bit = 19, - }, - .la = { - .reg = 0x338, - .shift = 16, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 19, + }, + .la = { + .reg = 0x338, + .shift = 16, + .mask = 0xff, + .def = 0x10, + }, }, }, { .id = 0x34, .name = "fdcdwr2", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x22c, - .bit = 20, - }, - .la = { - .reg = 0x340, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 20, + }, + .la = { + .reg = 0x340, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, }, { .id = 0x35, .name = "hdaw", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x22c, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x36, .name = "host1xw", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x22c, - .bit = 22, - }, - .la = { - .reg = 0x314, - .shift = 0, - .mask = 0xff, - .def = 0x25, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 22, + }, + .la = { + .reg = 0x314, + .shift = 0, + .mask = 0xff, + .def = 0x25, + }, }, }, { .id = 0x37, .name = "ispw", .swgroup = TEGRA_SWGROUP_ISP, - .smmu = { - .reg = 0x22c, - .bit = 23, - }, - .la = { - .reg = 0x31c, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 23, + }, + .la = { + .reg = 0x31c, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x38, .name = "mpcorelpw", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .la = { + .reg = 0x324, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x39, .name = "mpcorew", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .la = { + .reg = 0x320, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, }, { .id = 0x3b, .name = "ppcsahbdmaw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 27, - }, - .la = { - .reg = 0x348, - .shift = 0, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 27, + }, + .la = { + .reg = 0x348, + .shift = 0, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x3c, .name = "ppcsahbslvw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 28, - }, - .la = { - .reg = 0x348, - .shift = 16, - .mask = 0xff, - .def = 0xe8, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 28, + }, + .la = { + .reg = 0x348, + .shift = 16, + .mask = 0xff, + .def = 0xe8, + }, }, }, { .id = 0x3e, .name = "vdebsevw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 30, - }, - .la = { - .reg = 0x35c, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 30, + }, + .la = { + .reg = 0x35c, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x3f, .name = "vdedbgw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 31, - }, - .la = { - .reg = 0x35c, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 31, + }, + .la = { + .reg = 0x35c, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x40, .name = "vdembew", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 0, - }, - .la = { - .reg = 0x360, - .shift = 0, - .mask = 0xff, - .def = 0x89, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 0, + }, + .la = { + .reg = 0x360, + .shift = 0, + .mask = 0xff, + .def = 0x89, + }, }, }, { .id = 0x41, .name = "vdetpmw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 1, - }, - .la = { - .reg = 0x360, - .shift = 16, - .mask = 0xff, - .def = 0x59, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 1, + }, + .la = { + .reg = 0x360, + .shift = 16, + .mask = 0xff, + .def = 0x59, + }, }, }, { .id = 0x4a, .name = "xusb_hostr", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 10, - }, - .la = { - .reg = 0x37c, - .shift = 0, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 10, + }, + .la = { + .reg = 0x37c, + .shift = 0, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x4b, .name = "xusb_hostw", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 11, - }, - .la = { - .reg = 0x37c, - .shift = 16, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 11, + }, + .la = { + .reg = 0x37c, + .shift = 16, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x4c, .name = "xusb_devr", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 12, - }, - .la = { - .reg = 0x380, - .shift = 0, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 12, + }, + .la = { + .reg = 0x380, + .shift = 0, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x4d, .name = "xusb_devw", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 13, - }, - .la = { - .reg = 0x380, - .shift = 16, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 13, + }, + .la = { + .reg = 0x380, + .shift = 16, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x4e, .name = "fdcdwr3", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x230, - .bit = 14, - }, - .la = { - .reg = 0x388, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 14, + }, + .la = { + .reg = 0x388, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, }, { .id = 0x4f, .name = "fdcdrd3", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x230, - .bit = 15, - }, - .la = { - .reg = 0x384, - .shift = 0, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 15, + }, + .la = { + .reg = 0x384, + .shift = 0, + .mask = 0xff, + .def = 0x0c, + }, }, }, { .id = 0x50, .name = "fdcwr4", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x230, - .bit = 16, - }, - .la = { - .reg = 0x388, - .shift = 16, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 16, + }, + .la = { + .reg = 0x388, + .shift = 16, + .mask = 0xff, + .def = 0x10, + }, }, }, { .id = 0x51, .name = "fdcrd4", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x230, - .bit = 17, - }, - .la = { - .reg = 0x384, - .shift = 16, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 17, + }, + .la = { + .reg = 0x384, + .shift = 16, + .mask = 0xff, + .def = 0x0c, + }, }, }, { .id = 0x52, .name = "emucifr", .swgroup = TEGRA_SWGROUP_EMUCIF, - .la = { - .reg = 0x38c, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x38c, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x53, .name = "emucifw", .swgroup = TEGRA_SWGROUP_EMUCIF, - .la = { - .reg = 0x38c, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .la = { + .reg = 0x38c, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, }, { .id = 0x54, .name = "tsecsrd", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 20, - }, - .la = { - .reg = 0x390, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 20, + }, + .la = { + .reg = 0x390, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x55, .name = "tsecswr", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 21, - }, - .la = { - .reg = 0x390, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 21, + }, + .la = { + .reg = 0x390, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, }; @@ -983,4 +1113,5 @@ const struct tegra_mc_soc tegra114_mc_soc = { .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra114_mc_resets, .num_resets = ARRAY_SIZE(tegra114_mc_resets), + .ops = &tegra30_mc_ops, }; diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 5699d909abc2..908f8d5392b2 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -272,8 +272,8 @@ #define EMC_PUTERM_ADJ 0x574 #define DRAM_DEV_SEL_ALL 0 -#define DRAM_DEV_SEL_0 (2 << 30) -#define DRAM_DEV_SEL_1 (1 << 30) +#define DRAM_DEV_SEL_0 BIT(31) +#define DRAM_DEV_SEL_1 BIT(30) #define EMC_CFG_POWER_FEATURES_MASK \ (EMC_CFG_DYN_SREF | EMC_CFG_DRAM_ACPD | EMC_CFG_DRAM_CLKSTOP_SR | \ @@ -1269,10 +1269,6 @@ static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) } emc->debugfs.root = debugfs_create_dir("emc", NULL); - if (!emc->debugfs.root) { - dev_err(dev, "failed to create debugfs directory\n"); - return; - } debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, &tegra_emc_debug_available_rates_fops); diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 459211f50c08..d780a84241fe 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -16,921 +16,1055 @@ static const struct tegra_mc_client tegra124_mc_clients[] = { .id = 0x00, .name = "ptcr", .swgroup = TEGRA_SWGROUP_PTC, - .la = { - .reg = 0x34c, - .shift = 0, - .mask = 0xff, - .def = 0x0, + .regs = { + .la = { + .reg = 0x34c, + .shift = 0, + .mask = 0xff, + .def = 0x0, + }, }, }, { .id = 0x01, .name = "display0a", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 1, - }, - .la = { - .reg = 0x2e8, - .shift = 0, - .mask = 0xff, - .def = 0xc2, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 1, + }, + .la = { + .reg = 0x2e8, + .shift = 0, + .mask = 0xff, + .def = 0xc2, + }, }, }, { .id = 0x02, .name = "display0ab", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 2, - }, - .la = { - .reg = 0x2f4, - .shift = 0, - .mask = 0xff, - .def = 0xc6, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 2, + }, + .la = { + .reg = 0x2f4, + .shift = 0, + .mask = 0xff, + .def = 0xc6, + }, }, }, { .id = 0x03, .name = "display0b", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 3, - }, - .la = { - .reg = 0x2e8, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 3, + }, + .la = { + .reg = 0x2e8, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x04, .name = "display0bb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 4, - }, - .la = { - .reg = 0x2f4, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 4, + }, + .la = { + .reg = 0x2f4, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x05, .name = "display0c", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 5, - }, - .la = { - .reg = 0x2ec, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 5, + }, + .la = { + .reg = 0x2ec, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x06, .name = "display0cb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 6, - }, - .la = { - .reg = 0x2f8, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 6, + }, + .la = { + .reg = 0x2f8, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x0e, .name = "afir", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x228, - .bit = 14, - }, - .la = { - .reg = 0x2e0, - .shift = 0, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 14, + }, + .la = { + .reg = 0x2e0, + .shift = 0, + .mask = 0xff, + .def = 0x13, + }, }, }, { .id = 0x0f, .name = "avpcarm7r", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x228, - .bit = 15, - }, - .la = { - .reg = 0x2e4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 15, + }, + .la = { + .reg = 0x2e4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x10, .name = "displayhc", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 16, - }, - .la = { - .reg = 0x2f0, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 16, + }, + .la = { + .reg = 0x2f0, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x11, .name = "displayhcb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 17, - }, - .la = { - .reg = 0x2fc, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 17, + }, + .la = { + .reg = 0x2fc, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x15, .name = "hdar", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x228, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 0, - .mask = 0xff, - .def = 0x24, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 0, + .mask = 0xff, + .def = 0x24, + }, }, }, { .id = 0x16, .name = "host1xdmar", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 22, - }, - .la = { - .reg = 0x310, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 22, + }, + .la = { + .reg = 0x310, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x17, .name = "host1xr", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 23, - }, - .la = { - .reg = 0x310, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 23, + }, + .la = { + .reg = 0x310, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x1c, .name = "msencsrd", .swgroup = TEGRA_SWGROUP_MSENC, - .smmu = { - .reg = 0x228, - .bit = 28, - }, - .la = { - .reg = 0x328, - .shift = 0, - .mask = 0xff, - .def = 0x23, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 28, + }, + .la = { + .reg = 0x328, + .shift = 0, + .mask = 0xff, + .def = 0x23, + }, }, }, { .id = 0x1d, .name = "ppcsahbdmar", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 29, - }, - .la = { - .reg = 0x344, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 29, + }, + .la = { + .reg = 0x344, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x1e, .name = "ppcsahbslvr", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 30, - }, - .la = { - .reg = 0x344, - .shift = 16, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 30, + }, + .la = { + .reg = 0x344, + .shift = 16, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x1f, .name = "satar", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x228, - .bit = 31, - }, - .la = { - .reg = 0x350, - .shift = 0, - .mask = 0xff, - .def = 0x65, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 31, + }, + .la = { + .reg = 0x350, + .shift = 0, + .mask = 0xff, + .def = 0x65, + }, }, }, { .id = 0x22, .name = "vdebsevr", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 2, - }, - .la = { - .reg = 0x354, - .shift = 0, - .mask = 0xff, - .def = 0x4f, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 2, + }, + .la = { + .reg = 0x354, + .shift = 0, + .mask = 0xff, + .def = 0x4f, + }, }, }, { .id = 0x23, .name = "vdember", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 3, - }, - .la = { - .reg = 0x354, - .shift = 16, - .mask = 0xff, - .def = 0x3d, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 3, + }, + .la = { + .reg = 0x354, + .shift = 16, + .mask = 0xff, + .def = 0x3d, + }, }, }, { .id = 0x24, .name = "vdemcer", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 4, - }, - .la = { - .reg = 0x358, - .shift = 0, - .mask = 0xff, - .def = 0x66, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 4, + }, + .la = { + .reg = 0x358, + .shift = 0, + .mask = 0xff, + .def = 0x66, + }, }, }, { .id = 0x25, .name = "vdetper", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 5, - }, - .la = { - .reg = 0x358, - .shift = 16, - .mask = 0xff, - .def = 0xa5, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 5, + }, + .la = { + .reg = 0x358, + .shift = 16, + .mask = 0xff, + .def = 0xa5, + }, }, }, { .id = 0x26, .name = "mpcorelpr", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x324, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x27, .name = "mpcorer", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x320, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x2b, .name = "msencswr", .swgroup = TEGRA_SWGROUP_MSENC, - .smmu = { - .reg = 0x22c, - .bit = 11, - }, - .la = { - .reg = 0x328, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 11, + }, + .la = { + .reg = 0x328, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x31, .name = "afiw", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x22c, - .bit = 17, - }, - .la = { - .reg = 0x2e0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 17, + }, + .la = { + .reg = 0x2e0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x32, .name = "avpcarm7w", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x22c, - .bit = 18, - }, - .la = { - .reg = 0x2e4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 18, + }, + .la = { + .reg = 0x2e4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x35, .name = "hdaw", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x22c, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x36, .name = "host1xw", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x22c, - .bit = 22, - }, - .la = { - .reg = 0x314, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 22, + }, + .la = { + .reg = 0x314, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x38, .name = "mpcorelpw", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .la = { + .reg = 0x324, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x39, .name = "mpcorew", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .la = { + .reg = 0x320, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3b, .name = "ppcsahbdmaw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 27, - }, - .la = { - .reg = 0x348, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 27, + }, + .la = { + .reg = 0x348, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3c, .name = "ppcsahbslvw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 28, - }, - .la = { - .reg = 0x348, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 28, + }, + .la = { + .reg = 0x348, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3d, .name = "sataw", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x22c, - .bit = 29, - }, - .la = { - .reg = 0x350, - .shift = 16, - .mask = 0xff, - .def = 0x65, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 29, + }, + .la = { + .reg = 0x350, + .shift = 16, + .mask = 0xff, + .def = 0x65, + }, }, }, { .id = 0x3e, .name = "vdebsevw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 30, - }, - .la = { - .reg = 0x35c, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 30, + }, + .la = { + .reg = 0x35c, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3f, .name = "vdedbgw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 31, - }, - .la = { - .reg = 0x35c, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 31, + }, + .la = { + .reg = 0x35c, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x40, .name = "vdembew", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 0, - }, - .la = { - .reg = 0x360, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 0, + }, + .la = { + .reg = 0x360, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x41, .name = "vdetpmw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 1, - }, - .la = { - .reg = 0x360, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 1, + }, + .la = { + .reg = 0x360, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x44, .name = "ispra", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 4, - }, - .la = { - .reg = 0x370, - .shift = 0, - .mask = 0xff, - .def = 0x18, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 4, + }, + .la = { + .reg = 0x370, + .shift = 0, + .mask = 0xff, + .def = 0x18, + }, }, }, { .id = 0x46, .name = "ispwa", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 6, - }, - .la = { - .reg = 0x374, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 6, + }, + .la = { + .reg = 0x374, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x47, .name = "ispwb", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 7, - }, - .la = { - .reg = 0x374, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 7, + }, + .la = { + .reg = 0x374, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4a, .name = "xusb_hostr", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 10, - }, - .la = { - .reg = 0x37c, - .shift = 0, - .mask = 0xff, - .def = 0x39, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 10, + }, + .la = { + .reg = 0x37c, + .shift = 0, + .mask = 0xff, + .def = 0x39, + }, }, }, { .id = 0x4b, .name = "xusb_hostw", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 11, - }, - .la = { - .reg = 0x37c, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 11, + }, + .la = { + .reg = 0x37c, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4c, .name = "xusb_devr", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 12, - }, - .la = { - .reg = 0x380, - .shift = 0, - .mask = 0xff, - .def = 0x39, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 12, + }, + .la = { + .reg = 0x380, + .shift = 0, + .mask = 0xff, + .def = 0x39, + }, }, }, { .id = 0x4d, .name = "xusb_devw", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 13, - }, - .la = { - .reg = 0x380, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 13, + }, + .la = { + .reg = 0x380, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4e, .name = "isprab", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 14, - }, - .la = { - .reg = 0x384, - .shift = 0, - .mask = 0xff, - .def = 0x18, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 14, + }, + .la = { + .reg = 0x384, + .shift = 0, + .mask = 0xff, + .def = 0x18, + }, }, }, { .id = 0x50, .name = "ispwab", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 16, - }, - .la = { - .reg = 0x388, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 16, + }, + .la = { + .reg = 0x388, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x51, .name = "ispwbb", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 17, - }, - .la = { - .reg = 0x388, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 17, + }, + .la = { + .reg = 0x388, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x54, .name = "tsecsrd", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 20, - }, - .la = { - .reg = 0x390, - .shift = 0, - .mask = 0xff, - .def = 0x9b, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 20, + }, + .la = { + .reg = 0x390, + .shift = 0, + .mask = 0xff, + .def = 0x9b, + }, }, }, { .id = 0x55, .name = "tsecswr", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 21, - }, - .la = { - .reg = 0x390, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 21, + }, + .la = { + .reg = 0x390, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x56, .name = "a9avpscr", .swgroup = TEGRA_SWGROUP_A9AVP, - .smmu = { - .reg = 0x230, - .bit = 22, - }, - .la = { - .reg = 0x3a4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 22, + }, + .la = { + .reg = 0x3a4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x57, .name = "a9avpscw", .swgroup = TEGRA_SWGROUP_A9AVP, - .smmu = { - .reg = 0x230, - .bit = 23, - }, - .la = { - .reg = 0x3a4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 23, + }, + .la = { + .reg = 0x3a4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x58, .name = "gpusrd", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0x230, - .bit = 24, - }, - .la = { - .reg = 0x3c8, - .shift = 0, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + /* read-only */ + .reg = 0x230, + .bit = 24, + }, + .la = { + .reg = 0x3c8, + .shift = 0, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x59, .name = "gpuswr", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0x230, - .bit = 25, - }, - .la = { - .reg = 0x3c8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + /* read-only */ + .reg = 0x230, + .bit = 25, + }, + .la = { + .reg = 0x3c8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x5a, .name = "displayt", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x230, - .bit = 26, - }, - .la = { - .reg = 0x2f0, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 26, + }, + .la = { + .reg = 0x2f0, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x60, .name = "sdmmcra", .swgroup = TEGRA_SWGROUP_SDMMC1A, - .smmu = { - .reg = 0x234, - .bit = 0, - }, - .la = { - .reg = 0x3b8, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 0, + }, + .la = { + .reg = 0x3b8, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x61, .name = "sdmmcraa", .swgroup = TEGRA_SWGROUP_SDMMC2A, - .smmu = { - .reg = 0x234, - .bit = 1, - }, - .la = { - .reg = 0x3bc, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 1, + }, + .la = { + .reg = 0x3bc, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x62, .name = "sdmmcr", .swgroup = TEGRA_SWGROUP_SDMMC3A, - .smmu = { - .reg = 0x234, - .bit = 2, - }, - .la = { - .reg = 0x3c0, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 2, + }, + .la = { + .reg = 0x3c0, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x63, .swgroup = TEGRA_SWGROUP_SDMMC4A, .name = "sdmmcrab", - .smmu = { - .reg = 0x234, - .bit = 3, - }, - .la = { - .reg = 0x3c4, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 3, + }, + .la = { + .reg = 0x3c4, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x64, .name = "sdmmcwa", .swgroup = TEGRA_SWGROUP_SDMMC1A, - .smmu = { - .reg = 0x234, - .bit = 4, - }, - .la = { - .reg = 0x3b8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 4, + }, + .la = { + .reg = 0x3b8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x65, .name = "sdmmcwaa", .swgroup = TEGRA_SWGROUP_SDMMC2A, - .smmu = { - .reg = 0x234, - .bit = 5, - }, - .la = { - .reg = 0x3bc, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 5, + }, + .la = { + .reg = 0x3bc, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x66, .name = "sdmmcw", .swgroup = TEGRA_SWGROUP_SDMMC3A, - .smmu = { - .reg = 0x234, - .bit = 6, - }, - .la = { - .reg = 0x3c0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 6, + }, + .la = { + .reg = 0x3c0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x67, .name = "sdmmcwab", .swgroup = TEGRA_SWGROUP_SDMMC4A, - .smmu = { - .reg = 0x234, - .bit = 7, - }, - .la = { - .reg = 0x3c4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 7, + }, + .la = { + .reg = 0x3c4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x6c, .name = "vicsrd", .swgroup = TEGRA_SWGROUP_VIC, - .smmu = { - .reg = 0x234, - .bit = 12, - }, - .la = { - .reg = 0x394, - .shift = 0, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 12, + }, + .la = { + .reg = 0x394, + .shift = 0, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x6d, .name = "vicswr", .swgroup = TEGRA_SWGROUP_VIC, - .smmu = { - .reg = 0x234, - .bit = 13, - }, - .la = { - .reg = 0x394, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 13, + }, + .la = { + .reg = 0x394, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x72, .name = "viw", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x234, - .bit = 18, - }, - .la = { - .reg = 0x398, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 18, + }, + .la = { + .reg = 0x398, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x73, .name = "displayd", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x234, - .bit = 19, - }, - .la = { - .reg = 0x3c8, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 19, + }, + .la = { + .reg = 0x3c8, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, }; @@ -1140,6 +1274,7 @@ const struct tegra_mc_soc tegra124_mc_soc = { .resets = tegra124_mc_resets, .num_resets = ARRAY_SIZE(tegra124_mc_resets), .icc_ops = &tegra124_mc_icc_ops, + .ops = &tegra30_mc_ops, }; #endif /* CONFIG_ARCH_TEGRA_124_SOC */ @@ -1171,5 +1306,6 @@ const struct tegra_mc_soc tegra132_mc_soc = { .resets = tegra124_mc_resets, .num_resets = ARRAY_SIZE(tegra124_mc_resets), .icc_ops = &tegra124_mc_icc_ops, + .ops = &tegra30_mc_ops, }; #endif /* CONFIG_ARCH_TEGRA_132_SOC */ diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index e25c954dde2e..e65eac5764d4 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -1,1605 +1,878 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved. */ #include +#include #include #include #include #include +#include + #if defined(CONFIG_ARCH_TEGRA_186_SOC) #include #endif -#if defined(CONFIG_ARCH_TEGRA_194_SOC) -#include -#endif +#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0) +#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16) +#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8) -struct tegra186_mc_client { - const char *name; - unsigned int sid; - struct { - unsigned int override; - unsigned int security; - } regs; -}; - -struct tegra186_mc_soc { - const struct tegra186_mc_client *clients; - unsigned int num_clients; -}; - -struct tegra186_mc { - struct device *dev; - void __iomem *regs; - - const struct tegra186_mc_soc *soc; -}; - -static void tegra186_mc_program_sid(struct tegra186_mc *mc) +static void tegra186_mc_program_sid(struct tegra_mc *mc) { unsigned int i; for (i = 0; i < mc->soc->num_clients; i++) { - const struct tegra186_mc_client *client = &mc->soc->clients[i]; + const struct tegra_mc_client *client = &mc->soc->clients[i]; u32 override, security; - override = readl(mc->regs + client->regs.override); - security = readl(mc->regs + client->regs.security); + override = readl(mc->regs + client->regs.sid.override); + security = readl(mc->regs + client->regs.sid.security); dev_dbg(mc->dev, "client %s: override: %x security: %x\n", client->name, override, security); dev_dbg(mc->dev, "setting SID %u for %s\n", client->sid, client->name); - writel(client->sid, mc->regs + client->regs.override); + writel(client->sid, mc->regs + client->regs.sid.override); - override = readl(mc->regs + client->regs.override); - security = readl(mc->regs + client->regs.security); + override = readl(mc->regs + client->regs.sid.override); + security = readl(mc->regs + client->regs.sid.security); dev_dbg(mc->dev, "client %s: override: %x security: %x\n", client->name, override, security); } } -#if defined(CONFIG_ARCH_TEGRA_186_SOC) -static const struct tegra186_mc_client tegra186_mc_clients[] = { - { - .name = "ptcr", - .sid = TEGRA186_SID_PASSTHROUGH, - .regs = { - .override = 0x000, - .security = 0x004, - }, - }, { - .name = "afir", - .sid = TEGRA186_SID_AFI, - .regs = { - .override = 0x070, - .security = 0x074, - }, - }, { - .name = "hdar", - .sid = TEGRA186_SID_HDA, - .regs = { - .override = 0x0a8, - .security = 0x0ac, - }, - }, { - .name = "host1xdmar", - .sid = TEGRA186_SID_HOST1X, - .regs = { - .override = 0x0b0, - .security = 0x0b4, - }, - }, { - .name = "nvencsrd", - .sid = TEGRA186_SID_NVENC, - .regs = { - .override = 0x0e0, - .security = 0x0e4, - }, - }, { - .name = "satar", - .sid = TEGRA186_SID_SATA, - .regs = { - .override = 0x0f8, - .security = 0x0fc, - }, - }, { - .name = "mpcorer", - .sid = TEGRA186_SID_PASSTHROUGH, - .regs = { - .override = 0x138, - .security = 0x13c, - }, - }, { - .name = "nvencswr", - .sid = TEGRA186_SID_NVENC, - .regs = { - .override = 0x158, - .security = 0x15c, - }, - }, { - .name = "afiw", - .sid = TEGRA186_SID_AFI, - .regs = { - .override = 0x188, - .security = 0x18c, - }, - }, { - .name = "hdaw", - .sid = TEGRA186_SID_HDA, - .regs = { - .override = 0x1a8, - .security = 0x1ac, - }, - }, { - .name = "mpcorew", - .sid = TEGRA186_SID_PASSTHROUGH, - .regs = { - .override = 0x1c8, - .security = 0x1cc, - }, - }, { - .name = "sataw", - .sid = TEGRA186_SID_SATA, - .regs = { - .override = 0x1e8, - .security = 0x1ec, - }, - }, { - .name = "ispra", - .sid = TEGRA186_SID_ISP, - .regs = { - .override = 0x220, - .security = 0x224, - }, - }, { - .name = "ispwa", - .sid = TEGRA186_SID_ISP, - .regs = { - .override = 0x230, - .security = 0x234, - }, - }, { - .name = "ispwb", - .sid = TEGRA186_SID_ISP, - .regs = { - .override = 0x238, - .security = 0x23c, - }, - }, { - .name = "xusb_hostr", - .sid = TEGRA186_SID_XUSB_HOST, - .regs = { - .override = 0x250, - .security = 0x254, - }, - }, { - .name = "xusb_hostw", - .sid = TEGRA186_SID_XUSB_HOST, - .regs = { - .override = 0x258, - .security = 0x25c, - }, - }, { - .name = "xusb_devr", - .sid = TEGRA186_SID_XUSB_DEV, - .regs = { - .override = 0x260, - .security = 0x264, - }, - }, { - .name = "xusb_devw", - .sid = TEGRA186_SID_XUSB_DEV, - .regs = { - .override = 0x268, - .security = 0x26c, - }, - }, { - .name = "tsecsrd", - .sid = TEGRA186_SID_TSEC, - .regs = { - .override = 0x2a0, - .security = 0x2a4, - }, - }, { - .name = "tsecswr", - .sid = TEGRA186_SID_TSEC, - .regs = { - .override = 0x2a8, - .security = 0x2ac, - }, - }, { - .name = "gpusrd", - .sid = TEGRA186_SID_GPU, - .regs = { - .override = 0x2c0, - .security = 0x2c4, - }, - }, { - .name = "gpuswr", - .sid = TEGRA186_SID_GPU, - .regs = { - .override = 0x2c8, - .security = 0x2cc, - }, - }, { - .name = "sdmmcra", - .sid = TEGRA186_SID_SDMMC1, - .regs = { - .override = 0x300, - .security = 0x304, - }, - }, { - .name = "sdmmcraa", - .sid = TEGRA186_SID_SDMMC2, - .regs = { - .override = 0x308, - .security = 0x30c, - }, - }, { - .name = "sdmmcr", - .sid = TEGRA186_SID_SDMMC3, - .regs = { - .override = 0x310, - .security = 0x314, - }, - }, { - .name = "sdmmcrab", - .sid = TEGRA186_SID_SDMMC4, - .regs = { - .override = 0x318, - .security = 0x31c, - }, - }, { - .name = "sdmmcwa", - .sid = TEGRA186_SID_SDMMC1, - .regs = { - .override = 0x320, - .security = 0x324, - }, - }, { - .name = "sdmmcwaa", - .sid = TEGRA186_SID_SDMMC2, - .regs = { - .override = 0x328, - .security = 0x32c, - }, - }, { - .name = "sdmmcw", - .sid = TEGRA186_SID_SDMMC3, - .regs = { - .override = 0x330, - .security = 0x334, - }, - }, { - .name = "sdmmcwab", - .sid = TEGRA186_SID_SDMMC4, - .regs = { - .override = 0x338, - .security = 0x33c, - }, - }, { - .name = "vicsrd", - .sid = TEGRA186_SID_VIC, - .regs = { - .override = 0x360, - .security = 0x364, - }, - }, { - .name = "vicswr", - .sid = TEGRA186_SID_VIC, - .regs = { - .override = 0x368, - .security = 0x36c, - }, - }, { - .name = "viw", - .sid = TEGRA186_SID_VI, - .regs = { - .override = 0x390, - .security = 0x394, - }, - }, { - .name = "nvdecsrd", - .sid = TEGRA186_SID_NVDEC, - .regs = { - .override = 0x3c0, - .security = 0x3c4, - }, - }, { - .name = "nvdecswr", - .sid = TEGRA186_SID_NVDEC, - .regs = { - .override = 0x3c8, - .security = 0x3cc, - }, - }, { - .name = "aper", - .sid = TEGRA186_SID_APE, - .regs = { - .override = 0x3d0, - .security = 0x3d4, - }, - }, { - .name = "apew", - .sid = TEGRA186_SID_APE, - .regs = { - .override = 0x3d8, - .security = 0x3dc, - }, - }, { - .name = "nvjpgsrd", - .sid = TEGRA186_SID_NVJPG, - .regs = { - .override = 0x3f0, - .security = 0x3f4, - }, - }, { - .name = "nvjpgswr", - .sid = TEGRA186_SID_NVJPG, - .regs = { - .override = 0x3f8, - .security = 0x3fc, - }, - }, { - .name = "sesrd", - .sid = TEGRA186_SID_SE, - .regs = { - .override = 0x400, - .security = 0x404, - }, - }, { - .name = "seswr", - .sid = TEGRA186_SID_SE, - .regs = { - .override = 0x408, - .security = 0x40c, - }, - }, { - .name = "etrr", - .sid = TEGRA186_SID_ETR, - .regs = { - .override = 0x420, - .security = 0x424, - }, - }, { - .name = "etrw", - .sid = TEGRA186_SID_ETR, - .regs = { - .override = 0x428, - .security = 0x42c, - }, - }, { - .name = "tsecsrdb", - .sid = TEGRA186_SID_TSECB, - .regs = { - .override = 0x430, - .security = 0x434, - }, - }, { - .name = "tsecswrb", - .sid = TEGRA186_SID_TSECB, - .regs = { - .override = 0x438, - .security = 0x43c, - }, - }, { - .name = "gpusrd2", - .sid = TEGRA186_SID_GPU, - .regs = { - .override = 0x440, - .security = 0x444, - }, - }, { - .name = "gpuswr2", - .sid = TEGRA186_SID_GPU, - .regs = { - .override = 0x448, - .security = 0x44c, - }, - }, { - .name = "axisr", - .sid = TEGRA186_SID_GPCDMA_0, - .regs = { - .override = 0x460, - .security = 0x464, - }, - }, { - .name = "axisw", - .sid = TEGRA186_SID_GPCDMA_0, - .regs = { - .override = 0x468, - .security = 0x46c, - }, - }, { - .name = "eqosr", - .sid = TEGRA186_SID_EQOS, - .regs = { - .override = 0x470, - .security = 0x474, - }, - }, { - .name = "eqosw", - .sid = TEGRA186_SID_EQOS, - .regs = { - .override = 0x478, - .security = 0x47c, - }, - }, { - .name = "ufshcr", - .sid = TEGRA186_SID_UFSHC, - .regs = { - .override = 0x480, - .security = 0x484, - }, - }, { - .name = "ufshcw", - .sid = TEGRA186_SID_UFSHC, - .regs = { - .override = 0x488, - .security = 0x48c, - }, - }, { - .name = "nvdisplayr", - .sid = TEGRA186_SID_NVDISPLAY, - .regs = { - .override = 0x490, - .security = 0x494, - }, - }, { - .name = "bpmpr", - .sid = TEGRA186_SID_BPMP, - .regs = { - .override = 0x498, - .security = 0x49c, - }, - }, { - .name = "bpmpw", - .sid = TEGRA186_SID_BPMP, - .regs = { - .override = 0x4a0, - .security = 0x4a4, - }, - }, { - .name = "bpmpdmar", - .sid = TEGRA186_SID_BPMP, - .regs = { - .override = 0x4a8, - .security = 0x4ac, - }, - }, { - .name = "bpmpdmaw", - .sid = TEGRA186_SID_BPMP, - .regs = { - .override = 0x4b0, - .security = 0x4b4, - }, - }, { - .name = "aonr", - .sid = TEGRA186_SID_AON, - .regs = { - .override = 0x4b8, - .security = 0x4bc, - }, - }, { - .name = "aonw", - .sid = TEGRA186_SID_AON, - .regs = { - .override = 0x4c0, - .security = 0x4c4, - }, - }, { - .name = "aondmar", - .sid = TEGRA186_SID_AON, - .regs = { - .override = 0x4c8, - .security = 0x4cc, - }, - }, { - .name = "aondmaw", - .sid = TEGRA186_SID_AON, - .regs = { - .override = 0x4d0, - .security = 0x4d4, - }, - }, { - .name = "scer", - .sid = TEGRA186_SID_SCE, - .regs = { - .override = 0x4d8, - .security = 0x4dc, - }, - }, { - .name = "scew", - .sid = TEGRA186_SID_SCE, - .regs = { - .override = 0x4e0, - .security = 0x4e4, - }, - }, { - .name = "scedmar", - .sid = TEGRA186_SID_SCE, - .regs = { - .override = 0x4e8, - .security = 0x4ec, - }, - }, { - .name = "scedmaw", - .sid = TEGRA186_SID_SCE, - .regs = { - .override = 0x4f0, - .security = 0x4f4, - }, - }, { - .name = "apedmar", - .sid = TEGRA186_SID_APE, - .regs = { - .override = 0x4f8, - .security = 0x4fc, - }, - }, { - .name = "apedmaw", - .sid = TEGRA186_SID_APE, - .regs = { - .override = 0x500, - .security = 0x504, - }, - }, { - .name = "nvdisplayr1", - .sid = TEGRA186_SID_NVDISPLAY, - .regs = { - .override = 0x508, - .security = 0x50c, - }, - }, { - .name = "vicsrd1", - .sid = TEGRA186_SID_VIC, - .regs = { - .override = 0x510, - .security = 0x514, - }, - }, { - .name = "nvdecsrd1", - .sid = TEGRA186_SID_NVDEC, - .regs = { - .override = 0x518, - .security = 0x51c, - }, - }, -}; - -static const struct tegra186_mc_soc tegra186_mc_soc = { - .num_clients = ARRAY_SIZE(tegra186_mc_clients), - .clients = tegra186_mc_clients, -}; -#endif - -#if defined(CONFIG_ARCH_TEGRA_194_SOC) -static const struct tegra186_mc_client tegra194_mc_clients[] = { - { - .name = "ptcr", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x000, - .security = 0x004, - }, - }, { - .name = "miu7r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x008, - .security = 0x00c, - }, - }, { - .name = "miu7w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x010, - .security = 0x014, - }, - }, { - .name = "hdar", - .sid = TEGRA194_SID_HDA, - .regs = { - .override = 0x0a8, - .security = 0x0ac, - }, - }, { - .name = "host1xdmar", - .sid = TEGRA194_SID_HOST1X, - .regs = { - .override = 0x0b0, - .security = 0x0b4, - }, - }, { - .name = "nvencsrd", - .sid = TEGRA194_SID_NVENC, - .regs = { - .override = 0x0e0, - .security = 0x0e4, - }, - }, { - .name = "satar", - .sid = TEGRA194_SID_SATA, - .regs = { - .override = 0x0f8, - .security = 0x0fc, - }, - }, { - .name = "mpcorer", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x138, - .security = 0x13c, - }, - }, { - .name = "nvencswr", - .sid = TEGRA194_SID_NVENC, - .regs = { - .override = 0x158, - .security = 0x15c, - }, - }, { - .name = "hdaw", - .sid = TEGRA194_SID_HDA, - .regs = { - .override = 0x1a8, - .security = 0x1ac, - }, - }, { - .name = "mpcorew", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x1c8, - .security = 0x1cc, - }, - }, { - .name = "sataw", - .sid = TEGRA194_SID_SATA, - .regs = { - .override = 0x1e8, - .security = 0x1ec, - }, - }, { - .name = "ispra", - .sid = TEGRA194_SID_ISP, - .regs = { - .override = 0x220, - .security = 0x224, - }, - }, { - .name = "ispfalr", - .sid = TEGRA194_SID_ISP_FALCON, - .regs = { - .override = 0x228, - .security = 0x22c, - }, - }, { - .name = "ispwa", - .sid = TEGRA194_SID_ISP, - .regs = { - .override = 0x230, - .security = 0x234, - }, - }, { - .name = "ispwb", - .sid = TEGRA194_SID_ISP, - .regs = { - .override = 0x238, - .security = 0x23c, - }, - }, { - .name = "xusb_hostr", - .sid = TEGRA194_SID_XUSB_HOST, - .regs = { - .override = 0x250, - .security = 0x254, - }, - }, { - .name = "xusb_hostw", - .sid = TEGRA194_SID_XUSB_HOST, - .regs = { - .override = 0x258, - .security = 0x25c, - }, - }, { - .name = "xusb_devr", - .sid = TEGRA194_SID_XUSB_DEV, - .regs = { - .override = 0x260, - .security = 0x264, - }, - }, { - .name = "xusb_devw", - .sid = TEGRA194_SID_XUSB_DEV, - .regs = { - .override = 0x268, - .security = 0x26c, - }, - }, { - .name = "sdmmcra", - .sid = TEGRA194_SID_SDMMC1, - .regs = { - .override = 0x300, - .security = 0x304, - }, - }, { - .name = "sdmmcr", - .sid = TEGRA194_SID_SDMMC3, - .regs = { - .override = 0x310, - .security = 0x314, - }, - }, { - .name = "sdmmcrab", - .sid = TEGRA194_SID_SDMMC4, - .regs = { - .override = 0x318, - .security = 0x31c, - }, - }, { - .name = "sdmmcwa", - .sid = TEGRA194_SID_SDMMC1, - .regs = { - .override = 0x320, - .security = 0x324, - }, - }, { - .name = "sdmmcw", - .sid = TEGRA194_SID_SDMMC3, - .regs = { - .override = 0x330, - .security = 0x334, - }, - }, { - .name = "sdmmcwab", - .sid = TEGRA194_SID_SDMMC4, - .regs = { - .override = 0x338, - .security = 0x33c, - }, - }, { - .name = "vicsrd", - .sid = TEGRA194_SID_VIC, - .regs = { - .override = 0x360, - .security = 0x364, - }, - }, { - .name = "vicswr", - .sid = TEGRA194_SID_VIC, - .regs = { - .override = 0x368, - .security = 0x36c, - }, - }, { - .name = "viw", - .sid = TEGRA194_SID_VI, - .regs = { - .override = 0x390, - .security = 0x394, - }, - }, { - .name = "nvdecsrd", - .sid = TEGRA194_SID_NVDEC, - .regs = { - .override = 0x3c0, - .security = 0x3c4, - }, - }, { - .name = "nvdecswr", - .sid = TEGRA194_SID_NVDEC, - .regs = { - .override = 0x3c8, - .security = 0x3cc, - }, - }, { - .name = "aper", - .sid = TEGRA194_SID_APE, - .regs = { - .override = 0x3c0, - .security = 0x3c4, - }, - }, { - .name = "apew", - .sid = TEGRA194_SID_APE, - .regs = { - .override = 0x3d0, - .security = 0x3d4, - }, - }, { - .name = "nvjpgsrd", - .sid = TEGRA194_SID_NVJPG, - .regs = { - .override = 0x3f0, - .security = 0x3f4, - }, - }, { - .name = "nvjpgswr", - .sid = TEGRA194_SID_NVJPG, - .regs = { - .override = 0x3f0, - .security = 0x3f4, - }, - }, { - .name = "axiapr", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x410, - .security = 0x414, - }, - }, { - .name = "axiapw", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x418, - .security = 0x41c, - }, - }, { - .name = "etrr", - .sid = TEGRA194_SID_ETR, - .regs = { - .override = 0x420, - .security = 0x424, - }, - }, { - .name = "etrw", - .sid = TEGRA194_SID_ETR, - .regs = { - .override = 0x428, - .security = 0x42c, - }, - }, { - .name = "axisr", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x460, - .security = 0x464, - }, - }, { - .name = "axisw", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x468, - .security = 0x46c, - }, - }, { - .name = "eqosr", - .sid = TEGRA194_SID_EQOS, - .regs = { - .override = 0x470, - .security = 0x474, - }, - }, { - .name = "eqosw", - .sid = TEGRA194_SID_EQOS, - .regs = { - .override = 0x478, - .security = 0x47c, - }, - }, { - .name = "ufshcr", - .sid = TEGRA194_SID_UFSHC, - .regs = { - .override = 0x480, - .security = 0x484, - }, - }, { - .name = "ufshcw", - .sid = TEGRA194_SID_UFSHC, - .regs = { - .override = 0x488, - .security = 0x48c, - }, - }, { - .name = "nvdisplayr", - .sid = TEGRA194_SID_NVDISPLAY, - .regs = { - .override = 0x490, - .security = 0x494, - }, - }, { - .name = "bpmpr", - .sid = TEGRA194_SID_BPMP, - .regs = { - .override = 0x498, - .security = 0x49c, - }, - }, { - .name = "bpmpw", - .sid = TEGRA194_SID_BPMP, - .regs = { - .override = 0x4a0, - .security = 0x4a4, - }, - }, { - .name = "bpmpdmar", - .sid = TEGRA194_SID_BPMP, - .regs = { - .override = 0x4a8, - .security = 0x4ac, - }, - }, { - .name = "bpmpdmaw", - .sid = TEGRA194_SID_BPMP, - .regs = { - .override = 0x4b0, - .security = 0x4b4, - }, - }, { - .name = "aonr", - .sid = TEGRA194_SID_AON, - .regs = { - .override = 0x4b8, - .security = 0x4bc, - }, - }, { - .name = "aonw", - .sid = TEGRA194_SID_AON, - .regs = { - .override = 0x4c0, - .security = 0x4c4, - }, - }, { - .name = "aondmar", - .sid = TEGRA194_SID_AON, - .regs = { - .override = 0x4c8, - .security = 0x4cc, - }, - }, { - .name = "aondmaw", - .sid = TEGRA194_SID_AON, - .regs = { - .override = 0x4d0, - .security = 0x4d4, - }, - }, { - .name = "scer", - .sid = TEGRA194_SID_SCE, - .regs = { - .override = 0x4d8, - .security = 0x4dc, - }, - }, { - .name = "scew", - .sid = TEGRA194_SID_SCE, - .regs = { - .override = 0x4e0, - .security = 0x4e4, - }, - }, { - .name = "scedmar", - .sid = TEGRA194_SID_SCE, - .regs = { - .override = 0x4e8, - .security = 0x4ec, - }, - }, { - .name = "scedmaw", - .sid = TEGRA194_SID_SCE, - .regs = { - .override = 0x4f0, - .security = 0x4f4, - }, - }, { - .name = "apedmar", - .sid = TEGRA194_SID_APE, - .regs = { - .override = 0x4f8, - .security = 0x4fc, - }, - }, { - .name = "apedmaw", - .sid = TEGRA194_SID_APE, - .regs = { - .override = 0x500, - .security = 0x504, - }, - }, { - .name = "nvdisplayr1", - .sid = TEGRA194_SID_NVDISPLAY, - .regs = { - .override = 0x508, - .security = 0x50c, - }, - }, { - .name = "vicsrd1", - .sid = TEGRA194_SID_VIC, - .regs = { - .override = 0x510, - .security = 0x514, - }, - }, { - .name = "nvdecsrd1", - .sid = TEGRA194_SID_NVDEC, - .regs = { - .override = 0x518, - .security = 0x51c, - }, - }, { - .name = "miu0r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x530, - .security = 0x534, - }, - }, { - .name = "miu0w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x538, - .security = 0x53c, - }, - }, { - .name = "miu1r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x540, - .security = 0x544, - }, - }, { - .name = "miu1w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x548, - .security = 0x54c, - }, - }, { - .name = "miu2r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x570, - .security = 0x574, - }, - }, { - .name = "miu2w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x578, - .security = 0x57c, - }, - }, { - .name = "miu3r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x580, - .security = 0x584, - }, - }, { - .name = "miu3w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x588, - .security = 0x58c, - }, - }, { - .name = "miu4r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x590, - .security = 0x594, - }, - }, { - .name = "miu4w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x598, - .security = 0x59c, - }, - }, { - .name = "dpmur", - .sid = TEGRA194_SID_PASSTHROUGH, - .regs = { - .override = 0x598, - .security = 0x59c, - }, - }, { - .name = "vifalr", - .sid = TEGRA194_SID_VI_FALCON, - .regs = { - .override = 0x5e0, - .security = 0x5e4, - }, - }, { - .name = "vifalw", - .sid = TEGRA194_SID_VI_FALCON, - .regs = { - .override = 0x5e8, - .security = 0x5ec, - }, - }, { - .name = "dla0rda", - .sid = TEGRA194_SID_NVDLA0, - .regs = { - .override = 0x5f0, - .security = 0x5f4, - }, - }, { - .name = "dla0falrdb", - .sid = TEGRA194_SID_NVDLA0, - .regs = { - .override = 0x5f8, - .security = 0x5fc, - }, - }, { - .name = "dla0wra", - .sid = TEGRA194_SID_NVDLA0, - .regs = { - .override = 0x600, - .security = 0x604, - }, - }, { - .name = "dla0falwrb", - .sid = TEGRA194_SID_NVDLA0, - .regs = { - .override = 0x608, - .security = 0x60c, - }, - }, { - .name = "dla1rda", - .sid = TEGRA194_SID_NVDLA1, - .regs = { - .override = 0x610, - .security = 0x614, - }, - }, { - .name = "dla1falrdb", - .sid = TEGRA194_SID_NVDLA1, - .regs = { - .override = 0x618, - .security = 0x61c, - }, - }, { - .name = "dla1wra", - .sid = TEGRA194_SID_NVDLA1, - .regs = { - .override = 0x620, - .security = 0x624, - }, - }, { - .name = "dla1falwrb", - .sid = TEGRA194_SID_NVDLA1, - .regs = { - .override = 0x628, - .security = 0x62c, - }, - }, { - .name = "pva0rda", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x630, - .security = 0x634, - }, - }, { - .name = "pva0rdb", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x638, - .security = 0x63c, - }, - }, { - .name = "pva0rdc", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x640, - .security = 0x644, - }, - }, { - .name = "pva0wra", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x648, - .security = 0x64c, - }, - }, { - .name = "pva0wrb", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x650, - .security = 0x654, - }, - }, { - .name = "pva0wrc", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x658, - .security = 0x65c, - }, - }, { - .name = "pva1rda", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x660, - .security = 0x664, - }, - }, { - .name = "pva1rdb", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x668, - .security = 0x66c, - }, - }, { - .name = "pva1rdc", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x670, - .security = 0x674, - }, - }, { - .name = "pva1wra", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x678, - .security = 0x67c, - }, - }, { - .name = "pva1wrb", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x680, - .security = 0x684, - }, - }, { - .name = "pva1wrc", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x688, - .security = 0x68c, - }, - }, { - .name = "rcer", - .sid = TEGRA194_SID_RCE, - .regs = { - .override = 0x690, - .security = 0x694, - }, - }, { - .name = "rcew", - .sid = TEGRA194_SID_RCE, - .regs = { - .override = 0x698, - .security = 0x69c, - }, - }, { - .name = "rcedmar", - .sid = TEGRA194_SID_RCE, - .regs = { - .override = 0x6a0, - .security = 0x6a4, - }, - }, { - .name = "rcedmaw", - .sid = TEGRA194_SID_RCE, - .regs = { - .override = 0x6a8, - .security = 0x6ac, - }, - }, { - .name = "nvenc1srd", - .sid = TEGRA194_SID_NVENC1, - .regs = { - .override = 0x6b0, - .security = 0x6b4, - }, - }, { - .name = "nvenc1swr", - .sid = TEGRA194_SID_NVENC1, - .regs = { - .override = 0x6b8, - .security = 0x6bc, - }, - }, { - .name = "pcie0r", - .sid = TEGRA194_SID_PCIE0, - .regs = { - .override = 0x6c0, - .security = 0x6c4, - }, - }, { - .name = "pcie0w", - .sid = TEGRA194_SID_PCIE0, - .regs = { - .override = 0x6c8, - .security = 0x6cc, - }, - }, { - .name = "pcie1r", - .sid = TEGRA194_SID_PCIE1, - .regs = { - .override = 0x6d0, - .security = 0x6d4, - }, - }, { - .name = "pcie1w", - .sid = TEGRA194_SID_PCIE1, - .regs = { - .override = 0x6d8, - .security = 0x6dc, - }, - }, { - .name = "pcie2ar", - .sid = TEGRA194_SID_PCIE2, - .regs = { - .override = 0x6e0, - .security = 0x6e4, - }, - }, { - .name = "pcie2aw", - .sid = TEGRA194_SID_PCIE2, - .regs = { - .override = 0x6e8, - .security = 0x6ec, - }, - }, { - .name = "pcie3r", - .sid = TEGRA194_SID_PCIE3, - .regs = { - .override = 0x6f0, - .security = 0x6f4, - }, - }, { - .name = "pcie3w", - .sid = TEGRA194_SID_PCIE3, - .regs = { - .override = 0x6f8, - .security = 0x6fc, - }, - }, { - .name = "pcie4r", - .sid = TEGRA194_SID_PCIE4, - .regs = { - .override = 0x700, - .security = 0x704, - }, - }, { - .name = "pcie4w", - .sid = TEGRA194_SID_PCIE4, - .regs = { - .override = 0x708, - .security = 0x70c, - }, - }, { - .name = "pcie5r", - .sid = TEGRA194_SID_PCIE5, - .regs = { - .override = 0x710, - .security = 0x714, - }, - }, { - .name = "pcie5w", - .sid = TEGRA194_SID_PCIE5, - .regs = { - .override = 0x718, - .security = 0x71c, - }, - }, { - .name = "ispfalw", - .sid = TEGRA194_SID_ISP_FALCON, - .regs = { - .override = 0x720, - .security = 0x724, - }, - }, { - .name = "dla0rda1", - .sid = TEGRA194_SID_NVDLA0, - .regs = { - .override = 0x748, - .security = 0x74c, - }, - }, { - .name = "dla1rda1", - .sid = TEGRA194_SID_NVDLA1, - .regs = { - .override = 0x750, - .security = 0x754, - }, - }, { - .name = "pva0rda1", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x758, - .security = 0x75c, - }, - }, { - .name = "pva0rdb1", - .sid = TEGRA194_SID_PVA0, - .regs = { - .override = 0x760, - .security = 0x764, - }, - }, { - .name = "pva1rda1", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x768, - .security = 0x76c, - }, - }, { - .name = "pva1rdb1", - .sid = TEGRA194_SID_PVA1, - .regs = { - .override = 0x770, - .security = 0x774, - }, - }, { - .name = "pcie5r1", - .sid = TEGRA194_SID_PCIE5, - .regs = { - .override = 0x778, - .security = 0x77c, - }, - }, { - .name = "nvencsrd1", - .sid = TEGRA194_SID_NVENC, - .regs = { - .override = 0x780, - .security = 0x784, - }, - }, { - .name = "nvenc1srd1", - .sid = TEGRA194_SID_NVENC1, - .regs = { - .override = 0x788, - .security = 0x78c, - }, - }, { - .name = "ispra1", - .sid = TEGRA194_SID_ISP, - .regs = { - .override = 0x790, - .security = 0x794, - }, - }, { - .name = "pcie0r1", - .sid = TEGRA194_SID_PCIE0, - .regs = { - .override = 0x798, - .security = 0x79c, - }, - }, { - .name = "nvdec1srd", - .sid = TEGRA194_SID_NVDEC1, - .regs = { - .override = 0x7c8, - .security = 0x7cc, - }, - }, { - .name = "nvdec1srd1", - .sid = TEGRA194_SID_NVDEC1, - .regs = { - .override = 0x7d0, - .security = 0x7d4, - }, - }, { - .name = "nvdec1swr", - .sid = TEGRA194_SID_NVDEC1, - .regs = { - .override = 0x7d8, - .security = 0x7dc, - }, - }, { - .name = "miu5r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x7e0, - .security = 0x7e4, - }, - }, { - .name = "miu5w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x7e8, - .security = 0x7ec, - }, - }, { - .name = "miu6r", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x7f0, - .security = 0x7f4, - }, - }, { - .name = "miu6w", - .sid = TEGRA194_SID_MIU, - .regs = { - .override = 0x7f8, - .security = 0x7fc, - }, - }, -}; - -static const struct tegra186_mc_soc tegra194_mc_soc = { - .num_clients = ARRAY_SIZE(tegra194_mc_clients), - .clients = tegra194_mc_clients, -}; -#endif - -static int tegra186_mc_probe(struct platform_device *pdev) +static int tegra186_mc_probe(struct tegra_mc *mc) { - struct tegra186_mc *mc; - struct resource *res; int err; - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); - if (!mc) - return -ENOMEM; - - mc->soc = of_device_get_match_data(&pdev->dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mc->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mc->regs)) - return PTR_ERR(mc->regs); - - mc->dev = &pdev->dev; - - err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev); if (err < 0) return err; - platform_set_drvdata(pdev, mc); tegra186_mc_program_sid(mc); return 0; } -static int tegra186_mc_remove(struct platform_device *pdev) +static void tegra186_mc_remove(struct tegra_mc *mc) { - struct tegra186_mc *mc = platform_get_drvdata(pdev); - of_platform_depopulate(mc->dev); - - return 0; } -static const struct of_device_id tegra186_mc_of_match[] = { -#if defined(CONFIG_ARCH_TEGRA_186_SOC) - { .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc }, -#endif -#if defined(CONFIG_ARCH_TEGRA_194_SOC) - { .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc }, -#endif - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, tegra186_mc_of_match); - -static int __maybe_unused tegra186_mc_suspend(struct device *dev) +static int tegra186_mc_resume(struct tegra_mc *mc) { - return 0; -} - -static int __maybe_unused tegra186_mc_resume(struct device *dev) -{ - struct tegra186_mc *mc = dev_get_drvdata(dev); - tegra186_mc_program_sid(mc); return 0; } -static const struct dev_pm_ops tegra186_mc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tegra186_mc_suspend, tegra186_mc_resume) -}; +static void tegra186_mc_client_sid_override(struct tegra_mc *mc, + const struct tegra_mc_client *client, + unsigned int sid) +{ + u32 value, old; -static struct platform_driver tegra186_mc_driver = { - .driver = { - .name = "tegra186-mc", - .of_match_table = tegra186_mc_of_match, - .pm = &tegra186_mc_pm_ops, - .suppress_bind_attrs = true, - }, + value = readl(mc->regs + client->regs.sid.security); + if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) { + /* + * If the secure firmware has locked this down the override + * for this memory client, there's nothing we can do here. + */ + if (value & MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED) + return; + + /* + * Otherwise, try to set the override itself. Typically the + * secure firmware will never have set this configuration. + * Instead, it will either have disabled write access to + * this field, or it will already have set an explicit + * override itself. + */ + WARN_ON((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0); + + value |= MC_SID_STREAMID_SECURITY_OVERRIDE; + writel(value, mc->regs + client->regs.sid.security); + } + + value = readl(mc->regs + client->regs.sid.override); + old = value & MC_SID_STREAMID_OVERRIDE_MASK; + + if (old != sid) { + dev_dbg(mc->dev, "overriding SID %x for %s with %x\n", old, + client->name, sid); + writel(sid, mc->regs + client->regs.sid.override); + } +} + +static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct of_phandle_args args; + unsigned int i, index = 0; + + while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells", + index, &args)) { + if (args.np == mc->dev->of_node && args.args_count != 0) { + for (i = 0; i < mc->soc->num_clients; i++) { + const struct tegra_mc_client *client = &mc->soc->clients[i]; + + if (client->id == args.args[0]) { + u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK; + + tegra186_mc_client_sid_override(mc, client, sid); + } + } + } + + index++; + } +#endif + + 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, }; -module_platform_driver(tegra186_mc_driver); -MODULE_AUTHOR("Thierry Reding "); -MODULE_DESCRIPTION("NVIDIA Tegra186 Memory Controller driver"); -MODULE_LICENSE("GPL v2"); +#if defined(CONFIG_ARCH_TEGRA_186_SOC) +static const struct tegra_mc_client tegra186_mc_clients[] = { + { + .id = TEGRA186_MEMORY_CLIENT_PTCR, + .name = "ptcr", + .sid = TEGRA186_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x000, + .security = 0x004, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AFIR, + .name = "afir", + .sid = TEGRA186_SID_AFI, + .regs = { + .sid = { + .override = 0x070, + .security = 0x074, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_HDAR, + .name = "hdar", + .sid = TEGRA186_SID_HDA, + .regs = { + .sid = { + .override = 0x0a8, + .security = 0x0ac, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_HOST1XDMAR, + .name = "host1xdmar", + .sid = TEGRA186_SID_HOST1X, + .regs = { + .sid = { + .override = 0x0b0, + .security = 0x0b4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVENCSRD, + .name = "nvencsrd", + .sid = TEGRA186_SID_NVENC, + .regs = { + .sid = { + .override = 0x0e0, + .security = 0x0e4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SATAR, + .name = "satar", + .sid = TEGRA186_SID_SATA, + .regs = { + .sid = { + .override = 0x0f8, + .security = 0x0fc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_MPCORER, + .name = "mpcorer", + .sid = TEGRA186_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x138, + .security = 0x13c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVENCSWR, + .name = "nvencswr", + .sid = TEGRA186_SID_NVENC, + .regs = { + .sid = { + .override = 0x158, + .security = 0x15c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AFIW, + .name = "afiw", + .sid = TEGRA186_SID_AFI, + .regs = { + .sid = { + .override = 0x188, + .security = 0x18c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_HDAW, + .name = "hdaw", + .sid = TEGRA186_SID_HDA, + .regs = { + .sid = { + .override = 0x1a8, + .security = 0x1ac, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_MPCOREW, + .name = "mpcorew", + .sid = TEGRA186_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x1c8, + .security = 0x1cc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SATAW, + .name = "sataw", + .sid = TEGRA186_SID_SATA, + .regs = { + .sid = { + .override = 0x1e8, + .security = 0x1ec, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_ISPRA, + .name = "ispra", + .sid = TEGRA186_SID_ISP, + .regs = { + .sid = { + .override = 0x220, + .security = 0x224, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_ISPWA, + .name = "ispwa", + .sid = TEGRA186_SID_ISP, + .regs = { + .sid = { + .override = 0x230, + .security = 0x234, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_ISPWB, + .name = "ispwb", + .sid = TEGRA186_SID_ISP, + .regs = { + .sid = { + .override = 0x238, + .security = 0x23c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_XUSB_HOSTR, + .name = "xusb_hostr", + .sid = TEGRA186_SID_XUSB_HOST, + .regs = { + .sid = { + .override = 0x250, + .security = 0x254, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_XUSB_HOSTW, + .name = "xusb_hostw", + .sid = TEGRA186_SID_XUSB_HOST, + .regs = { + .sid = { + .override = 0x258, + .security = 0x25c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_XUSB_DEVR, + .name = "xusb_devr", + .sid = TEGRA186_SID_XUSB_DEV, + .regs = { + .sid = { + .override = 0x260, + .security = 0x264, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_XUSB_DEVW, + .name = "xusb_devw", + .sid = TEGRA186_SID_XUSB_DEV, + .regs = { + .sid = { + .override = 0x268, + .security = 0x26c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_TSECSRD, + .name = "tsecsrd", + .sid = TEGRA186_SID_TSEC, + .regs = { + .sid = { + .override = 0x2a0, + .security = 0x2a4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_TSECSWR, + .name = "tsecswr", + .sid = TEGRA186_SID_TSEC, + .regs = { + .sid = { + .override = 0x2a8, + .security = 0x2ac, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_GPUSRD, + .name = "gpusrd", + .sid = TEGRA186_SID_GPU, + .regs = { + .sid = { + .override = 0x2c0, + .security = 0x2c4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_GPUSWR, + .name = "gpuswr", + .sid = TEGRA186_SID_GPU, + .regs = { + .sid = { + .override = 0x2c8, + .security = 0x2cc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCRA, + .name = "sdmmcra", + .sid = TEGRA186_SID_SDMMC1, + .regs = { + .sid = { + .override = 0x300, + .security = 0x304, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCRAA, + .name = "sdmmcraa", + .sid = TEGRA186_SID_SDMMC2, + .regs = { + .sid = { + .override = 0x308, + .security = 0x30c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCR, + .name = "sdmmcr", + .sid = TEGRA186_SID_SDMMC3, + .regs = { + .sid = { + .override = 0x310, + .security = 0x314, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCRAB, + .name = "sdmmcrab", + .sid = TEGRA186_SID_SDMMC4, + .regs = { + .sid = { + .override = 0x318, + .security = 0x31c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCWA, + .name = "sdmmcwa", + .sid = TEGRA186_SID_SDMMC1, + .regs = { + .sid = { + .override = 0x320, + .security = 0x324, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCWAA, + .name = "sdmmcwaa", + .sid = TEGRA186_SID_SDMMC2, + .regs = { + .sid = { + .override = 0x328, + .security = 0x32c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCW, + .name = "sdmmcw", + .sid = TEGRA186_SID_SDMMC3, + .regs = { + .sid = { + .override = 0x330, + .security = 0x334, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SDMMCWAB, + .name = "sdmmcwab", + .sid = TEGRA186_SID_SDMMC4, + .regs = { + .sid = { + .override = 0x338, + .security = 0x33c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_VICSRD, + .name = "vicsrd", + .sid = TEGRA186_SID_VIC, + .regs = { + .sid = { + .override = 0x360, + .security = 0x364, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_VICSWR, + .name = "vicswr", + .sid = TEGRA186_SID_VIC, + .regs = { + .sid = { + .override = 0x368, + .security = 0x36c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_VIW, + .name = "viw", + .sid = TEGRA186_SID_VI, + .regs = { + .sid = { + .override = 0x390, + .security = 0x394, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVDECSRD, + .name = "nvdecsrd", + .sid = TEGRA186_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c0, + .security = 0x3c4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVDECSWR, + .name = "nvdecswr", + .sid = TEGRA186_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c8, + .security = 0x3cc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_APER, + .name = "aper", + .sid = TEGRA186_SID_APE, + .regs = { + .sid = { + .override = 0x3d0, + .security = 0x3d4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_APEW, + .name = "apew", + .sid = TEGRA186_SID_APE, + .regs = { + .sid = { + .override = 0x3d8, + .security = 0x3dc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVJPGSRD, + .name = "nvjpgsrd", + .sid = TEGRA186_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f0, + .security = 0x3f4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVJPGSWR, + .name = "nvjpgswr", + .sid = TEGRA186_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f8, + .security = 0x3fc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SESRD, + .name = "sesrd", + .sid = TEGRA186_SID_SE, + .regs = { + .sid = { + .override = 0x400, + .security = 0x404, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SESWR, + .name = "seswr", + .sid = TEGRA186_SID_SE, + .regs = { + .sid = { + .override = 0x408, + .security = 0x40c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_ETRR, + .name = "etrr", + .sid = TEGRA186_SID_ETR, + .regs = { + .sid = { + .override = 0x420, + .security = 0x424, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_ETRW, + .name = "etrw", + .sid = TEGRA186_SID_ETR, + .regs = { + .sid = { + .override = 0x428, + .security = 0x42c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_TSECSRDB, + .name = "tsecsrdb", + .sid = TEGRA186_SID_TSECB, + .regs = { + .sid = { + .override = 0x430, + .security = 0x434, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_TSECSWRB, + .name = "tsecswrb", + .sid = TEGRA186_SID_TSECB, + .regs = { + .sid = { + .override = 0x438, + .security = 0x43c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_GPUSRD2, + .name = "gpusrd2", + .sid = TEGRA186_SID_GPU, + .regs = { + .sid = { + .override = 0x440, + .security = 0x444, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_GPUSWR2, + .name = "gpuswr2", + .sid = TEGRA186_SID_GPU, + .regs = { + .sid = { + .override = 0x448, + .security = 0x44c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AXISR, + .name = "axisr", + .sid = TEGRA186_SID_GPCDMA_0, + .regs = { + .sid = { + .override = 0x460, + .security = 0x464, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AXISW, + .name = "axisw", + .sid = TEGRA186_SID_GPCDMA_0, + .regs = { + .sid = { + .override = 0x468, + .security = 0x46c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_EQOSR, + .name = "eqosr", + .sid = TEGRA186_SID_EQOS, + .regs = { + .sid = { + .override = 0x470, + .security = 0x474, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_EQOSW, + .name = "eqosw", + .sid = TEGRA186_SID_EQOS, + .regs = { + .sid = { + .override = 0x478, + .security = 0x47c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_UFSHCR, + .name = "ufshcr", + .sid = TEGRA186_SID_UFSHC, + .regs = { + .sid = { + .override = 0x480, + .security = 0x484, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_UFSHCW, + .name = "ufshcw", + .sid = TEGRA186_SID_UFSHC, + .regs = { + .sid = { + .override = 0x488, + .security = 0x48c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVDISPLAYR, + .name = "nvdisplayr", + .sid = TEGRA186_SID_NVDISPLAY, + .regs = { + .sid = { + .override = 0x490, + .security = 0x494, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_BPMPR, + .name = "bpmpr", + .sid = TEGRA186_SID_BPMP, + .regs = { + .sid = { + .override = 0x498, + .security = 0x49c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_BPMPW, + .name = "bpmpw", + .sid = TEGRA186_SID_BPMP, + .regs = { + .sid = { + .override = 0x4a0, + .security = 0x4a4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_BPMPDMAR, + .name = "bpmpdmar", + .sid = TEGRA186_SID_BPMP, + .regs = { + .sid = { + .override = 0x4a8, + .security = 0x4ac, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_BPMPDMAW, + .name = "bpmpdmaw", + .sid = TEGRA186_SID_BPMP, + .regs = { + .sid = { + .override = 0x4b0, + .security = 0x4b4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AONR, + .name = "aonr", + .sid = TEGRA186_SID_AON, + .regs = { + .sid = { + .override = 0x4b8, + .security = 0x4bc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AONW, + .name = "aonw", + .sid = TEGRA186_SID_AON, + .regs = { + .sid = { + .override = 0x4c0, + .security = 0x4c4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AONDMAR, + .name = "aondmar", + .sid = TEGRA186_SID_AON, + .regs = { + .sid = { + .override = 0x4c8, + .security = 0x4cc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_AONDMAW, + .name = "aondmaw", + .sid = TEGRA186_SID_AON, + .regs = { + .sid = { + .override = 0x4d0, + .security = 0x4d4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SCER, + .name = "scer", + .sid = TEGRA186_SID_SCE, + .regs = { + .sid = { + .override = 0x4d8, + .security = 0x4dc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SCEW, + .name = "scew", + .sid = TEGRA186_SID_SCE, + .regs = { + .sid = { + .override = 0x4e0, + .security = 0x4e4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SCEDMAR, + .name = "scedmar", + .sid = TEGRA186_SID_SCE, + .regs = { + .sid = { + .override = 0x4e8, + .security = 0x4ec, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_SCEDMAW, + .name = "scedmaw", + .sid = TEGRA186_SID_SCE, + .regs = { + .sid = { + .override = 0x4f0, + .security = 0x4f4, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_APEDMAR, + .name = "apedmar", + .sid = TEGRA186_SID_APE, + .regs = { + .sid = { + .override = 0x4f8, + .security = 0x4fc, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_APEDMAW, + .name = "apedmaw", + .sid = TEGRA186_SID_APE, + .regs = { + .sid = { + .override = 0x500, + .security = 0x504, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVDISPLAYR1, + .name = "nvdisplayr1", + .sid = TEGRA186_SID_NVDISPLAY, + .regs = { + .sid = { + .override = 0x508, + .security = 0x50c, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_VICSRD1, + .name = "vicsrd1", + .sid = TEGRA186_SID_VIC, + .regs = { + .sid = { + .override = 0x510, + .security = 0x514, + }, + }, + }, { + .id = TEGRA186_MEMORY_CLIENT_NVDECSRD1, + .name = "nvdecsrd1", + .sid = TEGRA186_SID_NVDEC, + .regs = { + .sid = { + .override = 0x518, + .security = 0x51c, + }, + }, + }, +}; + +const struct tegra_mc_soc tegra186_mc_soc = { + .num_clients = ARRAY_SIZE(tegra186_mc_clients), + .clients = tegra186_mc_clients, + .num_address_bits = 40, + .ops = &tegra186_mc_ops, +}; +#endif diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c new file mode 100644 index 000000000000..cab998b8bd5c --- /dev/null +++ b/drivers/memory/tegra/tegra194.c @@ -0,0 +1,1351 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved. + */ + +#include + +#include + +#include "mc.h" + +static const struct tegra_mc_client tegra194_mc_clients[] = { + { + .id = TEGRA194_MEMORY_CLIENT_PTCR, + .name = "ptcr", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x000, + .security = 0x004, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU7R, + .name = "miu7r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x008, + .security = 0x00c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU7W, + .name = "miu7w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x010, + .security = 0x014, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_HDAR, + .name = "hdar", + .sid = TEGRA194_SID_HDA, + .regs = { + .sid = { + .override = 0x0a8, + .security = 0x0ac, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_HOST1XDMAR, + .name = "host1xdmar", + .sid = TEGRA194_SID_HOST1X, + .regs = { + .sid = { + .override = 0x0b0, + .security = 0x0b4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENCSRD, + .name = "nvencsrd", + .sid = TEGRA194_SID_NVENC, + .regs = { + .sid = { + .override = 0x0e0, + .security = 0x0e4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SATAR, + .name = "satar", + .sid = TEGRA194_SID_SATA, + .regs = { + .sid = { + .override = 0x0f8, + .security = 0x0fc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MPCORER, + .name = "mpcorer", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x138, + .security = 0x13c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENCSWR, + .name = "nvencswr", + .sid = TEGRA194_SID_NVENC, + .regs = { + .sid = { + .override = 0x158, + .security = 0x15c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_HDAW, + .name = "hdaw", + .sid = TEGRA194_SID_HDA, + .regs = { + .sid = { + .override = 0x1a8, + .security = 0x1ac, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MPCOREW, + .name = "mpcorew", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x1c8, + .security = 0x1cc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SATAW, + .name = "sataw", + .sid = TEGRA194_SID_SATA, + .regs = { + .sid = { + .override = 0x1e8, + .security = 0x1ec, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPRA, + .name = "ispra", + .sid = TEGRA194_SID_ISP, + .regs = { + .sid = { + .override = 0x220, + .security = 0x224, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPFALR, + .name = "ispfalr", + .sid = TEGRA194_SID_ISP_FALCON, + .regs = { + .sid = { + .override = 0x228, + .security = 0x22c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPWA, + .name = "ispwa", + .sid = TEGRA194_SID_ISP, + .regs = { + .sid = { + .override = 0x230, + .security = 0x234, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPWB, + .name = "ispwb", + .sid = TEGRA194_SID_ISP, + .regs = { + .sid = { + .override = 0x238, + .security = 0x23c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_XUSB_HOSTR, + .name = "xusb_hostr", + .sid = TEGRA194_SID_XUSB_HOST, + .regs = { + .sid = { + .override = 0x250, + .security = 0x254, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_XUSB_HOSTW, + .name = "xusb_hostw", + .sid = TEGRA194_SID_XUSB_HOST, + .regs = { + .sid = { + .override = 0x258, + .security = 0x25c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_XUSB_DEVR, + .name = "xusb_devr", + .sid = TEGRA194_SID_XUSB_DEV, + .regs = { + .sid = { + .override = 0x260, + .security = 0x264, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_XUSB_DEVW, + .name = "xusb_devw", + .sid = TEGRA194_SID_XUSB_DEV, + .regs = { + .sid = { + .override = 0x268, + .security = 0x26c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCRA, + .name = "sdmmcra", + .sid = TEGRA194_SID_SDMMC1, + .regs = { + .sid = { + .override = 0x300, + .security = 0x304, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCR, + .name = "sdmmcr", + .sid = TEGRA194_SID_SDMMC3, + .regs = { + .sid = { + .override = 0x310, + .security = 0x314, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCRAB, + .name = "sdmmcrab", + .sid = TEGRA194_SID_SDMMC4, + .regs = { + .sid = { + .override = 0x318, + .security = 0x31c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCWA, + .name = "sdmmcwa", + .sid = TEGRA194_SID_SDMMC1, + .regs = { + .sid = { + .override = 0x320, + .security = 0x324, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCW, + .name = "sdmmcw", + .sid = TEGRA194_SID_SDMMC3, + .regs = { + .sid = { + .override = 0x330, + .security = 0x334, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SDMMCWAB, + .name = "sdmmcwab", + .sid = TEGRA194_SID_SDMMC4, + .regs = { + .sid = { + .override = 0x338, + .security = 0x33c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VICSRD, + .name = "vicsrd", + .sid = TEGRA194_SID_VIC, + .regs = { + .sid = { + .override = 0x360, + .security = 0x364, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VICSWR, + .name = "vicswr", + .sid = TEGRA194_SID_VIC, + .regs = { + .sid = { + .override = 0x368, + .security = 0x36c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VIW, + .name = "viw", + .sid = TEGRA194_SID_VI, + .regs = { + .sid = { + .override = 0x390, + .security = 0x394, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDECSRD, + .name = "nvdecsrd", + .sid = TEGRA194_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c0, + .security = 0x3c4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDECSWR, + .name = "nvdecswr", + .sid = TEGRA194_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c8, + .security = 0x3cc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_APER, + .name = "aper", + .sid = TEGRA194_SID_APE, + .regs = { + .sid = { + .override = 0x3c0, + .security = 0x3c4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_APEW, + .name = "apew", + .sid = TEGRA194_SID_APE, + .regs = { + .sid = { + .override = 0x3d0, + .security = 0x3d4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVJPGSRD, + .name = "nvjpgsrd", + .sid = TEGRA194_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f0, + .security = 0x3f4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVJPGSWR, + .name = "nvjpgswr", + .sid = TEGRA194_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f0, + .security = 0x3f4, + }, + }, + }, { + .name = "axiapr", + .id = TEGRA194_MEMORY_CLIENT_AXIAPR, + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x410, + .security = 0x414, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AXIAPW, + .name = "axiapw", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x418, + .security = 0x41c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ETRR, + .name = "etrr", + .sid = TEGRA194_SID_ETR, + .regs = { + .sid = { + .override = 0x420, + .security = 0x424, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ETRW, + .name = "etrw", + .sid = TEGRA194_SID_ETR, + .regs = { + .sid = { + .override = 0x428, + .security = 0x42c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AXISR, + .name = "axisr", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x460, + .security = 0x464, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AXISW, + .name = "axisw", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x468, + .security = 0x46c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_EQOSR, + .name = "eqosr", + .sid = TEGRA194_SID_EQOS, + .regs = { + .sid = { + .override = 0x470, + .security = 0x474, + }, + }, + }, { + .name = "eqosw", + .id = TEGRA194_MEMORY_CLIENT_EQOSW, + .sid = TEGRA194_SID_EQOS, + .regs = { + .sid = { + .override = 0x478, + .security = 0x47c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_UFSHCR, + .name = "ufshcr", + .sid = TEGRA194_SID_UFSHC, + .regs = { + .sid = { + .override = 0x480, + .security = 0x484, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_UFSHCW, + .name = "ufshcw", + .sid = TEGRA194_SID_UFSHC, + .regs = { + .sid = { + .override = 0x488, + .security = 0x48c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDISPLAYR, + .name = "nvdisplayr", + .sid = TEGRA194_SID_NVDISPLAY, + .regs = { + .sid = { + .override = 0x490, + .security = 0x494, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_BPMPR, + .name = "bpmpr", + .sid = TEGRA194_SID_BPMP, + .regs = { + .sid = { + .override = 0x498, + .security = 0x49c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_BPMPW, + .name = "bpmpw", + .sid = TEGRA194_SID_BPMP, + .regs = { + .sid = { + .override = 0x4a0, + .security = 0x4a4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_BPMPDMAR, + .name = "bpmpdmar", + .sid = TEGRA194_SID_BPMP, + .regs = { + .sid = { + .override = 0x4a8, + .security = 0x4ac, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_BPMPDMAW, + .name = "bpmpdmaw", + .sid = TEGRA194_SID_BPMP, + .regs = { + .sid = { + .override = 0x4b0, + .security = 0x4b4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AONR, + .name = "aonr", + .sid = TEGRA194_SID_AON, + .regs = { + .sid = { + .override = 0x4b8, + .security = 0x4bc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AONW, + .name = "aonw", + .sid = TEGRA194_SID_AON, + .regs = { + .sid = { + .override = 0x4c0, + .security = 0x4c4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AONDMAR, + .name = "aondmar", + .sid = TEGRA194_SID_AON, + .regs = { + .sid = { + .override = 0x4c8, + .security = 0x4cc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_AONDMAW, + .name = "aondmaw", + .sid = TEGRA194_SID_AON, + .regs = { + .sid = { + .override = 0x4d0, + .security = 0x4d4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SCER, + .name = "scer", + .sid = TEGRA194_SID_SCE, + .regs = { + .sid = { + .override = 0x4d8, + .security = 0x4dc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SCEW, + .name = "scew", + .sid = TEGRA194_SID_SCE, + .regs = { + .sid = { + .override = 0x4e0, + .security = 0x4e4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SCEDMAR, + .name = "scedmar", + .sid = TEGRA194_SID_SCE, + .regs = { + .sid = { + .override = 0x4e8, + .security = 0x4ec, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_SCEDMAW, + .name = "scedmaw", + .sid = TEGRA194_SID_SCE, + .regs = { + .sid = { + .override = 0x4f0, + .security = 0x4f4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_APEDMAR, + .name = "apedmar", + .sid = TEGRA194_SID_APE, + .regs = { + .sid = { + .override = 0x4f8, + .security = 0x4fc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_APEDMAW, + .name = "apedmaw", + .sid = TEGRA194_SID_APE, + .regs = { + .sid = { + .override = 0x500, + .security = 0x504, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDISPLAYR1, + .name = "nvdisplayr1", + .sid = TEGRA194_SID_NVDISPLAY, + .regs = { + .sid = { + .override = 0x508, + .security = 0x50c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VICSRD1, + .name = "vicsrd1", + .sid = TEGRA194_SID_VIC, + .regs = { + .sid = { + .override = 0x510, + .security = 0x514, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDECSRD1, + .name = "nvdecsrd1", + .sid = TEGRA194_SID_NVDEC, + .regs = { + .sid = { + .override = 0x518, + .security = 0x51c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU0R, + .name = "miu0r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x530, + .security = 0x534, + }, + }, + }, { + .name = "miu0w", + .id = TEGRA194_MEMORY_CLIENT_MIU0W, + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x538, + .security = 0x53c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU1R, + .name = "miu1r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x540, + .security = 0x544, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU1W, + .name = "miu1w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x548, + .security = 0x54c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU2R, + .name = "miu2r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x570, + .security = 0x574, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU2W, + .name = "miu2w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x578, + .security = 0x57c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU3R, + .name = "miu3r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x580, + .security = 0x584, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU3W, + .name = "miu3w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x588, + .security = 0x58c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU4R, + .name = "miu4r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x590, + .security = 0x594, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU4W, + .name = "miu4w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x598, + .security = 0x59c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DPMUR, + .name = "dpmur", + .sid = TEGRA194_SID_PASSTHROUGH, + .regs = { + .sid = { + .override = 0x598, + .security = 0x59c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VIFALR, + .name = "vifalr", + .sid = TEGRA194_SID_VI_FALCON, + .regs = { + .sid = { + .override = 0x5e0, + .security = 0x5e4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_VIFALW, + .name = "vifalw", + .sid = TEGRA194_SID_VI_FALCON, + .regs = { + .sid = { + .override = 0x5e8, + .security = 0x5ec, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA0RDA, + .name = "dla0rda", + .sid = TEGRA194_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x5f0, + .security = 0x5f4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA0FALRDB, + .name = "dla0falrdb", + .sid = TEGRA194_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x5f8, + .security = 0x5fc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA0WRA, + .name = "dla0wra", + .sid = TEGRA194_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x600, + .security = 0x604, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA0FALWRB, + .name = "dla0falwrb", + .sid = TEGRA194_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x608, + .security = 0x60c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA1RDA, + .name = "dla1rda", + .sid = TEGRA194_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x610, + .security = 0x614, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA1FALRDB, + .name = "dla1falrdb", + .sid = TEGRA194_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x618, + .security = 0x61c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA1WRA, + .name = "dla1wra", + .sid = TEGRA194_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x620, + .security = 0x624, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA1FALWRB, + .name = "dla1falwrb", + .sid = TEGRA194_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x628, + .security = 0x62c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0RDA, + .name = "pva0rda", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x630, + .security = 0x634, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0RDB, + .name = "pva0rdb", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x638, + .security = 0x63c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0RDC, + .name = "pva0rdc", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x640, + .security = 0x644, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0WRA, + .name = "pva0wra", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x648, + .security = 0x64c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0WRB, + .name = "pva0wrb", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x650, + .security = 0x654, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0WRC, + .name = "pva0wrc", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x658, + .security = 0x65c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1RDA, + .name = "pva1rda", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x660, + .security = 0x664, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1RDB, + .name = "pva1rdb", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x668, + .security = 0x66c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1RDC, + .name = "pva1rdc", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x670, + .security = 0x674, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1WRA, + .name = "pva1wra", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x678, + .security = 0x67c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1WRB, + .name = "pva1wrb", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x680, + .security = 0x684, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1WRC, + .name = "pva1wrc", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x688, + .security = 0x68c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_RCER, + .name = "rcer", + .sid = TEGRA194_SID_RCE, + .regs = { + .sid = { + .override = 0x690, + .security = 0x694, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_RCEW, + .name = "rcew", + .sid = TEGRA194_SID_RCE, + .regs = { + .sid = { + .override = 0x698, + .security = 0x69c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_RCEDMAR, + .name = "rcedmar", + .sid = TEGRA194_SID_RCE, + .regs = { + .sid = { + .override = 0x6a0, + .security = 0x6a4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_RCEDMAW, + .name = "rcedmaw", + .sid = TEGRA194_SID_RCE, + .regs = { + .sid = { + .override = 0x6a8, + .security = 0x6ac, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENC1SRD, + .name = "nvenc1srd", + .sid = TEGRA194_SID_NVENC1, + .regs = { + .sid = { + .override = 0x6b0, + .security = 0x6b4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENC1SWR, + .name = "nvenc1swr", + .sid = TEGRA194_SID_NVENC1, + .regs = { + .sid = { + .override = 0x6b8, + .security = 0x6bc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE0R, + .name = "pcie0r", + .sid = TEGRA194_SID_PCIE0, + .regs = { + .sid = { + .override = 0x6c0, + .security = 0x6c4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE0W, + .name = "pcie0w", + .sid = TEGRA194_SID_PCIE0, + .regs = { + .sid = { + .override = 0x6c8, + .security = 0x6cc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE1R, + .name = "pcie1r", + .sid = TEGRA194_SID_PCIE1, + .regs = { + .sid = { + .override = 0x6d0, + .security = 0x6d4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE1W, + .name = "pcie1w", + .sid = TEGRA194_SID_PCIE1, + .regs = { + .sid = { + .override = 0x6d8, + .security = 0x6dc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE2AR, + .name = "pcie2ar", + .sid = TEGRA194_SID_PCIE2, + .regs = { + .sid = { + .override = 0x6e0, + .security = 0x6e4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE2AW, + .name = "pcie2aw", + .sid = TEGRA194_SID_PCIE2, + .regs = { + .sid = { + .override = 0x6e8, + .security = 0x6ec, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE3R, + .name = "pcie3r", + .sid = TEGRA194_SID_PCIE3, + .regs = { + .sid = { + .override = 0x6f0, + .security = 0x6f4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE3W, + .name = "pcie3w", + .sid = TEGRA194_SID_PCIE3, + .regs = { + .sid = { + .override = 0x6f8, + .security = 0x6fc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE4R, + .name = "pcie4r", + .sid = TEGRA194_SID_PCIE4, + .regs = { + .sid = { + .override = 0x700, + .security = 0x704, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE4W, + .name = "pcie4w", + .sid = TEGRA194_SID_PCIE4, + .regs = { + .sid = { + .override = 0x708, + .security = 0x70c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE5R, + .name = "pcie5r", + .sid = TEGRA194_SID_PCIE5, + .regs = { + .sid = { + .override = 0x710, + .security = 0x714, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE5W, + .name = "pcie5w", + .sid = TEGRA194_SID_PCIE5, + .regs = { + .sid = { + .override = 0x718, + .security = 0x71c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPFALW, + .name = "ispfalw", + .sid = TEGRA194_SID_ISP_FALCON, + .regs = { + .sid = { + .override = 0x720, + .security = 0x724, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA0RDA1, + .name = "dla0rda1", + .sid = TEGRA194_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x748, + .security = 0x74c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_DLA1RDA1, + .name = "dla1rda1", + .sid = TEGRA194_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x750, + .security = 0x754, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0RDA1, + .name = "pva0rda1", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x758, + .security = 0x75c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA0RDB1, + .name = "pva0rdb1", + .sid = TEGRA194_SID_PVA0, + .regs = { + .sid = { + .override = 0x760, + .security = 0x764, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1RDA1, + .name = "pva1rda1", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x768, + .security = 0x76c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PVA1RDB1, + .name = "pva1rdb1", + .sid = TEGRA194_SID_PVA1, + .regs = { + .sid = { + .override = 0x770, + .security = 0x774, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE5R1, + .name = "pcie5r1", + .sid = TEGRA194_SID_PCIE5, + .regs = { + .sid = { + .override = 0x778, + .security = 0x77c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENCSRD1, + .name = "nvencsrd1", + .sid = TEGRA194_SID_NVENC, + .regs = { + .sid = { + .override = 0x780, + .security = 0x784, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVENC1SRD1, + .name = "nvenc1srd1", + .sid = TEGRA194_SID_NVENC1, + .regs = { + .sid = { + .override = 0x788, + .security = 0x78c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_ISPRA1, + .name = "ispra1", + .sid = TEGRA194_SID_ISP, + .regs = { + .sid = { + .override = 0x790, + .security = 0x794, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_PCIE0R1, + .name = "pcie0r1", + .sid = TEGRA194_SID_PCIE0, + .regs = { + .sid = { + .override = 0x798, + .security = 0x79c, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDEC1SRD, + .name = "nvdec1srd", + .sid = TEGRA194_SID_NVDEC1, + .regs = { + .sid = { + .override = 0x7c8, + .security = 0x7cc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDEC1SRD1, + .name = "nvdec1srd1", + .sid = TEGRA194_SID_NVDEC1, + .regs = { + .sid = { + .override = 0x7d0, + .security = 0x7d4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_NVDEC1SWR, + .name = "nvdec1swr", + .sid = TEGRA194_SID_NVDEC1, + .regs = { + .sid = { + .override = 0x7d8, + .security = 0x7dc, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU5R, + .name = "miu5r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x7e0, + .security = 0x7e4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU5W, + .name = "miu5w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x7e8, + .security = 0x7ec, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU6R, + .name = "miu6r", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x7f0, + .security = 0x7f4, + }, + }, + }, { + .id = TEGRA194_MEMORY_CLIENT_MIU6W, + .name = "miu6w", + .sid = TEGRA194_SID_MIU, + .regs = { + .sid = { + .override = 0x7f8, + .security = 0x7fc, + }, + }, + }, +}; + +const struct tegra_mc_soc tegra194_mc_soc = { + .num_clients = ARRAY_SIZE(tegra194_mc_clients), + .clients = tegra194_mc_clients, + .num_address_bits = 40, + .ops = &tegra186_mc_ops, +}; diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c index da8a0da8da79..c3462dbc8c22 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -776,10 +776,6 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) } emc->debugfs.root = debugfs_create_dir("emc", NULL); - if (!emc->debugfs.root) { - dev_err(emc->dev, "failed to create debugfs directory\n"); - return; - } debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, &tegra_emc_debug_available_rates_fops); @@ -908,49 +904,6 @@ err_msg: return err; } -static int tegra_emc_opp_table_init(struct tegra_emc *emc) -{ - u32 hw_version = BIT(tegra_sku_info.soc_process_id); - struct opp_table *hw_opp_table; - int err; - - hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1); - err = PTR_ERR_OR_ZERO(hw_opp_table); - if (err) { - dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err); - return err; - } - - err = dev_pm_opp_of_add_table(emc->dev); - if (err) { - if (err == -ENODEV) - dev_err(emc->dev, "OPP table not found, please update your device tree\n"); - else - dev_err(emc->dev, "failed to add OPP table: %d\n", err); - - goto put_hw_table; - } - - dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", - hw_version, clk_get_rate(emc->clk) / 1000000); - - /* first dummy rate-set initializes voltage state */ - err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); - if (err) { - dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err); - goto remove_table; - } - - return 0; - -remove_table: - dev_pm_opp_of_remove_table(emc->dev); -put_hw_table: - dev_pm_opp_put_supported_hw(hw_opp_table); - - return err; -} - static void devm_tegra_emc_unset_callback(void *data) { tegra20_clk_set_emc_round_callback(NULL, NULL); @@ -1077,6 +1030,7 @@ static int tegra_emc_devfreq_init(struct tegra_emc *emc) static int tegra_emc_probe(struct platform_device *pdev) { + struct tegra_core_opp_params opp_params = {}; struct device_node *np; struct tegra_emc *emc; int irq, err; @@ -1122,7 +1076,9 @@ static int tegra_emc_probe(struct platform_device *pdev) if (err) return err; - err = tegra_emc_opp_table_init(emc); + opp_params.init_state = true; + + err = devm_tegra_core_dev_init_opp_table(&pdev->dev, &opp_params); if (err) return err; diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 2db68a913b7a..fcd7738fcb53 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -679,7 +679,7 @@ static int tegra20_mc_stats_show(struct seq_file *s, void *unused) return 0; } -static int tegra20_mc_init(struct tegra_mc *mc) +static int tegra20_mc_probe(struct tegra_mc *mc) { debugfs_create_devm_seqfile(mc->dev, "stats", mc->debugfs.root, tegra20_mc_stats_show); @@ -687,6 +687,112 @@ static int tegra20_mc_init(struct tegra_mc *mc) return 0; } +static int tegra20_mc_suspend(struct tegra_mc *mc) +{ + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_suspend(mc->gart); + if (err < 0) + return err; + } + + return 0; +} + +static int tegra20_mc_resume(struct tegra_mc *mc) +{ + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_resume(mc->gart); + if (err < 0) + return err; + } + + return 0; +} + +static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) +{ + struct tegra_mc *mc = data; + unsigned long status; + unsigned int bit; + + /* mask all interrupts to avoid flooding */ + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; + if (!status) + return IRQ_NONE; + + for_each_set_bit(bit, &status, 32) { + const char *error = tegra_mc_status_names[bit]; + const char *direction = "read", *secure = ""; + const char *client, *desc; + phys_addr_t addr; + u32 value, reg; + u8 id, type; + + switch (BIT(bit)) { + case MC_INT_DECERR_EMEM: + reg = MC_DECERR_EMEM_OTHERS_STATUS; + value = mc_readl(mc, reg); + + id = value & mc->soc->client_id_mask; + desc = tegra_mc_error_names[2]; + + if (value & BIT(31)) + direction = "write"; + break; + + case MC_INT_INVALID_GART_PAGE: + reg = MC_GART_ERROR_REQ; + value = mc_readl(mc, reg); + + id = (value >> 1) & mc->soc->client_id_mask; + desc = tegra_mc_error_names[2]; + + if (value & BIT(0)) + direction = "write"; + break; + + case MC_INT_SECURITY_VIOLATION: + reg = MC_SECURITY_VIOLATION_STATUS; + value = mc_readl(mc, reg); + + id = value & mc->soc->client_id_mask; + type = (value & BIT(30)) ? 4 : 3; + desc = tegra_mc_error_names[type]; + secure = "secure "; + + if (value & BIT(31)) + direction = "write"; + break; + + default: + continue; + } + + client = mc->soc->clients[id].name; + addr = mc_readl(mc, reg + sizeof(u32)); + + dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", + client, secure, direction, &addr, error, + desc); + } + + /* clear interrupts */ + mc_writel(mc, status, MC_INTSTATUS); + + return IRQ_HANDLED; +} + +static const struct tegra_mc_ops tegra20_mc_ops = { + .probe = tegra20_mc_probe, + .suspend = tegra20_mc_suspend, + .resume = tegra20_mc_resume, + .handle_irq = tegra20_mc_handle_irq, +}; + const struct tegra_mc_soc tegra20_mc_soc = { .clients = tegra20_mc_clients, .num_clients = ARRAY_SIZE(tegra20_mc_clients), @@ -698,5 +804,5 @@ const struct tegra_mc_soc tegra20_mc_soc = { .resets = tegra20_mc_resets, .num_resets = ARRAY_SIZE(tegra20_mc_resets), .icc_ops = &tegra20_mc_icc_ops, - .init = tegra20_mc_init, + .ops = &tegra20_mc_ops, }; diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index 5f224796e32e..06c0f17fa429 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -1759,10 +1759,6 @@ static void tegra210_emc_debugfs_init(struct tegra210_emc *emc) } emc->debugfs.root = debugfs_create_dir("emc", NULL); - if (!emc->debugfs.root) { - dev_err(dev, "failed to create debugfs directory\n"); - return; - } debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, &tegra210_emc_debug_available_rates_fops); diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index b3bbc5a05ba1..8ab6498dbe7d 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -16,1005 +16,1149 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { .id = 0x01, .name = "display0a", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 1, - }, - .la = { - .reg = 0x2e8, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 1, + }, + .la = { + .reg = 0x2e8, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x02, .name = "display0ab", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 2, - }, - .la = { - .reg = 0x2f4, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 2, + }, + .la = { + .reg = 0x2f4, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x03, .name = "display0b", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 3, - }, - .la = { - .reg = 0x2e8, - .shift = 16, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 3, + }, + .la = { + .reg = 0x2e8, + .shift = 16, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x04, .name = "display0bb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 4, - }, - .la = { - .reg = 0x2f4, - .shift = 16, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 4, + }, + .la = { + .reg = 0x2f4, + .shift = 16, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x05, .name = "display0c", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 5, - }, - .la = { - .reg = 0x2ec, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 5, + }, + .la = { + .reg = 0x2ec, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x06, .name = "display0cb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 6, - }, - .la = { - .reg = 0x2f8, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 6, + }, + .la = { + .reg = 0x2f8, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x0e, .name = "afir", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x228, - .bit = 14, - }, - .la = { - .reg = 0x2e0, - .shift = 0, - .mask = 0xff, - .def = 0x2e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 14, + }, + .la = { + .reg = 0x2e0, + .shift = 0, + .mask = 0xff, + .def = 0x2e, + }, }, }, { .id = 0x0f, .name = "avpcarm7r", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x228, - .bit = 15, - }, - .la = { - .reg = 0x2e4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 15, + }, + .la = { + .reg = 0x2e4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x10, .name = "displayhc", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 16, - }, - .la = { - .reg = 0x2f0, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 16, + }, + .la = { + .reg = 0x2f0, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x11, .name = "displayhcb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 17, - }, - .la = { - .reg = 0x2fc, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 17, + }, + .la = { + .reg = 0x2fc, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x15, .name = "hdar", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x228, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 0, - .mask = 0xff, - .def = 0x24, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 0, + .mask = 0xff, + .def = 0x24, + }, }, }, { .id = 0x16, .name = "host1xdmar", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 22, - }, - .la = { - .reg = 0x310, - .shift = 0, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 22, + }, + .la = { + .reg = 0x310, + .shift = 0, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x17, .name = "host1xr", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 23, - }, - .la = { - .reg = 0x310, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 23, + }, + .la = { + .reg = 0x310, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x1c, .name = "nvencsrd", .swgroup = TEGRA_SWGROUP_NVENC, - .smmu = { - .reg = 0x228, - .bit = 28, - }, - .la = { - .reg = 0x328, - .shift = 0, - .mask = 0xff, - .def = 0x23, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 28, + }, + .la = { + .reg = 0x328, + .shift = 0, + .mask = 0xff, + .def = 0x23, + }, }, }, { .id = 0x1d, .name = "ppcsahbdmar", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 29, - }, - .la = { - .reg = 0x344, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 29, + }, + .la = { + .reg = 0x344, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x1e, .name = "ppcsahbslvr", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 30, - }, - .la = { - .reg = 0x344, - .shift = 16, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 30, + }, + .la = { + .reg = 0x344, + .shift = 16, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x1f, .name = "satar", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x228, - .bit = 31, - }, - .la = { - .reg = 0x350, - .shift = 0, - .mask = 0xff, - .def = 0x65, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 31, + }, + .la = { + .reg = 0x350, + .shift = 0, + .mask = 0xff, + .def = 0x65, + }, }, }, { .id = 0x27, .name = "mpcorer", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x320, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x2b, .name = "nvencswr", .swgroup = TEGRA_SWGROUP_NVENC, - .smmu = { - .reg = 0x22c, - .bit = 11, - }, - .la = { - .reg = 0x328, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 11, + }, + .la = { + .reg = 0x328, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x31, .name = "afiw", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x22c, - .bit = 17, - }, - .la = { - .reg = 0x2e0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 17, + }, + .la = { + .reg = 0x2e0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x32, .name = "avpcarm7w", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x22c, - .bit = 18, - }, - .la = { - .reg = 0x2e4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 18, + }, + .la = { + .reg = 0x2e4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x35, .name = "hdaw", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x22c, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x36, .name = "host1xw", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x22c, - .bit = 22, - }, - .la = { - .reg = 0x314, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 22, + }, + .la = { + .reg = 0x314, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x39, .name = "mpcorew", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .la = { + .reg = 0x320, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3b, .name = "ppcsahbdmaw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 27, - }, - .la = { - .reg = 0x348, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 27, + }, + .la = { + .reg = 0x348, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3c, .name = "ppcsahbslvw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 28, - }, - .la = { - .reg = 0x348, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 28, + }, + .la = { + .reg = 0x348, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x3d, .name = "sataw", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x22c, - .bit = 29, - }, - .la = { - .reg = 0x350, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 29, + }, + .la = { + .reg = 0x350, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x44, .name = "ispra", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 4, - }, - .la = { - .reg = 0x370, - .shift = 0, - .mask = 0xff, - .def = 0x18, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 4, + }, + .la = { + .reg = 0x370, + .shift = 0, + .mask = 0xff, + .def = 0x18, + }, }, }, { .id = 0x46, .name = "ispwa", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 6, - }, - .la = { - .reg = 0x374, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 6, + }, + .la = { + .reg = 0x374, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x47, .name = "ispwb", .swgroup = TEGRA_SWGROUP_ISP2, - .smmu = { - .reg = 0x230, - .bit = 7, - }, - .la = { - .reg = 0x374, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 7, + }, + .la = { + .reg = 0x374, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4a, .name = "xusb_hostr", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 10, - }, - .la = { - .reg = 0x37c, - .shift = 0, - .mask = 0xff, - .def = 0x7a, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 10, + }, + .la = { + .reg = 0x37c, + .shift = 0, + .mask = 0xff, + .def = 0x7a, + }, }, }, { .id = 0x4b, .name = "xusb_hostw", .swgroup = TEGRA_SWGROUP_XUSB_HOST, - .smmu = { - .reg = 0x230, - .bit = 11, - }, - .la = { - .reg = 0x37c, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 11, + }, + .la = { + .reg = 0x37c, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4c, .name = "xusb_devr", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 12, - }, - .la = { - .reg = 0x380, - .shift = 0, - .mask = 0xff, - .def = 0x39, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 12, + }, + .la = { + .reg = 0x380, + .shift = 0, + .mask = 0xff, + .def = 0x39, + }, }, }, { .id = 0x4d, .name = "xusb_devw", .swgroup = TEGRA_SWGROUP_XUSB_DEV, - .smmu = { - .reg = 0x230, - .bit = 13, - }, - .la = { - .reg = 0x380, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 13, + }, + .la = { + .reg = 0x380, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x4e, .name = "isprab", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 14, - }, - .la = { - .reg = 0x384, - .shift = 0, - .mask = 0xff, - .def = 0x18, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 14, + }, + .la = { + .reg = 0x384, + .shift = 0, + .mask = 0xff, + .def = 0x18, + }, }, }, { .id = 0x50, .name = "ispwab", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 16, - }, - .la = { - .reg = 0x388, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 16, + }, + .la = { + .reg = 0x388, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x51, .name = "ispwbb", .swgroup = TEGRA_SWGROUP_ISP2B, - .smmu = { - .reg = 0x230, - .bit = 17, - }, - .la = { - .reg = 0x388, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 17, + }, + .la = { + .reg = 0x388, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x54, .name = "tsecsrd", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 20, - }, - .la = { - .reg = 0x390, - .shift = 0, - .mask = 0xff, - .def = 0x9b, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 20, + }, + .la = { + .reg = 0x390, + .shift = 0, + .mask = 0xff, + .def = 0x9b, + }, }, }, { .id = 0x55, .name = "tsecswr", .swgroup = TEGRA_SWGROUP_TSEC, - .smmu = { - .reg = 0x230, - .bit = 21, - }, - .la = { - .reg = 0x390, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 21, + }, + .la = { + .reg = 0x390, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x56, .name = "a9avpscr", .swgroup = TEGRA_SWGROUP_A9AVP, - .smmu = { - .reg = 0x230, - .bit = 22, - }, - .la = { - .reg = 0x3a4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 22, + }, + .la = { + .reg = 0x3a4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, }, { .id = 0x57, .name = "a9avpscw", .swgroup = TEGRA_SWGROUP_A9AVP, - .smmu = { - .reg = 0x230, - .bit = 23, - }, - .la = { - .reg = 0x3a4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 23, + }, + .la = { + .reg = 0x3a4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x58, .name = "gpusrd", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0x230, - .bit = 24, - }, - .la = { - .reg = 0x3c8, - .shift = 0, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + /* read-only */ + .reg = 0x230, + .bit = 24, + }, + .la = { + .reg = 0x3c8, + .shift = 0, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x59, .name = "gpuswr", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0x230, - .bit = 25, - }, - .la = { - .reg = 0x3c8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + /* read-only */ + .reg = 0x230, + .bit = 25, + }, + .la = { + .reg = 0x3c8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x5a, .name = "displayt", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x230, - .bit = 26, - }, - .la = { - .reg = 0x2f0, - .shift = 16, - .mask = 0xff, - .def = 0x1e, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 26, + }, + .la = { + .reg = 0x2f0, + .shift = 16, + .mask = 0xff, + .def = 0x1e, + }, }, }, { .id = 0x60, .name = "sdmmcra", .swgroup = TEGRA_SWGROUP_SDMMC1A, - .smmu = { - .reg = 0x234, - .bit = 0, - }, - .la = { - .reg = 0x3b8, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 0, + }, + .la = { + .reg = 0x3b8, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x61, .name = "sdmmcraa", .swgroup = TEGRA_SWGROUP_SDMMC2A, - .smmu = { - .reg = 0x234, - .bit = 1, - }, - .la = { - .reg = 0x3bc, - .shift = 0, - .mask = 0xff, - .def = 0x5a, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 1, + }, + .la = { + .reg = 0x3bc, + .shift = 0, + .mask = 0xff, + .def = 0x5a, + }, }, }, { .id = 0x62, .name = "sdmmcr", .swgroup = TEGRA_SWGROUP_SDMMC3A, - .smmu = { - .reg = 0x234, - .bit = 2, - }, - .la = { - .reg = 0x3c0, - .shift = 0, - .mask = 0xff, - .def = 0x49, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 2, + }, + .la = { + .reg = 0x3c0, + .shift = 0, + .mask = 0xff, + .def = 0x49, + }, }, }, { .id = 0x63, .swgroup = TEGRA_SWGROUP_SDMMC4A, .name = "sdmmcrab", - .smmu = { - .reg = 0x234, - .bit = 3, - }, - .la = { - .reg = 0x3c4, - .shift = 0, - .mask = 0xff, - .def = 0x5a, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 3, + }, + .la = { + .reg = 0x3c4, + .shift = 0, + .mask = 0xff, + .def = 0x5a, + }, }, }, { .id = 0x64, .name = "sdmmcwa", .swgroup = TEGRA_SWGROUP_SDMMC1A, - .smmu = { - .reg = 0x234, - .bit = 4, - }, - .la = { - .reg = 0x3b8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 4, + }, + .la = { + .reg = 0x3b8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x65, .name = "sdmmcwaa", .swgroup = TEGRA_SWGROUP_SDMMC2A, - .smmu = { - .reg = 0x234, - .bit = 5, - }, - .la = { - .reg = 0x3bc, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 5, + }, + .la = { + .reg = 0x3bc, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x66, .name = "sdmmcw", .swgroup = TEGRA_SWGROUP_SDMMC3A, - .smmu = { - .reg = 0x234, - .bit = 6, - }, - .la = { - .reg = 0x3c0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 6, + }, + .la = { + .reg = 0x3c0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x67, .name = "sdmmcwab", .swgroup = TEGRA_SWGROUP_SDMMC4A, - .smmu = { - .reg = 0x234, - .bit = 7, - }, - .la = { - .reg = 0x3c4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 7, + }, + .la = { + .reg = 0x3c4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x6c, .name = "vicsrd", .swgroup = TEGRA_SWGROUP_VIC, - .smmu = { - .reg = 0x234, - .bit = 12, - }, - .la = { - .reg = 0x394, - .shift = 0, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 12, + }, + .la = { + .reg = 0x394, + .shift = 0, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x6d, .name = "vicswr", .swgroup = TEGRA_SWGROUP_VIC, - .smmu = { - .reg = 0x234, - .bit = 13, - }, - .la = { - .reg = 0x394, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 13, + }, + .la = { + .reg = 0x394, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x72, .name = "viw", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x234, - .bit = 18, - }, - .la = { - .reg = 0x398, - .shift = 0, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 18, + }, + .la = { + .reg = 0x398, + .shift = 0, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x73, .name = "displayd", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x234, - .bit = 19, - }, - .la = { - .reg = 0x3c8, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 19, + }, + .la = { + .reg = 0x3c8, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, }, { .id = 0x78, .name = "nvdecsrd", .swgroup = TEGRA_SWGROUP_NVDEC, - .smmu = { - .reg = 0x234, - .bit = 24, - }, - .la = { - .reg = 0x3d8, - .shift = 0, - .mask = 0xff, - .def = 0x23, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 24, + }, + .la = { + .reg = 0x3d8, + .shift = 0, + .mask = 0xff, + .def = 0x23, + }, }, }, { .id = 0x79, .name = "nvdecswr", .swgroup = TEGRA_SWGROUP_NVDEC, - .smmu = { - .reg = 0x234, - .bit = 25, - }, - .la = { - .reg = 0x3d8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 25, + }, + .la = { + .reg = 0x3d8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x7a, .name = "aper", .swgroup = TEGRA_SWGROUP_APE, - .smmu = { - .reg = 0x234, - .bit = 26, - }, - .la = { - .reg = 0x3dc, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 26, + }, + .la = { + .reg = 0x3dc, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x7b, .name = "apew", .swgroup = TEGRA_SWGROUP_APE, - .smmu = { - .reg = 0x234, - .bit = 27, - }, - .la = { - .reg = 0x3dc, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 27, + }, + .la = { + .reg = 0x3dc, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x7e, .name = "nvjpgsrd", .swgroup = TEGRA_SWGROUP_NVJPG, - .smmu = { - .reg = 0x234, - .bit = 30, - }, - .la = { - .reg = 0x3e4, - .shift = 0, - .mask = 0xff, - .def = 0x23, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 30, + }, + .la = { + .reg = 0x3e4, + .shift = 0, + .mask = 0xff, + .def = 0x23, + }, }, }, { .id = 0x7f, .name = "nvjpgswr", .swgroup = TEGRA_SWGROUP_NVJPG, - .smmu = { - .reg = 0x234, - .bit = 31, - }, - .la = { - .reg = 0x3e4, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x234, + .bit = 31, + }, + .la = { + .reg = 0x3e4, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x80, .name = "sesrd", .swgroup = TEGRA_SWGROUP_SE, - .smmu = { - .reg = 0xb98, - .bit = 0, - }, - .la = { - .reg = 0x3e0, - .shift = 0, - .mask = 0xff, - .def = 0x2e, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 0, + }, + .la = { + .reg = 0x3e0, + .shift = 0, + .mask = 0xff, + .def = 0x2e, + }, }, }, { .id = 0x81, .name = "seswr", .swgroup = TEGRA_SWGROUP_SE, - .smmu = { - .reg = 0xb98, - .bit = 1, - }, - .la = { - .reg = 0x3e0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 1, + }, + .la = { + .reg = 0x3e0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x82, .name = "axiapr", .swgroup = TEGRA_SWGROUP_AXIAP, - .smmu = { - .reg = 0xb98, - .bit = 2, - }, - .la = { - .reg = 0x3a0, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 2, + }, + .la = { + .reg = 0x3a0, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x83, .name = "axiapw", .swgroup = TEGRA_SWGROUP_AXIAP, - .smmu = { - .reg = 0xb98, - .bit = 3, - }, - .la = { - .reg = 0x3a0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 3, + }, + .la = { + .reg = 0x3a0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x84, .name = "etrr", .swgroup = TEGRA_SWGROUP_ETR, - .smmu = { - .reg = 0xb98, - .bit = 4, - }, - .la = { - .reg = 0x3ec, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 4, + }, + .la = { + .reg = 0x3ec, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, }, { .id = 0x85, .name = "etrw", .swgroup = TEGRA_SWGROUP_ETR, - .smmu = { - .reg = 0xb98, - .bit = 5, - }, - .la = { - .reg = 0x3ec, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 5, + }, + .la = { + .reg = 0x3ec, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x86, .name = "tsecsrdb", .swgroup = TEGRA_SWGROUP_TSECB, - .smmu = { - .reg = 0xb98, - .bit = 6, - }, - .la = { - .reg = 0x3f0, - .shift = 0, - .mask = 0xff, - .def = 0x9b, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 6, + }, + .la = { + .reg = 0x3f0, + .shift = 0, + .mask = 0xff, + .def = 0x9b, + }, }, }, { .id = 0x87, .name = "tsecswrb", .swgroup = TEGRA_SWGROUP_TSECB, - .smmu = { - .reg = 0xb98, - .bit = 7, - }, - .la = { - .reg = 0x3f0, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0xb98, + .bit = 7, + }, + .la = { + .reg = 0x3f0, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, { .id = 0x88, .name = "gpusrd2", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0xb98, - .bit = 8, - }, - .la = { - .reg = 0x3e8, - .shift = 0, - .mask = 0xff, - .def = 0x1a, + .regs = { + .smmu = { + /* read-only */ + .reg = 0xb98, + .bit = 8, + }, + .la = { + .reg = 0x3e8, + .shift = 0, + .mask = 0xff, + .def = 0x1a, + }, }, }, { .id = 0x89, .name = "gpuswr2", .swgroup = TEGRA_SWGROUP_GPU, - .smmu = { - /* read-only */ - .reg = 0xb98, - .bit = 9, - }, - .la = { - .reg = 0x3e8, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + /* read-only */ + .reg = 0xb98, + .bit = 9, + }, + .la = { + .reg = 0x3e8, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, }, }; @@ -1142,4 +1286,5 @@ const struct tegra_mc_soc tegra210_mc_soc = { .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra210_mc_resets, .num_resets = ARRAY_SIZE(tegra210_mc_resets), + .ops = &tegra30_mc_ops, }; diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index 829f6d673c96..7e21a852f2e1 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -150,8 +150,8 @@ #define EMC_SELF_REF_CMD_ENABLED BIT(0) #define DRAM_DEV_SEL_ALL (0 << 30) -#define DRAM_DEV_SEL_0 (2 << 30) -#define DRAM_DEV_SEL_1 (1 << 30) +#define DRAM_DEV_SEL_0 BIT(31) +#define DRAM_DEV_SEL_1 BIT(30) #define DRAM_BROADCAST(num) \ ((num) > 1 ? DRAM_DEV_SEL_ALL : DRAM_DEV_SEL_0) @@ -1354,10 +1354,6 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) } emc->debugfs.root = debugfs_create_dir("emc", NULL); - if (!emc->debugfs.root) { - dev_err(emc->dev, "failed to create debugfs directory\n"); - return; - } debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, &tegra_emc_debug_available_rates_fops); @@ -1480,49 +1476,6 @@ err_msg: return err; } -static int tegra_emc_opp_table_init(struct tegra_emc *emc) -{ - u32 hw_version = BIT(tegra_sku_info.soc_speedo_id); - struct opp_table *hw_opp_table; - int err; - - hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1); - err = PTR_ERR_OR_ZERO(hw_opp_table); - if (err) { - dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err); - return err; - } - - err = dev_pm_opp_of_add_table(emc->dev); - if (err) { - if (err == -ENODEV) - dev_err(emc->dev, "OPP table not found, please update your device tree\n"); - else - dev_err(emc->dev, "failed to add OPP table: %d\n", err); - - goto put_hw_table; - } - - dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n", - hw_version, clk_get_rate(emc->clk) / 1000000); - - /* first dummy rate-set initializes voltage state */ - err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); - if (err) { - dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err); - goto remove_table; - } - - return 0; - -remove_table: - dev_pm_opp_of_remove_table(emc->dev); -put_hw_table: - dev_pm_opp_put_supported_hw(hw_opp_table); - - return err; -} - static void devm_tegra_emc_unset_callback(void *data) { tegra20_clk_set_emc_round_callback(NULL, NULL); @@ -1568,6 +1521,7 @@ static int tegra_emc_init_clk(struct tegra_emc *emc) static int tegra_emc_probe(struct platform_device *pdev) { + struct tegra_core_opp_params opp_params = {}; struct device_node *np; struct tegra_emc *emc; int err; @@ -1617,7 +1571,9 @@ static int tegra_emc_probe(struct platform_device *pdev) if (err) return err; - err = tegra_emc_opp_table_init(emc); + opp_params.init_state = true; + + err = devm_tegra_core_dev_init_opp_table(&pdev->dev, &opp_params); if (err) return err; diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index ea849003014b..84316357513d 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -37,970 +37,1102 @@ static const struct tegra_mc_client tegra30_mc_clients[] = { .id = 0x00, .name = "ptcr", .swgroup = TEGRA_SWGROUP_PTC, - .la = { - .reg = 0x34c, - .shift = 0, - .mask = 0xff, - .def = 0x0, + .regs = { + .la = { + .reg = 0x34c, + .shift = 0, + .mask = 0xff, + .def = 0x0, + }, }, .fifo_size = 16 * 2, }, { .id = 0x01, .name = "display0a", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 1, - }, - .la = { - .reg = 0x2e8, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 1, + }, + .la = { + .reg = 0x2e8, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 128, }, { .id = 0x02, .name = "display0ab", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 2, - }, - .la = { - .reg = 0x2f4, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 2, + }, + .la = { + .reg = 0x2f4, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 128, }, { .id = 0x03, .name = "display0b", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 3, - }, - .la = { - .reg = 0x2e8, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 3, + }, + .la = { + .reg = 0x2e8, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 64, }, { .id = 0x04, .name = "display0bb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 4, - }, - .la = { - .reg = 0x2f4, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 4, + }, + .la = { + .reg = 0x2f4, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 64, }, { .id = 0x05, .name = "display0c", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 5, - }, - .la = { - .reg = 0x2ec, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 5, + }, + .la = { + .reg = 0x2ec, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 128, }, { .id = 0x06, .name = "display0cb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 6, - }, - .la = { - .reg = 0x2f8, - .shift = 0, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 6, + }, + .la = { + .reg = 0x2f8, + .shift = 0, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 128, }, { .id = 0x07, .name = "display1b", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 7, - }, - .la = { - .reg = 0x2ec, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 7, + }, + .la = { + .reg = 0x2ec, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 64, }, { .id = 0x08, .name = "display1bb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 8, - }, - .la = { - .reg = 0x2f8, - .shift = 16, - .mask = 0xff, - .def = 0x4e, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 8, + }, + .la = { + .reg = 0x2f8, + .shift = 16, + .mask = 0xff, + .def = 0x4e, + }, }, .fifo_size = 16 * 64, }, { .id = 0x09, .name = "eppup", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x228, - .bit = 9, - }, - .la = { - .reg = 0x300, - .shift = 0, - .mask = 0xff, - .def = 0x17, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 9, + }, + .la = { + .reg = 0x300, + .shift = 0, + .mask = 0xff, + .def = 0x17, + }, }, .fifo_size = 16 * 8, }, { .id = 0x0a, .name = "g2pr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 10, - }, - .la = { - .reg = 0x308, - .shift = 0, - .mask = 0xff, - .def = 0x09, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 10, + }, + .la = { + .reg = 0x308, + .shift = 0, + .mask = 0xff, + .def = 0x09, + }, }, .fifo_size = 16 * 64, }, { .id = 0x0b, .name = "g2sr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 11, - }, - .la = { - .reg = 0x308, - .shift = 16, - .mask = 0xff, - .def = 0x09, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 11, + }, + .la = { + .reg = 0x308, + .shift = 16, + .mask = 0xff, + .def = 0x09, + }, }, .fifo_size = 16 * 64, }, { .id = 0x0c, .name = "mpeunifbr", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x228, - .bit = 12, - }, - .la = { - .reg = 0x328, - .shift = 0, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 12, + }, + .la = { + .reg = 0x328, + .shift = 0, + .mask = 0xff, + .def = 0x50, + }, }, .fifo_size = 16 * 8, }, { .id = 0x0d, .name = "viruv", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x228, - .bit = 13, - }, - .la = { - .reg = 0x364, - .shift = 0, - .mask = 0xff, - .def = 0x2c, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 13, + }, + .la = { + .reg = 0x364, + .shift = 0, + .mask = 0xff, + .def = 0x2c, + }, }, .fifo_size = 16 * 8, }, { .id = 0x0e, .name = "afir", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x228, - .bit = 14, - }, - .la = { - .reg = 0x2e0, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 14, + }, + .la = { + .reg = 0x2e0, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, .fifo_size = 16 * 32, }, { .id = 0x0f, .name = "avpcarm7r", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x228, - .bit = 15, - }, - .la = { - .reg = 0x2e4, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 15, + }, + .la = { + .reg = 0x2e4, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, .fifo_size = 16 * 2, }, { .id = 0x10, .name = "displayhc", .swgroup = TEGRA_SWGROUP_DC, - .smmu = { - .reg = 0x228, - .bit = 16, - }, - .la = { - .reg = 0x2f0, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 16, + }, + .la = { + .reg = 0x2f0, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 2, }, { .id = 0x11, .name = "displayhcb", .swgroup = TEGRA_SWGROUP_DCB, - .smmu = { - .reg = 0x228, - .bit = 17, - }, - .la = { - .reg = 0x2fc, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 17, + }, + .la = { + .reg = 0x2fc, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 2, }, { .id = 0x12, .name = "fdcdrd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x228, - .bit = 18, - }, - .la = { - .reg = 0x334, - .shift = 0, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 18, + }, + .la = { + .reg = 0x334, + .shift = 0, + .mask = 0xff, + .def = 0x0a, + }, }, .fifo_size = 16 * 48, }, { .id = 0x13, .name = "fdcdrd2", .swgroup = TEGRA_SWGROUP_NV2, - .smmu = { - .reg = 0x228, - .bit = 19, - }, - .la = { - .reg = 0x33c, - .shift = 0, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 19, + }, + .la = { + .reg = 0x33c, + .shift = 0, + .mask = 0xff, + .def = 0x0a, + }, }, .fifo_size = 16 * 48, }, { .id = 0x14, .name = "g2dr", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x228, - .bit = 20, - }, - .la = { - .reg = 0x30c, - .shift = 0, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 20, + }, + .la = { + .reg = 0x30c, + .shift = 0, + .mask = 0xff, + .def = 0x0a, + }, }, .fifo_size = 16 * 48, }, { .id = 0x15, .name = "hdar", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x228, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 16, }, { .id = 0x16, .name = "host1xdmar", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 22, - }, - .la = { - .reg = 0x310, - .shift = 0, - .mask = 0xff, - .def = 0x05, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 22, + }, + .la = { + .reg = 0x310, + .shift = 0, + .mask = 0xff, + .def = 0x05, + }, }, .fifo_size = 16 * 16, }, { .id = 0x17, .name = "host1xr", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x228, - .bit = 23, - }, - .la = { - .reg = 0x310, - .shift = 16, - .mask = 0xff, - .def = 0x50, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 23, + }, + .la = { + .reg = 0x310, + .shift = 16, + .mask = 0xff, + .def = 0x50, + }, }, .fifo_size = 16 * 8, }, { .id = 0x18, .name = "idxsrd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x228, - .bit = 24, - }, - .la = { - .reg = 0x334, - .shift = 16, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 24, + }, + .la = { + .reg = 0x334, + .shift = 16, + .mask = 0xff, + .def = 0x13, + }, }, .fifo_size = 16 * 64, }, { .id = 0x19, .name = "idxsrd2", .swgroup = TEGRA_SWGROUP_NV2, - .smmu = { - .reg = 0x228, - .bit = 25, - }, - .la = { - .reg = 0x33c, - .shift = 16, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 25, + }, + .la = { + .reg = 0x33c, + .shift = 16, + .mask = 0xff, + .def = 0x13, + }, }, .fifo_size = 16 * 64, }, { .id = 0x1a, .name = "mpe_ipred", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x228, - .bit = 26, - }, - .la = { - .reg = 0x328, - .shift = 16, - .mask = 0xff, - .def = 0x80, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 26, + }, + .la = { + .reg = 0x328, + .shift = 16, + .mask = 0xff, + .def = 0x80, + }, }, .fifo_size = 16 * 2, }, { .id = 0x1b, .name = "mpeamemrd", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x228, - .bit = 27, - }, - .la = { - .reg = 0x32c, - .shift = 0, - .mask = 0xff, - .def = 0x42, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 27, + }, + .la = { + .reg = 0x32c, + .shift = 0, + .mask = 0xff, + .def = 0x42, + }, }, .fifo_size = 16 * 64, }, { .id = 0x1c, .name = "mpecsrd", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x228, - .bit = 28, - }, - .la = { - .reg = 0x32c, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 28, + }, + .la = { + .reg = 0x32c, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 8, }, { .id = 0x1d, .name = "ppcsahbdmar", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 29, - }, - .la = { - .reg = 0x344, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 29, + }, + .la = { + .reg = 0x344, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, .fifo_size = 16 * 2, }, { .id = 0x1e, .name = "ppcsahbslvr", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x228, - .bit = 30, - }, - .la = { - .reg = 0x344, - .shift = 16, - .mask = 0xff, - .def = 0x12, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 30, + }, + .la = { + .reg = 0x344, + .shift = 16, + .mask = 0xff, + .def = 0x12, + }, }, .fifo_size = 16 * 8, }, { .id = 0x1f, .name = "satar", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x228, - .bit = 31, - }, - .la = { - .reg = 0x350, - .shift = 0, - .mask = 0xff, - .def = 0x33, + .regs = { + .smmu = { + .reg = 0x228, + .bit = 31, + }, + .la = { + .reg = 0x350, + .shift = 0, + .mask = 0xff, + .def = 0x33, + }, }, .fifo_size = 16 * 32, }, { .id = 0x20, .name = "texsrd", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x22c, - .bit = 0, - }, - .la = { - .reg = 0x338, - .shift = 0, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 0, + }, + .la = { + .reg = 0x338, + .shift = 0, + .mask = 0xff, + .def = 0x13, + }, }, .fifo_size = 16 * 64, }, { .id = 0x21, .name = "texsrd2", .swgroup = TEGRA_SWGROUP_NV2, - .smmu = { - .reg = 0x22c, - .bit = 1, - }, - .la = { - .reg = 0x340, - .shift = 0, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 1, + }, + .la = { + .reg = 0x340, + .shift = 0, + .mask = 0xff, + .def = 0x13, + }, }, .fifo_size = 16 * 64, }, { .id = 0x22, .name = "vdebsevr", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 2, - }, - .la = { - .reg = 0x354, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 2, + }, + .la = { + .reg = 0x354, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 8, }, { .id = 0x23, .name = "vdember", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 3, - }, - .la = { - .reg = 0x354, - .shift = 16, - .mask = 0xff, - .def = 0xd0, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 3, + }, + .la = { + .reg = 0x354, + .shift = 16, + .mask = 0xff, + .def = 0xd0, + }, }, .fifo_size = 16 * 4, }, { .id = 0x24, .name = "vdemcer", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 4, - }, - .la = { - .reg = 0x358, - .shift = 0, - .mask = 0xff, - .def = 0x2a, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 4, + }, + .la = { + .reg = 0x358, + .shift = 0, + .mask = 0xff, + .def = 0x2a, + }, }, .fifo_size = 16 * 16, }, { .id = 0x25, .name = "vdetper", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 5, - }, - .la = { - .reg = 0x358, - .shift = 16, - .mask = 0xff, - .def = 0x74, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 5, + }, + .la = { + .reg = 0x358, + .shift = 16, + .mask = 0xff, + .def = 0x74, + }, }, .fifo_size = 16 * 16, }, { .id = 0x26, .name = "mpcorelpr", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x324, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, .fifo_size = 16 * 14, }, { .id = 0x27, .name = "mpcorer", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 0, - .mask = 0xff, - .def = 0x04, + .regs = { + .la = { + .reg = 0x320, + .shift = 0, + .mask = 0xff, + .def = 0x04, + }, }, .fifo_size = 16 * 14, }, { .id = 0x28, .name = "eppu", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 8, - }, - .la = { - .reg = 0x300, - .shift = 16, - .mask = 0xff, - .def = 0x6c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 8, + }, + .la = { + .reg = 0x300, + .shift = 16, + .mask = 0xff, + .def = 0x6c, + }, }, .fifo_size = 16 * 64, }, { .id = 0x29, .name = "eppv", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 9, - }, - .la = { - .reg = 0x304, - .shift = 0, - .mask = 0xff, - .def = 0x6c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 9, + }, + .la = { + .reg = 0x304, + .shift = 0, + .mask = 0xff, + .def = 0x6c, + }, }, .fifo_size = 16 * 64, }, { .id = 0x2a, .name = "eppy", .swgroup = TEGRA_SWGROUP_EPP, - .smmu = { - .reg = 0x22c, - .bit = 10, - }, - .la = { - .reg = 0x304, - .shift = 16, - .mask = 0xff, - .def = 0x6c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 10, + }, + .la = { + .reg = 0x304, + .shift = 16, + .mask = 0xff, + .def = 0x6c, + }, }, .fifo_size = 16 * 64, }, { .id = 0x2b, .name = "mpeunifbw", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x22c, - .bit = 11, - }, - .la = { - .reg = 0x330, - .shift = 0, - .mask = 0xff, - .def = 0x13, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 11, + }, + .la = { + .reg = 0x330, + .shift = 0, + .mask = 0xff, + .def = 0x13, + }, }, .fifo_size = 16 * 8, }, { .id = 0x2c, .name = "viwsb", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 12, - }, - .la = { - .reg = 0x364, - .shift = 16, - .mask = 0xff, - .def = 0x12, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 12, + }, + .la = { + .reg = 0x364, + .shift = 16, + .mask = 0xff, + .def = 0x12, + }, }, .fifo_size = 16 * 64, }, { .id = 0x2d, .name = "viwu", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 13, - }, - .la = { - .reg = 0x368, - .shift = 0, - .mask = 0xff, - .def = 0xb2, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 13, + }, + .la = { + .reg = 0x368, + .shift = 0, + .mask = 0xff, + .def = 0xb2, + }, }, .fifo_size = 16 * 64, }, { .id = 0x2e, .name = "viwv", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 14, - }, - .la = { - .reg = 0x368, - .shift = 16, - .mask = 0xff, - .def = 0xb2, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 14, + }, + .la = { + .reg = 0x368, + .shift = 16, + .mask = 0xff, + .def = 0xb2, + }, }, .fifo_size = 16 * 64, }, { .id = 0x2f, .name = "viwy", .swgroup = TEGRA_SWGROUP_VI, - .smmu = { - .reg = 0x22c, - .bit = 15, - }, - .la = { - .reg = 0x36c, - .shift = 0, - .mask = 0xff, - .def = 0x12, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 15, + }, + .la = { + .reg = 0x36c, + .shift = 0, + .mask = 0xff, + .def = 0x12, + }, }, .fifo_size = 16 * 64, }, { .id = 0x30, .name = "g2dw", .swgroup = TEGRA_SWGROUP_G2, - .smmu = { - .reg = 0x22c, - .bit = 16, - }, - .la = { - .reg = 0x30c, - .shift = 16, - .mask = 0xff, - .def = 0x9, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 16, + }, + .la = { + .reg = 0x30c, + .shift = 16, + .mask = 0xff, + .def = 0x9, + }, }, .fifo_size = 16 * 128, }, { .id = 0x31, .name = "afiw", .swgroup = TEGRA_SWGROUP_AFI, - .smmu = { - .reg = 0x22c, - .bit = 17, - }, - .la = { - .reg = 0x2e0, - .shift = 16, - .mask = 0xff, - .def = 0x0c, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 17, + }, + .la = { + .reg = 0x2e0, + .shift = 16, + .mask = 0xff, + .def = 0x0c, + }, }, .fifo_size = 16 * 32, }, { .id = 0x32, .name = "avpcarm7w", .swgroup = TEGRA_SWGROUP_AVPC, - .smmu = { - .reg = 0x22c, - .bit = 18, - }, - .la = { - .reg = 0x2e4, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 18, + }, + .la = { + .reg = 0x2e4, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, .fifo_size = 16 * 2, }, { .id = 0x33, .name = "fdcdwr", .swgroup = TEGRA_SWGROUP_NV, - .smmu = { - .reg = 0x22c, - .bit = 19, - }, - .la = { - .reg = 0x338, - .shift = 16, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 19, + }, + .la = { + .reg = 0x338, + .shift = 16, + .mask = 0xff, + .def = 0x0a, + }, }, .fifo_size = 16 * 48, }, { .id = 0x34, .name = "fdcdwr2", .swgroup = TEGRA_SWGROUP_NV2, - .smmu = { - .reg = 0x22c, - .bit = 20, - }, - .la = { - .reg = 0x340, - .shift = 16, - .mask = 0xff, - .def = 0x0a, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 20, + }, + .la = { + .reg = 0x340, + .shift = 16, + .mask = 0xff, + .def = 0x0a, + }, }, .fifo_size = 16 * 48, }, { .id = 0x35, .name = "hdaw", .swgroup = TEGRA_SWGROUP_HDA, - .smmu = { - .reg = 0x22c, - .bit = 21, - }, - .la = { - .reg = 0x318, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 21, + }, + .la = { + .reg = 0x318, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 16, }, { .id = 0x36, .name = "host1xw", .swgroup = TEGRA_SWGROUP_HC, - .smmu = { - .reg = 0x22c, - .bit = 22, - }, - .la = { - .reg = 0x314, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 22, + }, + .la = { + .reg = 0x314, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, .fifo_size = 16 * 32, }, { .id = 0x37, .name = "ispw", .swgroup = TEGRA_SWGROUP_ISP, - .smmu = { - .reg = 0x22c, - .bit = 23, - }, - .la = { - .reg = 0x31c, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 23, + }, + .la = { + .reg = 0x31c, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 64, }, { .id = 0x38, .name = "mpcorelpw", .swgroup = TEGRA_SWGROUP_MPCORELP, - .la = { - .reg = 0x324, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .la = { + .reg = 0x324, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, .fifo_size = 16 * 24, }, { .id = 0x39, .name = "mpcorew", .swgroup = TEGRA_SWGROUP_MPCORE, - .la = { - .reg = 0x320, - .shift = 16, - .mask = 0xff, - .def = 0x0e, + .regs = { + .la = { + .reg = 0x320, + .shift = 16, + .mask = 0xff, + .def = 0x0e, + }, }, .fifo_size = 16 * 24, }, { .id = 0x3a, .name = "mpecswr", .swgroup = TEGRA_SWGROUP_MPE, - .smmu = { - .reg = 0x22c, - .bit = 26, - }, - .la = { - .reg = 0x330, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 26, + }, + .la = { + .reg = 0x330, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 8, }, { .id = 0x3b, .name = "ppcsahbdmaw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 27, - }, - .la = { - .reg = 0x348, - .shift = 0, - .mask = 0xff, - .def = 0x10, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 27, + }, + .la = { + .reg = 0x348, + .shift = 0, + .mask = 0xff, + .def = 0x10, + }, }, .fifo_size = 16 * 2, }, { .id = 0x3c, .name = "ppcsahbslvw", .swgroup = TEGRA_SWGROUP_PPCS, - .smmu = { - .reg = 0x22c, - .bit = 28, - }, - .la = { - .reg = 0x348, - .shift = 16, - .mask = 0xff, - .def = 0x06, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 28, + }, + .la = { + .reg = 0x348, + .shift = 16, + .mask = 0xff, + .def = 0x06, + }, }, .fifo_size = 16 * 4, }, { .id = 0x3d, .name = "sataw", .swgroup = TEGRA_SWGROUP_SATA, - .smmu = { - .reg = 0x22c, - .bit = 29, - }, - .la = { - .reg = 0x350, - .shift = 16, - .mask = 0xff, - .def = 0x33, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 29, + }, + .la = { + .reg = 0x350, + .shift = 16, + .mask = 0xff, + .def = 0x33, + }, }, .fifo_size = 16 * 32, }, { .id = 0x3e, .name = "vdebsevw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 30, - }, - .la = { - .reg = 0x35c, - .shift = 0, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 30, + }, + .la = { + .reg = 0x35c, + .shift = 0, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 4, }, { .id = 0x3f, .name = "vdedbgw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x22c, - .bit = 31, - }, - .la = { - .reg = 0x35c, - .shift = 16, - .mask = 0xff, - .def = 0xff, + .regs = { + .smmu = { + .reg = 0x22c, + .bit = 31, + }, + .la = { + .reg = 0x35c, + .shift = 16, + .mask = 0xff, + .def = 0xff, + }, }, .fifo_size = 16 * 16, }, { .id = 0x40, .name = "vdembew", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 0, - }, - .la = { - .reg = 0x360, - .shift = 0, - .mask = 0xff, - .def = 0x42, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 0, + }, + .la = { + .reg = 0x360, + .shift = 0, + .mask = 0xff, + .def = 0x42, + }, }, .fifo_size = 16 * 2, }, { .id = 0x41, .name = "vdetpmw", .swgroup = TEGRA_SWGROUP_VDE, - .smmu = { - .reg = 0x230, - .bit = 1, - }, - .la = { - .reg = 0x360, - .shift = 16, - .mask = 0xff, - .def = 0x2a, + .regs = { + .smmu = { + .reg = 0x230, + .bit = 1, + }, + .la = { + .reg = 0x360, + .shift = 16, + .mask = 0xff, + .def = 0x2a, + }, }, .fifo_size = 16 * 16, }, @@ -1089,7 +1221,6 @@ static void tegra30_mc_tune_client_latency(struct tegra_mc *mc, unsigned int bandwidth_mbytes_sec) { u32 arb_tolerance_compensation_nsec, arb_tolerance_compensation_div; - const struct tegra_mc_la *la = &client->la; unsigned int fifo_size = client->fifo_size; u32 arb_nsec, la_ticks, value; @@ -1149,12 +1280,12 @@ static void tegra30_mc_tune_client_latency(struct tegra_mc *mc, * request. */ la_ticks = arb_nsec / mc->tick; - la_ticks = min(la_ticks, la->mask); + la_ticks = min(la_ticks, client->regs.la.mask); - value = mc_readl(mc, la->reg); - value &= ~(la->mask << la->shift); - value |= la_ticks << la->shift; - mc_writel(mc, value, la->reg); + value = mc_readl(mc, client->regs.la.reg); + value &= ~(client->regs.la.mask << client->regs.la.shift); + value |= la_ticks << client->regs.la.shift; + mc_writel(mc, value, client->regs.la.reg); } static int tegra30_mc_icc_set(struct icc_node *src, struct icc_node *dst) @@ -1268,4 +1399,5 @@ const struct tegra_mc_soc tegra30_mc_soc = { .resets = tegra30_mc_resets, .num_resets = ARRAY_SIZE(tegra30_mc_resets), .icc_ops = &tegra30_mc_icc_ops, + .ops = &tegra30_mc_ops, }; diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 0484e9c15c09..572333fadd68 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -331,8 +331,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port, break; data_sz = hdr.PageLength * 4; - ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz, - &page0_dma); + ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, + &page0_dma, GFP_KERNEL); rc = -ENOMEM; if (!ppage0_alloc) break; @@ -367,8 +367,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port, *p_p0 = *ppage0_alloc; /* save data */ *p_pp0++ = p_p0++; /* save addr */ } - pci_free_consistent(ioc->pcidev, data_sz, - (u8 *) ppage0_alloc, page0_dma); + dma_free_coherent(&ioc->pcidev->dev, data_sz, + ppage0_alloc, page0_dma); if (rc != 0) break; @@ -763,7 +763,8 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) data_sz = hdr.PageLength * 4; rc = -ENOMEM; - ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); + ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, + &page0_dma, GFP_KERNEL); if (ppage0_alloc) { try_again: @@ -817,7 +818,8 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) mptfc_display_port_link_speed(ioc, portnum, pp0dest); } - pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); + dma_free_coherent(&ioc->pcidev->dev, data_sz, ppage0_alloc, + page0_dma); } return rc; @@ -904,9 +906,8 @@ start_over: if (data_sz < sizeof(FCPortPage1_t)) data_sz = sizeof(FCPortPage1_t); - page1_alloc = pci_alloc_consistent(ioc->pcidev, - data_sz, - &page1_dma); + page1_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, + &page1_dma, GFP_KERNEL); if (!page1_alloc) return -ENOMEM; } @@ -916,8 +917,8 @@ start_over: data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz; if (hdr.PageLength * 4 > data_sz) { ioc->fc_data.fc_port_page1[portnum].data = NULL; - pci_free_consistent(ioc->pcidev, data_sz, (u8 *) - page1_alloc, page1_dma); + dma_free_coherent(&ioc->pcidev->dev, data_sz, + page1_alloc, page1_dma); goto start_over; } } @@ -932,8 +933,8 @@ start_over: } else { ioc->fc_data.fc_port_page1[portnum].data = NULL; - pci_free_consistent(ioc->pcidev, data_sz, (u8 *) - page1_alloc, page1_dma); + dma_free_coherent(&ioc->pcidev->dev, data_sz, page1_alloc, + page1_dma); } return rc; @@ -1514,10 +1515,10 @@ static void mptfc_remove(struct pci_dev *pdev) for (ii=0; iifacts.NumberOfPorts; ii++) { if (ioc->fc_data.fc_port_page1[ii].data) { - pci_free_consistent(ioc->pcidev, - ioc->fc_data.fc_port_page1[ii].pg_sz, - (u8 *) ioc->fc_data.fc_port_page1[ii].data, - ioc->fc_data.fc_port_page1[ii].dma); + dma_free_coherent(&ioc->pcidev->dev, + ioc->fc_data.fc_port_page1[ii].pg_sz, + ioc->fc_data.fc_port_page1[ii].data, + ioc->fc_data.fc_port_page1[ii].dma); ioc->fc_data.fc_port_page1[ii].data = NULL; } } diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 88f4c215caa6..9890a1532cb0 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -202,7 +202,7 @@ static void mmc_blk_put(struct mmc_blk_data *md) md->usage--; if (md->usage == 0) { int devidx = mmc_get_devidx(md->disk); - blk_put_queue(md->queue.queue); + ida_simple_remove(&mmc_blk_ida, devidx); put_disk(md->disk); kfree(md); @@ -2319,39 +2319,22 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, */ md->read_only = mmc_blk_readonly(card); - md->disk = alloc_disk(perdev_minors); - if (md->disk == NULL) { - ret = -ENOMEM; + md->disk = mmc_init_queue(&md->queue, card); + if (IS_ERR(md->disk)) { + ret = PTR_ERR(md->disk); goto err_kfree; } INIT_LIST_HEAD(&md->part); INIT_LIST_HEAD(&md->rpmbs); md->usage = 1; - - ret = mmc_init_queue(&md->queue, card); - if (ret) - goto err_putdisk; - md->queue.blkdata = md; - /* - * Keep an extra reference to the queue so that we can shutdown the - * queue (i.e. call blk_cleanup_queue()) while there are still - * references to the 'md'. The corresponding blk_put_queue() is in - * mmc_blk_put(). - */ - if (!blk_get_queue(md->queue.queue)) { - mmc_cleanup_queue(&md->queue); - ret = -ENODEV; - goto err_putdisk; - } - md->disk->major = MMC_BLOCK_MAJOR; + md->disk->minors = perdev_minors; md->disk->first_minor = devidx * perdev_minors; md->disk->fops = &mmc_bdops; md->disk->private_data = md; - md->disk->queue = md->queue.queue; md->parent = parent; set_disk_ro(md->disk, md->read_only || default_ro); md->disk->flags = GENHD_FL_EXT_DEVT; @@ -2400,8 +2383,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, return md; - err_putdisk: - put_disk(md->disk); err_kfree: kfree(md); out: diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index d600e0a4a460..cc3261777637 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -424,9 +424,10 @@ static inline bool mmc_merge_capable(struct mmc_host *host) * * Initialise a MMC card request queue. */ -int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) +struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) { struct mmc_host *host = card->host; + struct gendisk *disk; int ret; mq->card = card; @@ -464,26 +465,22 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) ret = blk_mq_alloc_tag_set(&mq->tag_set); if (ret) - return ret; + return ERR_PTR(ret); + - mq->queue = blk_mq_init_queue(&mq->tag_set); - if (IS_ERR(mq->queue)) { - ret = PTR_ERR(mq->queue); - goto free_tag_set; + disk = blk_mq_alloc_disk(&mq->tag_set, mq); + if (IS_ERR(disk)) { + blk_mq_free_tag_set(&mq->tag_set); + return disk; } + mq->queue = disk->queue; if (mmc_host_is_spi(host) && host->use_spi_crc) blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue); - - mq->queue->queuedata = mq; blk_queue_rq_timeout(mq->queue, 60 * HZ); mmc_setup_queue(mq, card); - return 0; - -free_tag_set: - blk_mq_free_tag_set(&mq->tag_set); - return ret; + return disk; } void mmc_queue_suspend(struct mmc_queue *mq) diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 3319d8ab57d0..9ade3bcbb714 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -94,7 +94,7 @@ struct mmc_queue { struct work_struct complete_work; }; -extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *); +struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card); extern void mmc_cleanup_queue(struct mmc_queue *); extern void mmc_queue_suspend(struct mmc_queue *); extern void mmc_queue_resume(struct mmc_queue *); diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index ac2bdba8bb1a..3c0c8eca4d51 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -511,7 +511,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME, ubi->ubi_num); - if (n == UBI_DFS_DIR_LEN) { + if (n > UBI_DFS_DIR_LEN) { /* The array size is too small */ return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index a99e71bc7b3c..771b92019af1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2660,6 +2660,7 @@ int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, case RES_XRCD: err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, vhcr->in_param, &vhcr->out_param); + break; default: break; diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 85c66af9e56d..7ae754eadf22 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "ixp46x_ts.h" diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c index 9ecc395239e9..99d4d9439d05 100644 --- a/drivers/net/ethernet/xscale/ptp_ixp46x.c +++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c @@ -12,9 +12,8 @@ #include #include #include -#include - #include +#include #include "ixp46x_ts.h" diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index f9e2d0114f7a..afd129c056d4 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1516,12 +1516,16 @@ static void virtnet_poll_cleantx(struct receive_queue *rq) return; if (__netif_tx_trylock(txq)) { - free_old_xmit_skbs(sq, true); + do { + virtqueue_disable_cb(sq->vq); + free_old_xmit_skbs(sq, true); + } while (unlikely(!virtqueue_enable_cb_delayed(sq->vq))); + + if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } - - if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) - netif_tx_wake_queue(txq); } static int virtnet_poll(struct napi_struct *napi, int budget) @@ -1592,6 +1596,8 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) struct virtnet_info *vi = sq->vq->vdev->priv; unsigned int index = vq2txq(sq->vq); struct netdev_queue *txq; + int opaque; + bool done; if (unlikely(is_xdp_raw_buffer_queue(vi, index))) { /* We don't need to enable cb for XDP */ @@ -1601,14 +1607,32 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) txq = netdev_get_tx_queue(vi->dev, index); __netif_tx_lock(txq, raw_smp_processor_id()); + virtqueue_disable_cb(sq->vq); free_old_xmit_skbs(sq, true); - __netif_tx_unlock(txq); - - virtqueue_napi_complete(napi, sq->vq, 0); if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) netif_tx_wake_queue(txq); + opaque = virtqueue_enable_cb_prepare(sq->vq); + + done = napi_complete_done(napi, 0); + + if (!done) + virtqueue_disable_cb(sq->vq); + + __netif_tx_unlock(txq); + + if (done) { + if (unlikely(virtqueue_poll(sq->vq, opaque))) { + if (napi_schedule_prep(napi)) { + __netif_tx_lock(txq, raw_smp_processor_id()); + virtqueue_disable_cb(sq->vq); + __netif_tx_unlock(txq); + __napi_schedule(napi); + } + } + } + return 0; } @@ -1670,10 +1694,14 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) bool use_napi = sq->napi.weight; /* Free up any pending old buffers before queueing new ones. */ - free_old_xmit_skbs(sq, false); + do { + if (use_napi) + virtqueue_disable_cb(sq->vq); - if (use_napi && kick) - virtqueue_enable_cb_delayed(sq->vq); + free_old_xmit_skbs(sq, false); + + } while (use_napi && kick && + unlikely(!virtqueue_enable_cb_delayed(sq->vq))); /* timestamp packet in software */ skb_tx_timestamp(skb); @@ -3313,8 +3341,11 @@ static __maybe_unused int virtnet_restore(struct virtio_device *vdev) virtnet_set_queues(vi, vi->curr_queue_pairs); err = virtnet_cpu_notif_add(vi); - if (err) + if (err) { + virtnet_freeze_down(vdev); + remove_vq_common(vi); return err; + } return 0; } diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index e97521138f7e..3c51ab239fb2 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -22,6 +22,7 @@ #include #include #include +#include #define DEBUG_DESC 0 #define DEBUG_RX 0 diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 80c656dcbbac..11779be42186 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -609,6 +609,7 @@ EXPORT_SYMBOL_NS_GPL(nvme_put_ns, NVME_TARGET_PASSTHRU); static inline void nvme_clear_nvme_request(struct request *req) { + nvme_req(req)->status = 0; nvme_req(req)->retries = 0; nvme_req(req)->flags = 0; req->rq_flags |= RQF_DONTPREP; @@ -631,6 +632,8 @@ static inline void nvme_init_request(struct request *req, cmd->common.flags &= ~NVME_CMD_SGL_ALL; req->cmd_flags |= REQ_FAILFAST_DRIVER; + if (req->mq_hctx->type == HCTX_TYPE_POLL) + req->cmd_flags |= REQ_HIPRI; nvme_clear_nvme_request(req); memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd)); } @@ -1029,29 +1032,23 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req) } EXPORT_SYMBOL_GPL(nvme_setup_cmd); -static void nvme_end_sync_rq(struct request *rq, blk_status_t error) +/* + * Return values: + * 0: success + * >0: nvme controller's cqe status response + * <0: kernel error in lieu of controller response + */ +static int nvme_execute_rq(struct gendisk *disk, struct request *rq, + bool at_head) { - struct completion *waiting = rq->end_io_data; + blk_status_t status; - rq->end_io_data = NULL; - complete(waiting); -} - -static void nvme_execute_rq_polled(struct request_queue *q, - struct gendisk *bd_disk, struct request *rq, int at_head) -{ - DECLARE_COMPLETION_ONSTACK(wait); - - WARN_ON_ONCE(!test_bit(QUEUE_FLAG_POLL, &q->queue_flags)); - - rq->cmd_flags |= REQ_HIPRI; - rq->end_io_data = &wait; - blk_execute_rq_nowait(bd_disk, rq, at_head, nvme_end_sync_rq); - - while (!completion_done(&wait)) { - blk_poll(q, request_to_qc_t(rq->mq_hctx, rq), true); - cond_resched(); - } + status = blk_execute_rq(disk, rq, at_head); + if (nvme_req(rq)->flags & NVME_REQ_CANCELLED) + return -EINTR; + if (nvme_req(rq)->status) + return nvme_req(rq)->status; + return blk_status_to_errno(status); } /* @@ -1061,7 +1058,7 @@ static void nvme_execute_rq_polled(struct request_queue *q, int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, union nvme_result *result, void *buffer, unsigned bufflen, unsigned timeout, int qid, int at_head, - blk_mq_req_flags_t flags, bool poll) + blk_mq_req_flags_t flags) { struct request *req; int ret; @@ -1082,16 +1079,9 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, goto out; } - if (poll) - nvme_execute_rq_polled(req->q, NULL, req, at_head); - else - blk_execute_rq(NULL, req, at_head); - if (result) + ret = nvme_execute_rq(NULL, req, at_head); + if (result && ret >= 0) *result = nvme_req(req)->result; - if (nvme_req(req)->flags & NVME_REQ_CANCELLED) - ret = -EINTR; - else - ret = nvme_req(req)->status; out: blk_mq_free_request(req); return ret; @@ -1102,7 +1092,7 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, void *buffer, unsigned bufflen) { return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen, 0, - NVME_QID_ANY, 0, 0, false); + NVME_QID_ANY, 0, 0); } EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd); @@ -1179,18 +1169,21 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) } } -void nvme_execute_passthru_rq(struct request *rq) +int nvme_execute_passthru_rq(struct request *rq) { struct nvme_command *cmd = nvme_req(rq)->cmd; struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl; struct nvme_ns *ns = rq->q->queuedata; struct gendisk *disk = ns ? ns->disk : NULL; u32 effects; + int ret; effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode); - blk_execute_rq(disk, rq, 0); + ret = nvme_execute_rq(disk, rq, false); if (effects) /* nothing to be done for zero cmd effects */ nvme_passthru_end(ctrl, effects); + + return ret; } EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU); @@ -1465,7 +1458,7 @@ static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid, c.features.dword11 = cpu_to_le32(dword11); ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res, - buffer, buflen, 0, NVME_QID_ANY, 0, 0, false); + buffer, buflen, 0, NVME_QID_ANY, 0, 0); if (ret >= 0 && result) *result = le32_to_cpu(res.u32); return ret; @@ -2047,7 +2040,7 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len, cmd.common.cdw11 = cpu_to_le32(len); return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len, 0, - NVME_QID_ANY, 1, 0, false); + NVME_QID_ANY, 1, 0); } EXPORT_SYMBOL_GPL(nvme_sec_submit); #endif /* CONFIG_BLK_SED_OPAL */ diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 1e6a7cc056ca..a5469fd9d4c3 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -154,7 +154,7 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val) cmd.prop_get.offset = cpu_to_le32(off); ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0, 0, - NVME_QID_ANY, 0, 0, false); + NVME_QID_ANY, 0, 0); if (ret >= 0) *val = le64_to_cpu(res.u64); @@ -200,7 +200,7 @@ int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val) cmd.prop_get.offset = cpu_to_le32(off); ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0, 0, - NVME_QID_ANY, 0, 0, false); + NVME_QID_ANY, 0, 0); if (ret >= 0) *val = le64_to_cpu(res.u64); @@ -245,7 +245,7 @@ int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val) cmd.prop_set.value = cpu_to_le64(val); ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, NULL, NULL, 0, 0, - NVME_QID_ANY, 0, 0, false); + NVME_QID_ANY, 0, 0); if (unlikely(ret)) dev_err(ctrl->device, "Property Set error: %d, offset %#x\n", @@ -391,7 +391,7 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl) ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, data, sizeof(*data), 0, NVME_QID_ANY, 1, - BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT, false); + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT); if (ret) { nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32), &cmd, data); @@ -415,7 +415,6 @@ EXPORT_SYMBOL_GPL(nvmf_connect_admin_queue); * @qid: NVMe I/O queue number for the new I/O connection between * host and target (note qid == 0 is illegal as this is * the Admin queue, per NVMe standard). - * @poll: Whether or not to poll for the completion of the connect cmd. * * This function issues a fabrics-protocol connection * of a NVMe I/O queue (via NVMe Fabrics "Connect" command) @@ -427,7 +426,7 @@ EXPORT_SYMBOL_GPL(nvmf_connect_admin_queue); * > 0: NVMe error status code * < 0: Linux errno error code */ -int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll) +int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) { struct nvme_command cmd = { }; struct nvmf_connect_data *data; @@ -453,7 +452,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll) ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res, data, sizeof(*data), 0, qid, 1, - BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT, poll); + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT); if (ret) { nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32), &cmd, data); diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index c31dad69a773..a146cb903869 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -182,7 +182,7 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val); int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val); int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val); int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl); -int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll); +int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid); int nvmf_register_transport(struct nvmf_transport_ops *ops); void nvmf_unregister_transport(struct nvmf_transport_ops *ops); void nvmf_free_options(struct nvmf_ctrl_options *opts); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 95aad3fed571..b08a61ca283f 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2346,7 +2346,7 @@ nvme_fc_connect_io_queues(struct nvme_fc_ctrl *ctrl, u16 qsize) (qsize / 5)); if (ret) break; - ret = nvmf_connect_io_queue(&ctrl->ctrl, i, false); + ret = nvmf_connect_io_queue(&ctrl->ctrl, i); if (ret) break; diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index d93928d1e5bd..305ddd415e45 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -93,11 +93,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, } } - nvme_execute_passthru_rq(req); - if (nvme_req(req)->flags & NVME_REQ_CANCELLED) - ret = -EINTR; - else - ret = nvme_req(req)->status; + ret = nvme_execute_passthru_rq(req); if (result) *result = le64_to_cpu(nvme_req(req)->result.u64); if (meta && !ret && !write) { diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 75420ceacc10..18ef8dd03a90 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -658,7 +658,7 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, union nvme_result *result, void *buffer, unsigned bufflen, unsigned timeout, int qid, int at_head, - blk_mq_req_flags_t flags, bool poll); + blk_mq_req_flags_t flags); int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, unsigned int dword11, void *buffer, size_t buflen, u32 *result); @@ -876,7 +876,7 @@ static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl) u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode); -void nvme_execute_passthru_rq(struct request *rq); +int nvme_execute_passthru_rq(struct request *rq); struct nvme_ctrl *nvme_ctrl_from_file(struct file *file); struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid); void nvme_put_ns(struct nvme_ns *ns); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index a9e70cefd7ed..7f6b3a991501 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -680,11 +680,10 @@ static void nvme_rdma_stop_io_queues(struct nvme_rdma_ctrl *ctrl) static int nvme_rdma_start_queue(struct nvme_rdma_ctrl *ctrl, int idx) { struct nvme_rdma_queue *queue = &ctrl->queues[idx]; - bool poll = nvme_rdma_poll_queue(queue); int ret; if (idx) - ret = nvmf_connect_io_queue(&ctrl->ctrl, idx, poll); + ret = nvmf_connect_io_queue(&ctrl->ctrl, idx); else ret = nvmf_connect_admin_queue(&ctrl->ctrl); diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index c7bd37103cf4..12acfe05cd68 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1574,7 +1574,7 @@ static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx) int ret; if (idx) - ret = nvmf_connect_io_queue(nctrl, idx, false); + ret = nvmf_connect_io_queue(nctrl, idx); else ret = nvmf_connect_admin_queue(nctrl); diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index a5c4a1865026..3a17a7e26bbf 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -337,7 +337,7 @@ static int nvme_loop_connect_io_queues(struct nvme_loop_ctrl *ctrl) int i, ret; for (i = 1; i < ctrl->ctrl.queue_count; i++) { - ret = nvmf_connect_io_queue(&ctrl->ctrl, i, false); + ret = nvmf_connect_io_queue(&ctrl->ctrl, i); if (ret) return ret; set_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[i].flags); diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index fced52de33ce..225cd1ffbe45 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -153,11 +153,10 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w) { struct nvmet_req *req = container_of(w, struct nvmet_req, p.work); struct request *rq = req->p.rq; - u16 status; + int status; - nvme_execute_passthru_rq(rq); + status = nvme_execute_passthru_rq(rq); - status = nvme_req(rq)->status; if (status == NVME_SC_SUCCESS && req->cmd->common.opcode == nvme_admin_identify) { switch (req->cmd->identify.cns) { @@ -168,7 +167,8 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w) nvmet_passthru_override_id_ns(req); break; } - } + } else if (status < 0) + status = NVME_SC_INTERNAL; req->cqe->result = nvme_req(rq)->result; nvmet_req_complete(req, status); diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index d8aceef83284..07ee347ea3f3 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1497,7 +1497,6 @@ static void nvmet_tcp_state_change(struct sock *sk) case TCP_CLOSE_WAIT: case TCP_CLOSE: /* FALLTHRU */ - sk->sk_user_data = NULL; nvmet_tcp_schedule_release_queue(queue); break; default: diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 2f2c8a1729f9..5e1e3796efa4 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -37,6 +37,14 @@ config PCI_FTPCI100 depends on OF default ARCH_GEMINI +config PCI_IXP4XX + bool "Intel IXP4xx PCI controller" + depends on ARM && OF + default ARCH_IXP4XX + help + Say Y here if you want support for the PCI host controller found + in the Intel IXP4xx XScale-based network processor SoC. + config PCI_TEGRA bool "NVIDIA Tegra PCIe controller" depends on ARCH_TEGRA || COMPILE_TEST diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 63e3880a3e87..aaf30b3dcc14 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PCIE_CADENCE) += cadence/ obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o +obj-$(CONFIG_PCI_IXP4XX) += pci-ixp4xx.o obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 254d2570f8c9..30db2d68c17a 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -263,9 +263,12 @@ struct cdns_pcie_ops { * struct cdns_pcie - private data for Cadence PCIe controller drivers * @reg_base: IO mapped register base * @mem_res: start/end offsets in the physical system memory to map PCI accesses + * @dev: PCIe controller * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint. - * @bus: In Root Complex mode, the bus number - * @ops: Platform specific ops to control various inputs from Cadence PCIe + * @phy_count: number of supported PHY devices + * @phy: list of pointers to specific PHY control blocks + * @link: list of pointers to corresponding device link representations + * @ops: Platform-specific ops to control various inputs from Cadence PCIe * wrapper */ struct cdns_pcie { diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 0cf1333c0440..80fc98acf097 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -37,6 +37,7 @@ #define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9) #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10) #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11) +#define IMX8MQ_GPR_PCIE_VREG_BYPASS BIT(12) #define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8) #define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000 @@ -80,6 +81,7 @@ struct imx6_pcie { u32 tx_swing_full; u32 tx_swing_low; struct regulator *vpcie; + struct regulator *vph; void __iomem *phy_base; /* power domain for pcie */ @@ -621,6 +623,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) imx6_pcie_grp_offset(imx6_pcie), IMX8MQ_GPR_PCIE_REF_USE_PAD, IMX8MQ_GPR_PCIE_REF_USE_PAD); + /* + * Regarding the datasheet, the PCIE_VPH is suggested + * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the + * VREG_BYPASS should be cleared to zero. + */ + if (imx6_pcie->vph && + regulator_get_voltage(imx6_pcie->vph) > 3000000) + regmap_update_bits(imx6_pcie->iomuxc_gpr, + imx6_pcie_grp_offset(imx6_pcie), + IMX8MQ_GPR_PCIE_VREG_BYPASS, + 0); break; case IMX7D: regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, @@ -1002,10 +1015,8 @@ static int imx6_pcie_probe(struct platform_device *pdev) return ret; } imx6_pcie->phy_base = devm_ioremap_resource(dev, &res); - if (IS_ERR(imx6_pcie->phy_base)) { - dev_err(dev, "Unable to map PCIe PHY\n"); + if (IS_ERR(imx6_pcie->phy_base)) return PTR_ERR(imx6_pcie->phy_base); - } } dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1130,6 +1141,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) imx6_pcie->vpcie = NULL; } + imx6_pcie->vph = devm_regulator_get_optional(&pdev->dev, "vph"); + if (IS_ERR(imx6_pcie->vph)) { + if (PTR_ERR(imx6_pcie->vph) != -ENODEV) + return PTR_ERR(imx6_pcie->vph); + imx6_pcie->vph = NULL; + } + platform_set_drvdata(pdev, imx6_pcie); ret = imx6_pcie_attach_pd(dev); @@ -1175,6 +1193,7 @@ static const struct imx6_pcie_drvdata drvdata[] = { .variant = IMX6QP, .flags = IMX6_PCIE_FLAG_IMX6_PHY | IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, + .dbi_length = 0x200, }, [IMX7D] = { .variant = IMX7D, diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index f89a7d24ba28..d15cf35fa7f2 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -39,6 +39,10 @@ #define PCIE_APP_IRN_PM_TO_ACK BIT(9) #define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11) #define PCIE_APP_IRN_BW_MGT BIT(12) +#define PCIE_APP_IRN_INTA BIT(13) +#define PCIE_APP_IRN_INTB BIT(14) +#define PCIE_APP_IRN_INTC BIT(15) +#define PCIE_APP_IRN_INTD BIT(16) #define PCIE_APP_IRN_MSG_LTR BIT(18) #define PCIE_APP_IRN_SYS_ERR_RC BIT(29) #define PCIE_APP_INTX_OFST 12 @@ -48,10 +52,8 @@ PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \ PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \ PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \ - (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTA) | \ - (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTB) | \ - (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTC) | \ - (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTD)) + PCIE_APP_IRN_INTA | PCIE_APP_IRN_INTB | \ + PCIE_APP_IRN_INTC | PCIE_APP_IRN_INTD) #define BUS_IATU_OFFSET SZ_256M #define RESET_INTERVAL_MS 100 diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 504669e3afe0..3ec7b29d5dc7 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1826,7 +1826,7 @@ static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq) if (unlikely(irq > 31)) return -EINVAL; - appl_writel(pcie, (1 << irq), APPL_MSI_CTRL_1); + appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1); return 0; } @@ -2214,6 +2214,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) goto fail_host_init; } + dw_pcie_setup_rc(&pcie->pci.pp); + ret = tegra_pcie_dw_start_link(&pcie->pci); if (ret < 0) goto fail_host_init; diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index ee0156921ebc..306950272fd6 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -42,17 +42,6 @@ struct ls_pcie_g4 { int irq; }; -static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off) -{ - return ioread32(pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off); -} - -static inline void ls_pcie_g4_lut_writel(struct ls_pcie_g4 *pcie, - u32 off, u32 val) -{ - iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off); -} - static inline u32 ls_pcie_g4_pf_readl(struct ls_pcie_g4 *pcie, u32 off) { return ioread32(pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off); diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index e3f5e7ab7606..c95ebe808f92 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -57,7 +57,7 @@ #define PIO_COMPLETION_STATUS_UR 1 #define PIO_COMPLETION_STATUS_CRS 2 #define PIO_COMPLETION_STATUS_CA 4 -#define PIO_NON_POSTED_REQ BIT(0) +#define PIO_NON_POSTED_REQ BIT(10) #define PIO_ADDR_LS (PIO_BASE_ADDR + 0x8) #define PIO_ADDR_MS (PIO_BASE_ADDR + 0xc) #define PIO_WR_DATA (PIO_BASE_ADDR + 0x10) @@ -125,6 +125,7 @@ #define LTSSM_MASK 0x3f #define LTSSM_L0 0x10 #define RC_BAR_CONFIG 0x300 +#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44) /* PCIe core controller registers */ #define CTRL_CORE_BASE_ADDR 0x18000 @@ -385,6 +386,16 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) reg |= (IS_RC_MSK << IS_RC_SHIFT); advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); + /* + * Replace incorrect PCI vendor id value 0x1b4b by correct value 0x11ab. + * VENDOR_ID_REG contains vendor id in low 16 bits and subsystem vendor + * id in high 16 bits. Updating this register changes readback value of + * read-only vendor id bits in PCIE_CORE_DEV_ID_REG register. Workaround + * for erratum 4.1: "The value of device and vendor ID is incorrect". + */ + reg = (PCI_VENDOR_ID_MARVELL << 16) | PCI_VENDOR_ID_MARVELL; + advk_writel(pcie, reg, VENDOR_ID_REG); + /* Set Advanced Error Capabilities and Control PF0 register */ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX | PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN | diff --git a/drivers/pci/controller/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c index da3cd216da00..aefef1986201 100644 --- a/drivers/pci/controller/pci-ftpci100.c +++ b/drivers/pci/controller/pci-ftpci100.c @@ -34,12 +34,12 @@ * Special configuration registers directly in the first few words * in I/O space. */ -#define PCI_IOSIZE 0x00 -#define PCI_PROT 0x04 /* AHB protection */ -#define PCI_CTRL 0x08 /* PCI control signal */ -#define PCI_SOFTRST 0x10 /* Soft reset counter and response error enable */ -#define PCI_CONFIG 0x28 /* PCI configuration command register */ -#define PCI_DATA 0x2C +#define FTPCI_IOSIZE 0x00 +#define FTPCI_PROT 0x04 /* AHB protection */ +#define FTPCI_CTRL 0x08 /* PCI control signal */ +#define FTPCI_SOFTRST 0x10 /* Soft reset counter and response error enable */ +#define FTPCI_CONFIG 0x28 /* PCI configuration command register */ +#define FTPCI_DATA 0x2C #define FARADAY_PCI_STATUS_CMD 0x04 /* Status and command */ #define FARADAY_PCI_PMC 0x40 /* Power management control */ @@ -195,9 +195,9 @@ static int faraday_raw_pci_read_config(struct faraday_pci *p, int bus_number, PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | PCI_CONF_ENABLE, - p->base + PCI_CONFIG); + p->base + FTPCI_CONFIG); - *value = readl(p->base + PCI_DATA); + *value = readl(p->base + FTPCI_DATA); if (size == 1) *value = (*value >> (8 * (config & 3))) & 0xFF; @@ -230,17 +230,17 @@ static int faraday_raw_pci_write_config(struct faraday_pci *p, int bus_number, PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | PCI_CONF_ENABLE, - p->base + PCI_CONFIG); + p->base + FTPCI_CONFIG); switch (size) { case 4: - writel(value, p->base + PCI_DATA); + writel(value, p->base + FTPCI_DATA); break; case 2: - writew(value, p->base + PCI_DATA + (config & 3)); + writew(value, p->base + FTPCI_DATA + (config & 3)); break; case 1: - writeb(value, p->base + PCI_DATA + (config & 3)); + writeb(value, p->base + FTPCI_DATA + (config & 3)); break; default: ret = PCIBIOS_BAD_REGISTER_NUMBER; @@ -469,7 +469,7 @@ static int faraday_pci_probe(struct platform_device *pdev) if (!faraday_res_to_memcfg(io->start - win->offset, resource_size(io), &val)) { /* setup I/O space size */ - writel(val, p->base + PCI_IOSIZE); + writel(val, p->base + FTPCI_IOSIZE); } else { dev_err(dev, "illegal IO mem size\n"); return -EINVAL; @@ -477,11 +477,11 @@ static int faraday_pci_probe(struct platform_device *pdev) } /* Setup hostbridge */ - val = readl(p->base + PCI_CTRL); + val = readl(p->base + FTPCI_CTRL); val |= PCI_COMMAND_IO; val |= PCI_COMMAND_MEMORY; val |= PCI_COMMAND_MASTER; - writel(val, p->base + PCI_CTRL); + writel(val, p->base + FTPCI_CTRL); /* Mask and clear all interrupts */ faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); if (variant->cascaded_irq) { diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index bebe3eeebc4e..a53bd8728d0d 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -444,7 +444,6 @@ enum hv_pcibus_state { hv_pcibus_probed, hv_pcibus_installed, hv_pcibus_removing, - hv_pcibus_removed, hv_pcibus_maximum }; @@ -453,7 +452,6 @@ struct hv_pcibus_device { /* Protocol version negotiated with the host */ enum pci_protocol_version_t protocol_version; enum hv_pcibus_state state; - refcount_t remove_lock; struct hv_device *hdev; resource_size_t low_mmio_space; resource_size_t high_mmio_space; @@ -461,7 +459,6 @@ struct hv_pcibus_device { struct resource *low_mmio_res; struct resource *high_mmio_res; struct completion *survey_event; - struct completion remove_event; struct pci_bus *pci_bus; spinlock_t config_lock; /* Avoid two threads writing index page */ spinlock_t device_list_lock; /* Protect lists below */ @@ -593,9 +590,6 @@ static void put_pcichild(struct hv_pci_dev *hpdev) kfree(hpdev); } -static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus); -static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus); - /* * There is no good way to get notified from vmbus_onoffer_rescind(), * so let's use polling here, since this is not a hot path. @@ -2064,10 +2058,8 @@ static void pci_devices_present_work(struct work_struct *work) } spin_unlock_irqrestore(&hbus->device_list_lock, flags); - if (!dr) { - put_hvpcibus(hbus); + if (!dr) return; - } /* First, mark all existing children as reported missing. */ spin_lock_irqsave(&hbus->device_list_lock, flags); @@ -2150,7 +2142,6 @@ static void pci_devices_present_work(struct work_struct *work) break; } - put_hvpcibus(hbus); kfree(dr); } @@ -2191,12 +2182,10 @@ static int hv_pci_start_relations_work(struct hv_pcibus_device *hbus, list_add_tail(&dr->list_entry, &hbus->dr_list); spin_unlock_irqrestore(&hbus->device_list_lock, flags); - if (pending_dr) { + if (pending_dr) kfree(dr_wrk); - } else { - get_hvpcibus(hbus); + else queue_work(hbus->wq, &dr_wrk->wrk); - } return 0; } @@ -2339,8 +2328,6 @@ static void hv_eject_device_work(struct work_struct *work) put_pcichild(hpdev); put_pcichild(hpdev); /* hpdev has been freed. Do not use it any more. */ - - put_hvpcibus(hbus); } /** @@ -2364,7 +2351,6 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev) hpdev->state = hv_pcichild_ejecting; get_pcichild(hpdev); INIT_WORK(&hpdev->wrk, hv_eject_device_work); - get_hvpcibus(hbus); queue_work(hbus->wq, &hpdev->wrk); } @@ -2964,17 +2950,6 @@ static int hv_send_resources_released(struct hv_device *hdev) return 0; } -static void get_hvpcibus(struct hv_pcibus_device *hbus) -{ - refcount_inc(&hbus->remove_lock); -} - -static void put_hvpcibus(struct hv_pcibus_device *hbus) -{ - if (refcount_dec_and_test(&hbus->remove_lock)) - complete(&hbus->remove_event); -} - #define HVPCI_DOM_MAP_SIZE (64 * 1024) static DECLARE_BITMAP(hvpci_dom_map, HVPCI_DOM_MAP_SIZE); @@ -3094,14 +3069,12 @@ static int hv_pci_probe(struct hv_device *hdev, hbus->sysdata.domain = dom; hbus->hdev = hdev; - refcount_set(&hbus->remove_lock, 1); INIT_LIST_HEAD(&hbus->children); INIT_LIST_HEAD(&hbus->dr_list); INIT_LIST_HEAD(&hbus->resources_for_children); spin_lock_init(&hbus->config_lock); spin_lock_init(&hbus->device_list_lock); spin_lock_init(&hbus->retarget_msi_interrupt_lock); - init_completion(&hbus->remove_event); hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0, hbus->sysdata.domain); if (!hbus->wq) { @@ -3243,8 +3216,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs) struct pci_packet teardown_packet; u8 buffer[sizeof(struct pci_message)]; } pkt; - struct hv_dr_state *dr; struct hv_pci_compl comp_pkt; + struct hv_pci_dev *hpdev, *tmp; + unsigned long flags; int ret; /* @@ -3256,9 +3230,16 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs) if (!keep_devs) { /* Delete any children which might still exist. */ - dr = kzalloc(sizeof(*dr), GFP_KERNEL); - if (dr && hv_pci_start_relations_work(hbus, dr)) - kfree(dr); + spin_lock_irqsave(&hbus->device_list_lock, flags); + list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) { + list_del(&hpdev->list_entry); + if (hpdev->pci_slot) + pci_destroy_slot(hpdev->pci_slot); + /* For the two refs got in new_pcichild_device() */ + put_pcichild(hpdev); + put_pcichild(hpdev); + } + spin_unlock_irqrestore(&hbus->device_list_lock, flags); } ret = hv_send_resources_released(hdev); @@ -3301,13 +3282,23 @@ static int hv_pci_remove(struct hv_device *hdev) hbus = hv_get_drvdata(hdev); if (hbus->state == hv_pcibus_installed) { + tasklet_disable(&hdev->channel->callback_event); + hbus->state = hv_pcibus_removing; + tasklet_enable(&hdev->channel->callback_event); + destroy_workqueue(hbus->wq); + hbus->wq = NULL; + /* + * At this point, no work is running or can be scheduled + * on hbus-wq. We can't race with hv_pci_devices_present() + * or hv_pci_eject_device(), it's safe to proceed. + */ + /* Remove the bus from PCI's point of view. */ pci_lock_rescan_remove(); pci_stop_root_bus(hbus->pci_bus); hv_pci_remove_slots(hbus); pci_remove_root_bus(hbus->pci_bus); pci_unlock_rescan_remove(); - hbus->state = hv_pcibus_removed; } ret = hv_pci_bus_exit(hdev, false); @@ -3320,9 +3311,6 @@ static int hv_pci_remove(struct hv_device *hdev) hv_pci_free_bridge_windows(hbus); irq_domain_remove(hbus->irq_domain); irq_domain_free_fwnode(hbus->sysdata.fwnode); - put_hvpcibus(hbus); - wait_for_completion(&hbus->remove_event); - destroy_workqueue(hbus->wq); hv_put_dom_num(hbus->sysdata.domain); diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c new file mode 100644 index 000000000000..896a45b24236 --- /dev/null +++ b/drivers/pci/controller/pci-ixp4xx.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Intel IXP4xx PCI host controller + * + * Copyright (C) 2017 Linus Walleij + * + * Based on the IXP4xx arch/arm/mach-ixp4xx/common-pci.c driver + * Copyright (C) 2002 Intel Corporation + * Copyright (C) 2003 Greg Ungerer + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * Copyright (C) 2005 Deepak Saxena + * Copyright (C) 2005 Alessandro Zummo + * + * TODO: + * - Test IO-space access + * - DMA support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets */ +#define IXP4XX_PCI_NP_AD 0x00 +#define IXP4XX_PCI_NP_CBE 0x04 +#define IXP4XX_PCI_NP_WDATA 0x08 +#define IXP4XX_PCI_NP_RDATA 0x0c +#define IXP4XX_PCI_CRP_AD_CBE 0x10 +#define IXP4XX_PCI_CRP_WDATA 0x14 +#define IXP4XX_PCI_CRP_RDATA 0x18 +#define IXP4XX_PCI_CSR 0x1c +#define IXP4XX_PCI_ISR 0x20 +#define IXP4XX_PCI_INTEN 0x24 +#define IXP4XX_PCI_DMACTRL 0x28 +#define IXP4XX_PCI_AHBMEMBASE 0x2c +#define IXP4XX_PCI_AHBIOBASE 0x30 +#define IXP4XX_PCI_PCIMEMBASE 0x34 +#define IXP4XX_PCI_AHBDOORBELL 0x38 +#define IXP4XX_PCI_PCIDOORBELL 0x3c +#define IXP4XX_PCI_ATPDMA0_AHBADDR 0x40 +#define IXP4XX_PCI_ATPDMA0_PCIADDR 0x44 +#define IXP4XX_PCI_ATPDMA0_LENADDR 0x48 +#define IXP4XX_PCI_ATPDMA1_AHBADDR 0x4c +#define IXP4XX_PCI_ATPDMA1_PCIADDR 0x50 +#define IXP4XX_PCI_ATPDMA1_LENADDR 0x54 + +/* CSR bit definitions */ +#define IXP4XX_PCI_CSR_HOST BIT(0) +#define IXP4XX_PCI_CSR_ARBEN BIT(1) +#define IXP4XX_PCI_CSR_ADS BIT(2) +#define IXP4XX_PCI_CSR_PDS BIT(3) +#define IXP4XX_PCI_CSR_ABE BIT(4) +#define IXP4XX_PCI_CSR_DBT BIT(5) +#define IXP4XX_PCI_CSR_ASE BIT(8) +#define IXP4XX_PCI_CSR_IC BIT(15) +#define IXP4XX_PCI_CSR_PRST BIT(16) + +/* ISR (Interrupt status) Register bit definitions */ +#define IXP4XX_PCI_ISR_PSE BIT(0) +#define IXP4XX_PCI_ISR_PFE BIT(1) +#define IXP4XX_PCI_ISR_PPE BIT(2) +#define IXP4XX_PCI_ISR_AHBE BIT(3) +#define IXP4XX_PCI_ISR_APDC BIT(4) +#define IXP4XX_PCI_ISR_PADC BIT(5) +#define IXP4XX_PCI_ISR_ADB BIT(6) +#define IXP4XX_PCI_ISR_PDB BIT(7) + +/* INTEN (Interrupt Enable) Register bit definitions */ +#define IXP4XX_PCI_INTEN_PSE BIT(0) +#define IXP4XX_PCI_INTEN_PFE BIT(1) +#define IXP4XX_PCI_INTEN_PPE BIT(2) +#define IXP4XX_PCI_INTEN_AHBE BIT(3) +#define IXP4XX_PCI_INTEN_APDC BIT(4) +#define IXP4XX_PCI_INTEN_PADC BIT(5) +#define IXP4XX_PCI_INTEN_ADB BIT(6) +#define IXP4XX_PCI_INTEN_PDB BIT(7) + +/* Shift value for byte enable on NP cmd/byte enable register */ +#define IXP4XX_PCI_NP_CBE_BESL 4 + +/* PCI commands supported by NP access unit */ +#define NP_CMD_IOREAD 0x2 +#define NP_CMD_IOWRITE 0x3 +#define NP_CMD_CONFIGREAD 0xa +#define NP_CMD_CONFIGWRITE 0xb +#define NP_CMD_MEMREAD 0x6 +#define NP_CMD_MEMWRITE 0x7 + +/* Constants for CRP access into local config space */ +#define CRP_AD_CBE_BESL 20 +#define CRP_AD_CBE_WRITE 0x00010000 + +/* Special PCI configuration space registers for this controller */ +#define IXP4XX_PCI_RTOTTO 0x40 + +struct ixp4xx_pci { + struct device *dev; + void __iomem *base; + bool errata_hammer; + bool host_mode; +}; + +/* + * The IXP4xx has a peculiar address bus that will change the + * byte order on SoC peripherals depending on whether the device + * operates in big-endian or little-endian mode. That means that + * readl() and writel() that always use little-endian access + * will not work for SoC peripherals such as the PCI controller + * when used in big-endian mode. The accesses to the individual + * PCI devices on the other hand, are always little-endian and + * can use readl() and writel(). + * + * For local AHB bus access we need to use __raw_[readl|writel]() + * to make sure that we access the SoC devices in the CPU native + * endianness. + */ +static inline u32 ixp4xx_readl(struct ixp4xx_pci *p, u32 reg) +{ + return __raw_readl(p->base + reg); +} + +static inline void ixp4xx_writel(struct ixp4xx_pci *p, u32 reg, u32 val) +{ + __raw_writel(val, p->base + reg); +} + +static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p) +{ + u32 isr = ixp4xx_readl(p, IXP4XX_PCI_ISR); + + if (isr & IXP4XX_PCI_ISR_PFE) { + /* Make sure the master abort bit is reset */ + ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE); + dev_dbg(p->dev, "master abort detected\n"); + return -EINVAL; + } + + return 0; +} + +static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data) +{ + ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); + + if (p->errata_hammer) { + int i; + + /* + * PCI workaround - only works if NP PCI space reads have + * no side effects. Hammer the register and read twice 8 + * times. last one will be good. + */ + for (i = 0; i < 8; i++) { + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + } + } else { + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + } + + return ixp4xx_pci_check_master_abort(p); +} + +static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data) +{ + ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); + + /* Set up the write */ + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + + /* Execute the write by writing to NP_WDATA */ + ixp4xx_writel(p, IXP4XX_PCI_NP_WDATA, data); + + return ixp4xx_pci_check_master_abort(p); +} + +static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where) +{ + /* Root bus is always 0 in this hardware */ + if (bus_num == 0) { + /* type 0 */ + return BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | + (where & ~3); + } else { + /* type 1 */ + return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | + ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; + } +} + +/* + * CRP functions are "Controller Configuration Port" accesses + * initiated from within this driver itself to read/write PCI + * control information in the config space. + */ +static u32 ixp4xx_crp_byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int ixp4xx_crp_read_config(struct ixp4xx_pci *p, int where, int size, + u32 *value) +{ + u32 n, cmd, val; + + n = where % 4; + cmd = where & ~3; + + dev_dbg(p->dev, "%s from %d size %d cmd %08x\n", + __func__, where, size, cmd); + + ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd); + val = ixp4xx_readl(p, IXP4XX_PCI_CRP_RDATA); + + val >>= (8*n); + switch (size) { + case 1: + val &= U8_MAX; + dev_dbg(p->dev, "%s read byte %02x\n", __func__, val); + break; + case 2: + val &= U16_MAX; + dev_dbg(p->dev, "%s read word %04x\n", __func__, val); + break; + case 4: + val &= U32_MAX; + dev_dbg(p->dev, "%s read long %08x\n", __func__, val); + break; + default: + /* Should not happen */ + dev_err(p->dev, "%s illegal size\n", __func__); + return PCIBIOS_DEVICE_NOT_FOUND; + } + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int ixp4xx_crp_write_config(struct ixp4xx_pci *p, int where, int size, + u32 value) +{ + u32 n, cmd, val; + + n = where % 4; + cmd = ixp4xx_crp_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + cmd |= where & ~3; + cmd |= CRP_AD_CBE_WRITE; + + val = value << (8*n); + + dev_dbg(p->dev, "%s to %d size %d cmd %08x val %08x\n", + __func__, where, size, cmd, val); + + ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd); + ixp4xx_writel(p, IXP4XX_PCI_CRP_WDATA, val); + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Then follows the functions that read and write from the common PCI + * configuration space. + */ +static u32 ixp4xx_byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << 4; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << 4; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + struct ixp4xx_pci *p = bus->sysdata; + u32 n, addr, val, cmd; + u8 bus_num = bus->number; + int ret; + + *value = 0xffffffff; + n = where % 4; + cmd = ixp4xx_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + cmd |= NP_CMD_CONFIGREAD; + dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n", + where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); + + ret = ixp4xx_pci_read(p, addr, cmd, &val); + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + val >>= (8*n); + switch (size) { + case 1: + val &= U8_MAX; + dev_dbg(p->dev, "%s read byte %02x\n", __func__, val); + break; + case 2: + val &= U16_MAX; + dev_dbg(p->dev, "%s read word %04x\n", __func__, val); + break; + case 4: + val &= U32_MAX; + dev_dbg(p->dev, "%s read long %08x\n", __func__, val); + break; + default: + /* Should not happen */ + dev_err(p->dev, "%s illegal size\n", __func__); + return PCIBIOS_DEVICE_NOT_FOUND; + } + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + struct ixp4xx_pci *p = bus->sysdata; + u32 n, addr, val, cmd; + u8 bus_num = bus->number; + int ret; + + n = where % 4; + cmd = ixp4xx_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + cmd |= NP_CMD_CONFIGWRITE; + val = value << (8*n); + + dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n", + value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); + + ret = ixp4xx_pci_write(p, addr, cmd, val); + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ixp4xx_pci_ops = { + .read = ixp4xx_pci_read_config, + .write = ixp4xx_pci_write_config, +}; + +static u32 ixp4xx_pci_addr_to_64mconf(phys_addr_t addr) +{ + u8 base; + + base = ((addr & 0xff000000) >> 24); + return (base << 24) | ((base + 1) << 16) + | ((base + 2) << 8) | (base + 3); +} + +static int ixp4xx_pci_parse_map_ranges(struct ixp4xx_pci *p) +{ + struct device *dev = p->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p); + struct resource_entry *win; + struct resource *res; + phys_addr_t addr; + + win = resource_list_first_type(&bridge->windows, IORESOURCE_MEM); + if (win) { + u32 pcimembase; + + res = win->res; + addr = res->start - win->offset; + + if (res->flags & IORESOURCE_PREFETCH) + res->name = "IXP4xx PCI PRE-MEM"; + else + res->name = "IXP4xx PCI NON-PRE-MEM"; + + dev_dbg(dev, "%s window %pR, bus addr %pa\n", + res->name, res, &addr); + if (resource_size(res) != SZ_64M) { + dev_err(dev, "memory range is not 64MB\n"); + return -EINVAL; + } + + pcimembase = ixp4xx_pci_addr_to_64mconf(addr); + /* Commit configuration */ + ixp4xx_writel(p, IXP4XX_PCI_PCIMEMBASE, pcimembase); + } else { + dev_err(dev, "no AHB memory mapping defined\n"); + } + + win = resource_list_first_type(&bridge->windows, IORESOURCE_IO); + if (win) { + res = win->res; + + addr = pci_pio_to_address(res->start); + if (addr & 0xff) { + dev_err(dev, "IO mem at uneven address: %pa\n", &addr); + return -EINVAL; + } + + res->name = "IXP4xx PCI IO MEM"; + /* + * Setup I/O space location for PCI->AHB access, the + * upper 24 bits of the address goes into the lower + * 24 bits of this register. + */ + ixp4xx_writel(p, IXP4XX_PCI_AHBIOBASE, (addr >> 8)); + } else { + dev_info(dev, "no IO space AHB memory mapping defined\n"); + } + + return 0; +} + +static int ixp4xx_pci_parse_map_dma_ranges(struct ixp4xx_pci *p) +{ + struct device *dev = p->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p); + struct resource_entry *win; + struct resource *res; + phys_addr_t addr; + u32 ahbmembase; + + win = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); + if (win) { + res = win->res; + addr = res->start - win->offset; + + if (resource_size(res) != SZ_64M) { + dev_err(dev, "DMA memory range is not 64MB\n"); + return -EINVAL; + } + + dev_dbg(dev, "DMA MEM BASE: %pa\n", &addr); + /* + * 4 PCI-to-AHB windows of 16 MB each, write the 8 high bits + * into each byte of the PCI_AHBMEMBASE register. + */ + ahbmembase = ixp4xx_pci_addr_to_64mconf(addr); + /* Commit AHB membase */ + ixp4xx_writel(p, IXP4XX_PCI_AHBMEMBASE, ahbmembase); + } else { + dev_err(dev, "no DMA memory range defined\n"); + } + + return 0; +} + +/* Only used to get context for abort handling */ +static struct ixp4xx_pci *ixp4xx_pci_abort_singleton; + +static int ixp4xx_pci_abort_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + struct ixp4xx_pci *p = ixp4xx_pci_abort_singleton; + u32 isr, status; + int ret; + + isr = ixp4xx_readl(p, IXP4XX_PCI_ISR); + ret = ixp4xx_crp_read_config(p, PCI_STATUS, 2, &status); + if (ret) { + dev_err(p->dev, "unable to read abort status\n"); + return -EINVAL; + } + + dev_err(p->dev, + "PCI: abort_handler addr = %#lx, isr = %#x, status = %#x\n", + addr, isr, status); + + /* Make sure the Master Abort bit is reset */ + ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE); + status |= PCI_STATUS_REC_MASTER_ABORT; + ret = ixp4xx_crp_write_config(p, PCI_STATUS, 2, status); + if (ret) + dev_err(p->dev, "unable to clear abort status bit\n"); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) { + dev_err(p->dev, "imprecise abort\n"); + regs->ARM_pc += 4; + } + + return 0; +} + +static int __init ixp4xx_pci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct ixp4xx_pci *p; + struct pci_host_bridge *host; + int ret; + u32 val; + phys_addr_t addr; + u32 basereg[4] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + }; + int i; + + host = devm_pci_alloc_host_bridge(dev, sizeof(*p)); + if (!host) + return -ENOMEM; + + host->ops = &ixp4xx_pci_ops; + p = pci_host_bridge_priv(host); + host->sysdata = p; + p->dev = dev; + dev_set_drvdata(dev, p); + + /* + * Set up quirk for erratic behaviour in the 42x variant + * when accessing config space. + */ + if (of_device_is_compatible(np, "intel,ixp42x-pci")) { + p->errata_hammer = true; + dev_info(dev, "activate hammering errata\n"); + } + + p->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(p->base)) + return PTR_ERR(p->base); + + val = ixp4xx_readl(p, IXP4XX_PCI_CSR); + p->host_mode = !!(val & IXP4XX_PCI_CSR_HOST); + dev_info(dev, "controller is in %s mode\n", + p->host_mode ? "host" : "option"); + + /* Hook in our fault handler for PCI errors */ + ixp4xx_pci_abort_singleton = p; + hook_fault_code(16+6, ixp4xx_pci_abort_handler, SIGBUS, 0, + "imprecise external abort"); + + ret = ixp4xx_pci_parse_map_ranges(p); + if (ret) + return ret; + + ret = ixp4xx_pci_parse_map_dma_ranges(p); + if (ret) + return ret; + + /* This is only configured in host mode */ + if (p->host_mode) { + addr = __pa(PAGE_OFFSET); + /* This is a noop (0x00) but explains what is going on */ + addr |= PCI_BASE_ADDRESS_SPACE_MEMORY; + + for (i = 0; i < 4; i++) { + /* Write this directly into the config space */ + ret = ixp4xx_crp_write_config(p, basereg[i], 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_%d\n", i); + else + dev_info(dev, "set PCI_BASE_ADDR_%d to %pa\n", i, &addr); + addr += SZ_16M; + } + + /* + * Enable CSR window at 64 MiB to allow PCI masters to continue + * prefetching past the 64 MiB boundary, if all AHB to PCI + * windows are consecutive. + */ + ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_4, 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_4\n"); + else + dev_info(dev, "set PCI_BASE_ADDR_4 to %pa\n", &addr); + + /* + * Put the IO memory window at the very end of physical memory + * at 0xfffffc00. This is when the system is trying to access IO + * memory over AHB. + */ + addr = 0xfffffc00; + addr |= PCI_BASE_ADDRESS_SPACE_IO; + ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_5, 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_5\n"); + else + dev_info(dev, "set PCI_BASE_ADDR_5 to %pa\n", &addr); + + /* + * Retry timeout to 0x80 + * Transfer ready timeout to 0xff + */ + ret = ixp4xx_crp_write_config(p, IXP4XX_PCI_RTOTTO, 4, + 0x000080ff); + if (ret) + dev_err(dev, "failed to set up TRDY limit\n"); + else + dev_info(dev, "set TRDY limit to 0x80ff\n"); + } + + /* Clear interrupts */ + val = IXP4XX_PCI_ISR_PSE | IXP4XX_PCI_ISR_PFE | IXP4XX_PCI_ISR_PPE | IXP4XX_PCI_ISR_AHBE; + ixp4xx_writel(p, IXP4XX_PCI_ISR, val); + + /* + * Set Initialize Complete in PCI Control Register: allow IXP4XX to + * generate PCI configuration cycles. Specify that the AHB bus is + * operating in big-endian mode. Set up byte lane swapping between + * little-endian PCI and the big-endian AHB bus. + */ + val = IXP4XX_PCI_CSR_IC | IXP4XX_PCI_CSR_ABE; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + val |= (IXP4XX_PCI_CSR_PDS | IXP4XX_PCI_CSR_ADS); + ixp4xx_writel(p, IXP4XX_PCI_CSR, val); + + ret = ixp4xx_crp_write_config(p, PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + if (ret) + dev_err(dev, "unable to initialize master and command memory\n"); + else + dev_info(dev, "initialized as master\n"); + + pci_host_probe(host); + + return 0; +} + +static const struct of_device_id ixp4xx_pci_of_match[] = { + { + .compatible = "intel,ixp42x-pci", + }, + { + .compatible = "intel,ixp43x-pci", + }, + {}, +}; + +/* + * This driver needs to be a builtin module with suppressed bind + * attributes since the probe() is initializing a hard exception + * handler and this can only be done from __init-tagged code + * sections. This module cannot be removed and inserted at all. + */ +static struct platform_driver ixp4xx_pci_driver = { + .driver = { + .name = "ixp4xx-pci", + .suppress_bind_attrs = true, + .of_match_table = ixp4xx_pci_of_match, + }, +}; +builtin_platform_driver_probe(ixp4xx_pci_driver, ixp4xx_pci_probe); diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index 8069bd9232d4..c979229a6d0d 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -2539,6 +2539,7 @@ static const struct of_device_id tegra_pcie_of_match[] = { { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos) { diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index 7f503dd4ff81..e64536047b65 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ -/** +/* * APM X-Gene PCIe Driver * * Copyright (c) 2014 Applied Micro Circuits Corporation. @@ -485,7 +485,7 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, { void __iomem *cfg_base = port->cfg_base; struct device *dev = port->dev; - void *bar_addr; + void __iomem *bar_addr; u32 pim_reg; u64 cpu_addr = entry->res->start; u64 pci_addr = cpu_addr - entry->offset; diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index eede4e8f3f75..35a82124a126 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -49,7 +49,7 @@ enum iproc_msi_reg { struct iproc_msi; /** - * iProc MSI group + * struct iproc_msi_grp - iProc MSI group * * One MSI group is allocated per GIC interrupt, serviced by one iProc MSI * event queue. @@ -65,7 +65,7 @@ struct iproc_msi_grp { }; /** - * iProc event queue based MSI + * struct iproc_msi - iProc event queue based MSI * * Only meant to be used on platforms without MSI support integrated into the * GIC. @@ -171,7 +171,7 @@ static struct irq_chip iproc_msi_irq_chip = { static struct msi_domain_info iproc_msi_domain_info = { .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, + MSI_FLAG_PCI_MSIX, .chip = &iproc_msi_irq_chip, }; @@ -250,20 +250,23 @@ static int iproc_msi_irq_domain_alloc(struct irq_domain *domain, struct iproc_msi *msi = domain->host_data; int hwirq, i; + if (msi->nr_cpus > 1 && nr_irqs > 1) + return -EINVAL; + mutex_lock(&msi->bitmap_lock); - /* Allocate 'nr_cpus' number of MSI vectors each time */ - hwirq = bitmap_find_next_zero_area(msi->bitmap, msi->nr_msi_vecs, 0, - msi->nr_cpus, 0); - if (hwirq < msi->nr_msi_vecs) { - bitmap_set(msi->bitmap, hwirq, msi->nr_cpus); - } else { - mutex_unlock(&msi->bitmap_lock); - return -ENOSPC; - } + /* + * Allocate 'nr_irqs' multiplied by 'nr_cpus' number of MSI vectors + * each time + */ + hwirq = bitmap_find_free_region(msi->bitmap, msi->nr_msi_vecs, + order_base_2(msi->nr_cpus * nr_irqs)); mutex_unlock(&msi->bitmap_lock); + if (hwirq < 0) + return -ENOSPC; + for (i = 0; i < nr_irqs; i++) { irq_domain_set_info(domain, virq + i, hwirq + i, &iproc_msi_bottom_irq_chip, @@ -284,7 +287,8 @@ static void iproc_msi_irq_domain_free(struct irq_domain *domain, mutex_lock(&msi->bitmap_lock); hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq); - bitmap_clear(msi->bitmap, hwirq, msi->nr_cpus); + bitmap_release_region(msi->bitmap, hwirq, + order_base_2(msi->nr_cpus * nr_irqs)); mutex_unlock(&msi->bitmap_lock); @@ -539,6 +543,9 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) mutex_init(&msi->bitmap_lock); msi->nr_cpus = num_possible_cpus(); + if (msi->nr_cpus == 1) + iproc_msi_domain_info.flags |= MSI_FLAG_MULTI_PCI_MSI; + msi->nr_irqs = of_irq_count(node); if (!msi->nr_irqs) { dev_err(pcie->dev, "found no MSI GIC interrupt\n"); diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 02e52f698eeb..30ac5fbefbbf 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -89,8 +89,8 @@ #define IPROC_PCIE_REG_INVALID 0xffff /** - * iProc PCIe outbound mapping controller specific parameters - * + * struct iproc_pcie_ob_map - iProc PCIe outbound mapping controller-specific + * parameters * @window_sizes: list of supported outbound mapping window sizes in MB * @nr_sizes: number of supported outbound mapping window sizes */ @@ -136,22 +136,20 @@ static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = { }; /** - * iProc PCIe inbound mapping type + * enum iproc_pcie_ib_map_type - iProc PCIe inbound mapping type + * @IPROC_PCIE_IB_MAP_MEM: DDR memory + * @IPROC_PCIE_IB_MAP_IO: device I/O memory + * @IPROC_PCIE_IB_MAP_INVALID: invalid or unused */ enum iproc_pcie_ib_map_type { - /* for DDR memory */ IPROC_PCIE_IB_MAP_MEM = 0, - - /* for device I/O memory */ IPROC_PCIE_IB_MAP_IO, - - /* invalid or unused */ IPROC_PCIE_IB_MAP_INVALID }; /** - * iProc PCIe inbound mapping controller specific parameters - * + * struct iproc_pcie_ib_map - iProc PCIe inbound mapping controller-specific + * parameters * @type: inbound mapping region type * @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or * SZ_1G @@ -437,7 +435,7 @@ static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie, writel(val, pcie->base + offset); } -/** +/* * APB error forwarding can be disabled during access of configuration * registers of the endpoint device, to prevent unsupported requests * (typically seen during enumeration with multi-function devices) from @@ -619,7 +617,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } -/** +/* * Note access to the configuration registers are protected at the higher layer * by 'pci_lock' in drivers/pci/access.c */ @@ -897,7 +895,7 @@ static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx, return 0; } -/** +/* * Some iProc SoCs require the SW to configure the outbound address mapping * * Outbound address translation: diff --git a/drivers/pci/controller/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h index c2676e442f55..dcca315897c8 100644 --- a/drivers/pci/controller/pcie-iproc.h +++ b/drivers/pci/controller/pcie-iproc.h @@ -7,7 +7,13 @@ #define _PCIE_IPROC_H /** - * iProc PCIe interface type + * enum iproc_pcie_type - iProc PCIe interface type + * @IPROC_PCIE_PAXB_BCMA: BCMA-based host controllers + * @IPROC_PCIE_PAXB: PAXB-based host controllers for + * NS, NSP, Cygnus, NS2, and Pegasus SOCs + * @IPROC_PCIE_PAXB_V2: PAXB-based host controllers for Stingray SoCs + * @IPROC_PCIE_PAXC: PAXC-based host controllers + * @IPROC_PCIE_PAXC_V2: PAXC-based host controllers (second generation) * * PAXB is the wrapper used in root complex that can be connected to an * external endpoint device. @@ -24,7 +30,7 @@ enum iproc_pcie_type { }; /** - * iProc PCIe outbound mapping + * struct iproc_pcie_ob - iProc PCIe outbound mapping * @axi_offset: offset from the AXI address to the internal address used by * the iProc PCIe core * @nr_windows: total number of supported outbound mapping windows @@ -35,7 +41,7 @@ struct iproc_pcie_ob { }; /** - * iProc PCIe inbound mapping + * struct iproc_pcie_ib - iProc PCIe inbound mapping * @nr_regions: total number of supported inbound mapping regions */ struct iproc_pcie_ib { @@ -47,13 +53,13 @@ struct iproc_pcie_ib_map; struct iproc_msi; /** - * iProc PCIe device - * + * struct iproc_pcie - iProc PCIe device * @dev: pointer to device data structure * @type: iProc PCIe interface type * @reg_offsets: register offsets * @base: PCIe host controller I/O register base * @base_addr: PCIe host controller register base physical address + * @mem: host bridge memory window resource * @phy: optional PHY device that controls the Serdes * @map_irq: function callback to map interrupts * @ep_is_internal: indicates an internal emulated endpoint device is connected diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 3c5b97716d40..f3aeb8d4eaca 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -1012,6 +1012,7 @@ static const struct of_device_id mtk_pcie_of_match[] = { { .compatible = "mediatek,mt8192-pcie" }, {}, }; +MODULE_DEVICE_TABLE(of, mtk_pcie_of_match); static struct platform_driver mtk_pcie_driver = { .probe = mtk_pcie_probe, diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 62a042e75d9a..25bee693834f 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -991,10 +991,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "subsys"); if (regs) { pcie->base = devm_ioremap_resource(dev, regs); - if (IS_ERR(pcie->base)) { - dev_err(dev, "failed to map shared register\n"); + if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); - } } pcie->free_ck = devm_clk_get(dev, "free_ck"); diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 89c68c56d93b..fdab8202ae5d 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -341,7 +341,7 @@ static struct event_map local_status_to_event[] = { LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_SYS_ERR), }; -struct { +static struct { u32 base; u32 offset; u32 mask; diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index f1d08a1b1591..78d04ac29cd5 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -592,10 +592,6 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip) if (err) return err; - err = rockchip_pcie_setup_irq(rockchip); - if (err) - return err; - rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v"); if (IS_ERR(rockchip->vpcie12v)) { if (PTR_ERR(rockchip->vpcie12v) != -ENODEV) @@ -973,8 +969,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (err) goto err_vpcie; - rockchip_pcie_enable_interrupts(rockchip); - err = rockchip_pcie_init_irq_domain(rockchip); if (err < 0) goto err_deinit_port; @@ -992,6 +986,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev) bridge->sysdata = rockchip; bridge->ops = &rockchip_pcie_ops; + err = rockchip_pcie_setup_irq(rockchip); + if (err) + goto err_remove_irq_domain; + + rockchip_pcie_enable_interrupts(rockchip); + err = pci_host_probe(bridge); if (err < 0) goto err_remove_irq_domain; diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index d2a1920bb055..1c40d2506aef 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -32,7 +32,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, struct pci_config_window *cfg; unsigned int bus_range, bus_range_max, bsz; struct resource *conflict; - int i, err; + int err; if (busr->start > busr->end) return ERR_PTR(-EINVAL); @@ -50,6 +50,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, cfg->busr.start = busr->start; cfg->busr.end = busr->end; cfg->busr.flags = IORESOURCE_BUS; + cfg->bus_shift = bus_shift; bus_range = resource_size(&cfg->busr); bus_range_max = resource_size(cfgres) >> bus_shift; if (bus_range > bus_range_max) { @@ -77,13 +78,6 @@ struct pci_config_window *pci_ecam_create(struct device *dev, cfg->winp = kcalloc(bus_range, sizeof(*cfg->winp), GFP_KERNEL); if (!cfg->winp) goto err_exit_malloc; - for (i = 0; i < bus_range; i++) { - cfg->winp[i] = - pci_remap_cfgspace(cfgres->start + i * bsz, - bsz); - if (!cfg->winp[i]) - goto err_exit_iomap; - } } else { cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz); if (!cfg->win) @@ -129,6 +123,44 @@ void pci_ecam_free(struct pci_config_window *cfg) } EXPORT_SYMBOL_GPL(pci_ecam_free); +static int pci_ecam_add_bus(struct pci_bus *bus) +{ + struct pci_config_window *cfg = bus->sysdata; + unsigned int bsz = 1 << cfg->bus_shift; + unsigned int busn = bus->number; + phys_addr_t start; + + if (!per_bus_mapping) + return 0; + + if (busn < cfg->busr.start || busn > cfg->busr.end) + return -EINVAL; + + busn -= cfg->busr.start; + start = cfg->res.start + busn * bsz; + + cfg->winp[busn] = pci_remap_cfgspace(start, bsz); + if (!cfg->winp[busn]) + return -ENOMEM; + + return 0; +} + +static void pci_ecam_remove_bus(struct pci_bus *bus) +{ + struct pci_config_window *cfg = bus->sysdata; + unsigned int busn = bus->number; + + if (!per_bus_mapping || busn < cfg->busr.start || busn > cfg->busr.end) + return; + + busn -= cfg->busr.start; + if (cfg->winp[busn]) { + iounmap(cfg->winp[busn]); + cfg->winp[busn] = NULL; + } +} + /* * Function to implement the pci_ops ->map_bus method */ @@ -167,6 +199,8 @@ EXPORT_SYMBOL_GPL(pci_ecam_map_bus); /* ECAM ops */ const struct pci_ecam_ops pci_generic_ecam_ops = { .pci_ops = { + .add_bus = pci_ecam_add_bus, + .remove_bus = pci_ecam_remove_bus, .map_bus = pci_ecam_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, @@ -178,6 +212,8 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops); /* ECAM ops for 32-bit access only (non-compliant) */ const struct pci_ecam_ops pci_32b_ops = { .pci_ops = { + .add_bus = pci_ecam_add_bus, + .remove_bus = pci_ecam_remove_bus, .map_bus = pci_ecam_map_bus, .read = pci_generic_config_read32, .write = pci_generic_config_write32, @@ -187,6 +223,8 @@ const struct pci_ecam_ops pci_32b_ops = { /* ECAM ops for 32-bit read only (non-compliant) */ const struct pci_ecam_ops pci_32b_read_ops = { .pci_ops = { + .add_bus = pci_ecam_add_bus, + .remove_bus = pci_ecam_remove_bus, .map_bus = pci_ecam_map_bus, .read = pci_generic_config_read32, .write = pci_generic_config_write, diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index f33ff2bca414..3fdd1b9bd8c3 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -75,6 +75,9 @@ int cpci_hp_unregister_bus(struct pci_bus *bus); int cpci_hp_start(void); int cpci_hp_stop(void); +/* Global variables */ +extern int cpci_debug; + /* * Internal function prototypes, these functions should not be used by * board/chassis drivers. diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 2c16adb7f4ec..6c48066acb44 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -19,8 +19,6 @@ #define MY_NAME "cpci_hotplug" -extern int cpci_debug; - #define dbg(format, arg...) \ do { \ if (cpci_debug) \ diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index b8aacb41a83c..f99a7927e5a8 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -296,9 +296,10 @@ static int ctrl_slot_cleanup(struct controller *ctrl) * * Won't work for more than one PCI-PCI bridge in a slot. * - * @bus_num - bus number of PCI device - * @dev_num - device number of PCI device - * @slot - Pointer to u8 where slot number will be returned + * @bus: pointer to the PCI bus structure + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: Pointer to u8 where slot number will be returned * * Output: SUCCESS or FAILURE */ diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 68de958a9be8..1b26ca0b3701 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1877,7 +1877,7 @@ static void interrupt_event_handler(struct controller *ctrl) /** * cpqhp_pushbutton_thread - handle pushbutton events - * @slot: target slot (struct) + * @t: pointer to struct timer_list which holds all timer-related callbacks * * Scheduled procedure to handle blocking stuff for the pushbuttons. * Handles all pending events and exits. diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 5ac31f683b85..058d5937d8a9 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -73,7 +73,7 @@ static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf) if (retval) return retval; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, @@ -130,7 +130,7 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf) if (retval) return retval; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf, @@ -175,7 +175,7 @@ static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf) if (retval) return retval; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static struct pci_slot_attribute hotplug_slot_attr_latch = { @@ -192,7 +192,7 @@ static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf) if (retval) return retval; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static struct pci_slot_attribute hotplug_slot_attr_presence = { diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4fd200d8b0a9..d4a930881054 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -47,6 +47,9 @@ extern int pciehp_poll_time; * struct controller - PCIe hotplug controller * @pcie: pointer to the controller's PCIe port service device * @slot_cap: cached copy of the Slot Capabilities register + * @inband_presence_disabled: In-Band Presence Detect Disable supported by + * controller and disabled per spec recommendation (PCIe r5.0, appendix I + * implementation note) * @slot_ctrl: cached copy of the Slot Control register * @ctrl_lock: serializes writes to the Slot Control register * @cmd_started: jiffies when the Slot Control register was last written; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index fb3840e222ad..9d06939736c0 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -563,6 +563,32 @@ void pciehp_power_off_slot(struct controller *ctrl) PCI_EXP_SLTCTL_PWR_OFF); } +static void pciehp_ignore_dpc_link_change(struct controller *ctrl, + struct pci_dev *pdev, int irq) +{ + /* + * Ignore link changes which occurred while waiting for DPC recovery. + * Could be several if DPC triggered multiple times consecutively. + */ + synchronize_hardirq(irq); + atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events); + if (pciehp_poll_mode) + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_DLLSC); + ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n", + slot_name(ctrl)); + + /* + * If the link is unexpectedly down after successful recovery, + * the corresponding link change may have been ignored above. + * Synthesize it to ensure that it is acted on. + */ + down_read(&ctrl->reset_lock); + if (!pciehp_check_link_active(ctrl)) + pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); + up_read(&ctrl->reset_lock); +} + static irqreturn_t pciehp_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; @@ -706,6 +732,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) PCI_EXP_SLTCTL_ATTN_IND_ON); } + /* + * Ignore Link Down/Up events caused by Downstream Port Containment + * if recovery from the error succeeded. + */ + if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) && + ctrl->state == ON_STATE) { + events &= ~PCI_EXP_SLTSTA_DLLSC; + pciehp_ignore_dpc_link_change(ctrl, pdev, irq); + } + /* * Disable requests have higher priority than Presence Detect Changed * or Data Link Layer State Changed events. diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index dbfa0b55d31a..068b7810a574 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -50,7 +50,7 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t add_slot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static ssize_t remove_slot_store(struct kobject *kobj, @@ -80,7 +80,7 @@ static ssize_t remove_slot_store(struct kobject *kobj, static ssize_t remove_slot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static struct kobj_attribute add_slot_attr = diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index 45658bb5c554..64beed7a26be 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -24,50 +24,54 @@ static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; - char *out = buf; int index, busnr; struct resource *res; struct pci_bus *bus; + size_t len = 0; pdev = to_pci_dev(dev); bus = pdev->subordinate; - out += sprintf(buf, "Free resources: memory\n"); + len += sysfs_emit_at(buf, len, "Free resources: memory\n"); pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && !(res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)resource_size(res)); + len += sysfs_emit_at(buf, len, + "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } - out += sprintf(out, "Free resources: prefetchable memory\n"); + len += sysfs_emit_at(buf, len, "Free resources: prefetchable memory\n"); pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && (res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)resource_size(res)); + len += sysfs_emit_at(buf, len, + "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } - out += sprintf(out, "Free resources: IO\n"); + len += sysfs_emit_at(buf, len, "Free resources: IO\n"); pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_IO)) { - out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)resource_size(res)); + len += sysfs_emit_at(buf, len, + "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } - out += sprintf(out, "Free resources: bus numbers\n"); + len += sysfs_emit_at(buf, len, "Free resources: bus numbers\n"); for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) { if (!pci_find_bus(pci_domain_nr(bus), busnr)) break; } if (busnr < bus->busn_res.end) - out += sprintf(out, "start = %8.8x, length = %8.8x\n", - busnr, (int)(bus->busn_res.end - busnr)); + len += sysfs_emit_at(buf, len, + "start = %8.8x, length = %8.8x\n", + busnr, (int)(bus->busn_res.end - busnr)); - return out - buf; + return len; } static DEVICE_ATTR(ctrl, S_IRUGO, show_ctrl, NULL); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index afc06e6ce115..dafdc652fcd0 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -346,7 +346,7 @@ static ssize_t sriov_totalvfs_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); + return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); } static ssize_t sriov_numvfs_show(struct device *dev, @@ -361,7 +361,7 @@ static ssize_t sriov_numvfs_show(struct device *dev, num_vfs = pdev->sriov->num_VFs; device_unlock(&pdev->dev); - return sprintf(buf, "%u\n", num_vfs); + return sysfs_emit(buf, "%u\n", num_vfs); } /* @@ -391,9 +391,16 @@ static ssize_t sriov_numvfs_store(struct device *dev, if (num_vfs == pdev->sriov->num_VFs) goto exit; + /* is PF driver loaded */ + if (!pdev->driver) { + pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n"); + ret = -ENOENT; + goto exit; + } + /* is PF driver loaded w/callback */ - if (!pdev->driver || !pdev->driver->sriov_configure) { - pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n"); + if (!pdev->driver->sriov_configure) { + pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n"); ret = -ENOENT; goto exit; } @@ -435,7 +442,7 @@ static ssize_t sriov_offset_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->offset); + return sysfs_emit(buf, "%u\n", pdev->sriov->offset); } static ssize_t sriov_stride_show(struct device *dev, @@ -444,7 +451,7 @@ static ssize_t sriov_stride_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->stride); + return sysfs_emit(buf, "%u\n", pdev->sriov->stride); } static ssize_t sriov_vf_device_show(struct device *dev, @@ -453,7 +460,7 @@ static ssize_t sriov_vf_device_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%x\n", pdev->sriov->vf_device); + return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device); } static ssize_t sriov_drivers_autoprobe_show(struct device *dev, @@ -462,7 +469,7 @@ static ssize_t sriov_drivers_autoprobe_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe); + return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe); } static ssize_t sriov_drivers_autoprobe_store(struct device *dev, diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 217dc9f0231f..9232255c8515 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -464,11 +464,11 @@ static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, return retval; entry = irq_get_msi_desc(irq); - if (entry) - return sprintf(buf, "%s\n", - entry->msi_attrib.is_msix ? "msix" : "msi"); + if (!entry) + return -ENODEV; - return -ENODEV; + return sysfs_emit(buf, "%s\n", + entry->msi_attrib.is_msix ? "msix" : "msi"); } static int populate_msi_sysfs(struct pci_dev *pdev) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 196382630363..50cdde3e9a8b 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -48,12 +48,16 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_p2pdma *p2pdma; size_t size = 0; - if (pdev->p2pdma->pool) - size = gen_pool_size(pdev->p2pdma->pool); + rcu_read_lock(); + p2pdma = rcu_dereference(pdev->p2pdma); + if (p2pdma && p2pdma->pool) + size = gen_pool_size(p2pdma->pool); + rcu_read_unlock(); - return scnprintf(buf, PAGE_SIZE, "%zd\n", size); + return sysfs_emit(buf, "%zd\n", size); } static DEVICE_ATTR_RO(size); @@ -61,12 +65,16 @@ static ssize_t available_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_p2pdma *p2pdma; size_t avail = 0; - if (pdev->p2pdma->pool) - avail = gen_pool_avail(pdev->p2pdma->pool); + rcu_read_lock(); + p2pdma = rcu_dereference(pdev->p2pdma); + if (p2pdma && p2pdma->pool) + avail = gen_pool_avail(p2pdma->pool); + rcu_read_unlock(); - return scnprintf(buf, PAGE_SIZE, "%zd\n", avail); + return sysfs_emit(buf, "%zd\n", avail); } static DEVICE_ATTR_RO(available); @@ -74,9 +82,16 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_p2pdma *p2pdma; + bool published = false; - return scnprintf(buf, PAGE_SIZE, "%d\n", - pdev->p2pdma->p2pmem_published); + rcu_read_lock(); + p2pdma = rcu_dereference(pdev->p2pdma); + if (p2pdma) + published = p2pdma->p2pmem_published; + rcu_read_unlock(); + + return sysfs_emit(buf, "%d\n", published); } static DEVICE_ATTR_RO(published); @@ -95,8 +110,9 @@ static const struct attribute_group p2pmem_group = { static void pci_p2pdma_release(void *data) { struct pci_dev *pdev = data; - struct pci_p2pdma *p2pdma = pdev->p2pdma; + struct pci_p2pdma *p2pdma; + p2pdma = rcu_dereference_protected(pdev->p2pdma, 1); if (!p2pdma) return; @@ -128,16 +144,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) if (error) goto out_pool_destroy; - pdev->p2pdma = p2p; - error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); if (error) goto out_pool_destroy; + rcu_assign_pointer(pdev->p2pdma, p2p); return 0; out_pool_destroy: - pdev->p2pdma = NULL; gen_pool_destroy(p2p->pool); out: devm_kfree(&pdev->dev, p2p); @@ -159,6 +173,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, { struct pci_p2pdma_pagemap *p2p_pgmap; struct dev_pagemap *pgmap; + struct pci_p2pdma *p2pdma; void *addr; int error; @@ -200,7 +215,8 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, goto pgmap_free; } - error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr, + p2pdma = rcu_dereference_protected(pdev->p2pdma, 1); + error = gen_pool_add_owner(p2pdma->pool, (unsigned long)addr, pci_bus_address(pdev, bar) + offset, range_len(&pgmap->range), dev_to_node(&pdev->dev), pgmap->ref); @@ -308,10 +324,41 @@ static const struct pci_p2pdma_whitelist_entry { {} }; -static bool __host_bridge_whitelist(struct pci_host_bridge *host, - bool same_host_bridge) +/* + * This lookup function tries to find the PCI device corresponding to a given + * host bridge. + * + * It assumes the host bridge device is the first PCI device in the + * bus->devices list and that the devfn is 00.0. These assumptions should hold + * for all the devices in the whitelist above. + * + * This function is equivalent to pci_get_slot(host->bus, 0), however it does + * not take the pci_bus_sem lock seeing __host_bridge_whitelist() must not + * sleep. + * + * For this to be safe, the caller should hold a reference to a device on the + * bridge, which should ensure the host_bridge device will not be freed + * or removed from the head of the devices list. + */ +static struct pci_dev *pci_host_bridge_dev(struct pci_host_bridge *host) { - struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0)); + struct pci_dev *root; + + root = list_first_entry_or_null(&host->bus->devices, + struct pci_dev, bus_list); + + if (!root) + return NULL; + if (root->devfn != PCI_DEVFN(0, 0)) + return NULL; + + return root; +} + +static bool __host_bridge_whitelist(struct pci_host_bridge *host, + bool same_host_bridge, bool warn) +{ + struct pci_dev *root = pci_host_bridge_dev(host); const struct pci_p2pdma_whitelist_entry *entry; unsigned short vendor, device; @@ -320,7 +367,6 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host, vendor = root->vendor; device = root->device; - pci_dev_put(root); for (entry = pci_p2pdma_whitelist; entry->vendor; entry++) { if (vendor != entry->vendor || device != entry->device) @@ -331,6 +377,10 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host, return true; } + if (warn) + pci_warn(root, "Host bridge not in P2PDMA whitelist: %04x:%04x\n", + vendor, device); + return false; } @@ -338,44 +388,90 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host, * If we can't find a common upstream bridge take a look at the root * complex and compare it to a whitelist of known good hardware. */ -static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b) +static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b, + bool warn) { struct pci_host_bridge *host_a = pci_find_host_bridge(a->bus); struct pci_host_bridge *host_b = pci_find_host_bridge(b->bus); if (host_a == host_b) - return __host_bridge_whitelist(host_a, true); + return __host_bridge_whitelist(host_a, true, warn); - if (__host_bridge_whitelist(host_a, false) && - __host_bridge_whitelist(host_b, false)) + if (__host_bridge_whitelist(host_a, false, warn) && + __host_bridge_whitelist(host_b, false, warn)) return true; return false; } -static enum pci_p2pdma_map_type -__upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client, - int *dist, bool *acs_redirects, struct seq_buf *acs_list) +static unsigned long map_types_idx(struct pci_dev *client) { + return (pci_domain_nr(client->bus) << 16) | + (client->bus->number << 8) | client->devfn; +} + +/* + * Calculate the P2PDMA mapping type and distance between two PCI devices. + * + * If the two devices are the same PCI function, return + * PCI_P2PDMA_MAP_BUS_ADDR and a distance of 0. + * + * If they are two functions of the same device, return + * PCI_P2PDMA_MAP_BUS_ADDR and a distance of 2 (one hop up to the bridge, + * then one hop back down to another function of the same device). + * + * In the case where two devices are connected to the same PCIe switch, + * return a distance of 4. This corresponds to the following PCI tree: + * + * -+ Root Port + * \+ Switch Upstream Port + * +-+ Switch Downstream Port 0 + * + \- Device A + * \-+ Switch Downstream Port 1 + * \- Device B + * + * The distance is 4 because we traverse from Device A to Downstream Port 0 + * to the common Switch Upstream Port, back down to Downstream Port 1 and + * then to Device B. The mapping type returned depends on the ACS + * redirection setting of the ports along the path. + * + * If ACS redirect is set on any port in the path, traffic between the + * devices will go through the host bridge, so return + * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; otherwise return + * PCI_P2PDMA_MAP_BUS_ADDR. + * + * Any two devices that have a data path that goes through the host bridge + * will consult a whitelist. If the host bridge is in the whitelist, return + * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of + * ports per above. If the device is not in the whitelist, return + * PCI_P2PDMA_MAP_NOT_SUPPORTED. + */ +static enum pci_p2pdma_map_type +calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client, + int *dist, bool verbose) +{ + enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; struct pci_dev *a = provider, *b = client, *bb; + bool acs_redirects = false; + struct pci_p2pdma *p2pdma; + struct seq_buf acs_list; + int acs_cnt = 0; int dist_a = 0; int dist_b = 0; - int acs_cnt = 0; + char buf[128]; - if (acs_redirects) - *acs_redirects = false; + seq_buf_init(&acs_list, buf, sizeof(buf)); /* * Note, we don't need to take references to devices returned by * pci_upstream_bridge() seeing we hold a reference to a child * device which will already hold a reference to the upstream bridge. */ - while (a) { dist_b = 0; if (pci_bridge_has_acs_redir(a)) { - seq_buf_print_bus_devfn(acs_list, a); + seq_buf_print_bus_devfn(&acs_list, a); acs_cnt++; } @@ -393,10 +489,8 @@ __upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client, dist_a++; } - if (dist) - *dist = dist_a + dist_b; - - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; + *dist = dist_a + dist_b; + goto map_through_host_bridge; check_b_path_acs: bb = b; @@ -406,124 +500,45 @@ check_b_path_acs: break; if (pci_bridge_has_acs_redir(bb)) { - seq_buf_print_bus_devfn(acs_list, bb); + seq_buf_print_bus_devfn(&acs_list, bb); acs_cnt++; } bb = pci_upstream_bridge(bb); } - if (dist) - *dist = dist_a + dist_b; + *dist = dist_a + dist_b; - if (acs_cnt) { - if (acs_redirects) - *acs_redirects = true; - - return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; + if (!acs_cnt) { + map_type = PCI_P2PDMA_MAP_BUS_ADDR; + goto done; } - return PCI_P2PDMA_MAP_BUS_ADDR; -} - -static unsigned long map_types_idx(struct pci_dev *client) -{ - return (pci_domain_nr(client->bus) << 16) | - (client->bus->number << 8) | client->devfn; -} - -/* - * Find the distance through the nearest common upstream bridge between - * two PCI devices. - * - * If the two devices are the same device then 0 will be returned. - * - * If there are two virtual functions of the same device behind the same - * bridge port then 2 will be returned (one step down to the PCIe switch, - * then one step back to the same device). - * - * In the case where two devices are connected to the same PCIe switch, the - * value 4 will be returned. This corresponds to the following PCI tree: - * - * -+ Root Port - * \+ Switch Upstream Port - * +-+ Switch Downstream Port - * + \- Device A - * \-+ Switch Downstream Port - * \- Device B - * - * The distance is 4 because we traverse from Device A through the downstream - * port of the switch, to the common upstream port, back up to the second - * downstream port and then to Device B. - * - * Any two devices that cannot communicate using p2pdma will return - * PCI_P2PDMA_MAP_NOT_SUPPORTED. - * - * Any two devices that have a data path that goes through the host bridge - * will consult a whitelist. If the host bridges are on the whitelist, - * this function will return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE. - * - * If either bridge is not on the whitelist this function returns - * PCI_P2PDMA_MAP_NOT_SUPPORTED. - * - * If a bridge which has any ACS redirection bits set is in the path, - * acs_redirects will be set to true. In this case, a list of all infringing - * bridge addresses will be populated in acs_list (assuming it's non-null) - * for printk purposes. - */ -static enum pci_p2pdma_map_type -upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client, - int *dist, bool *acs_redirects, struct seq_buf *acs_list) -{ - enum pci_p2pdma_map_type map_type; - - map_type = __upstream_bridge_distance(provider, client, dist, - acs_redirects, acs_list); - - if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) { - if (!cpu_supports_p2pdma() && - !host_bridge_whitelist(provider, client)) - map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED; - } - - if (provider->p2pdma) - xa_store(&provider->p2pdma->map_types, map_types_idx(client), - xa_mk_value(map_type), GFP_KERNEL); - - return map_type; -} - -static enum pci_p2pdma_map_type -upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client, - int *dist) -{ - struct seq_buf acs_list; - bool acs_redirects; - int ret; - - seq_buf_init(&acs_list, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE); - if (!acs_list.buffer) - return -ENOMEM; - - ret = upstream_bridge_distance(provider, client, dist, &acs_redirects, - &acs_list); - if (acs_redirects) { + if (verbose) { + acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */ pci_warn(client, "ACS redirect is set between the client and provider (%s)\n", pci_name(provider)); - /* Drop final semicolon */ - acs_list.buffer[acs_list.len-1] = 0; pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n", acs_list.buffer); } + acs_redirects = true; - if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) { - pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n", - pci_name(provider)); +map_through_host_bridge: + if (!cpu_supports_p2pdma() && + !host_bridge_whitelist(provider, client, acs_redirects)) { + if (verbose) + pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n", + pci_name(provider)); + map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED; } - - kfree(acs_list.buffer); - - return ret; +done: + rcu_read_lock(); + p2pdma = rcu_dereference(provider->p2pdma); + if (p2pdma) + xa_store(&p2pdma->map_types, map_types_idx(client), + xa_mk_value(map_type), GFP_KERNEL); + rcu_read_unlock(); + return map_type; } /** @@ -546,11 +561,11 @@ upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client, int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, int num_clients, bool verbose) { + enum pci_p2pdma_map_type map; bool not_supported = false; struct pci_dev *pci_client; int total_dist = 0; - int distance; - int i, ret; + int i, distance; if (num_clients == 0) return -1; @@ -564,16 +579,12 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, return -1; } - if (verbose) - ret = upstream_bridge_distance_warn(provider, - pci_client, &distance); - else - ret = upstream_bridge_distance(provider, pci_client, - &distance, NULL, NULL); + map = calc_map_type_and_dist(provider, pci_client, &distance, + verbose); pci_dev_put(pci_client); - if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) + if (map == PCI_P2PDMA_MAP_NOT_SUPPORTED) not_supported = true; if (not_supported && !verbose) @@ -595,7 +606,15 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many); */ bool pci_has_p2pmem(struct pci_dev *pdev) { - return pdev->p2pdma && pdev->p2pdma->p2pmem_published; + struct pci_p2pdma *p2pdma; + bool res; + + rcu_read_lock(); + p2pdma = rcu_dereference(pdev->p2pdma); + res = p2pdma && p2pdma->p2pmem_published; + rcu_read_unlock(); + + return res; } EXPORT_SYMBOL_GPL(pci_has_p2pmem); @@ -675,6 +694,7 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size) { void *ret = NULL; struct percpu_ref *ref; + struct pci_p2pdma *p2pdma; /* * Pairs with synchronize_rcu() in pci_p2pdma_release() to @@ -682,16 +702,16 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size) * read-lock. */ rcu_read_lock(); - if (unlikely(!pdev->p2pdma)) + p2pdma = rcu_dereference(pdev->p2pdma); + if (unlikely(!p2pdma)) goto out; - ret = (void *)gen_pool_alloc_owner(pdev->p2pdma->pool, size, - (void **) &ref); + ret = (void *)gen_pool_alloc_owner(p2pdma->pool, size, (void **) &ref); if (!ret) goto out; if (unlikely(!percpu_ref_tryget_live(ref))) { - gen_pool_free(pdev->p2pdma->pool, (unsigned long) ret, size); + gen_pool_free(p2pdma->pool, (unsigned long) ret, size); ret = NULL; goto out; } @@ -710,8 +730,9 @@ EXPORT_SYMBOL_GPL(pci_alloc_p2pmem); void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size) { struct percpu_ref *ref; + struct pci_p2pdma *p2pdma = rcu_dereference_protected(pdev->p2pdma, 1); - gen_pool_free_owner(pdev->p2pdma->pool, (uintptr_t)addr, size, + gen_pool_free_owner(p2pdma->pool, (uintptr_t)addr, size, (void **) &ref); percpu_ref_put(ref); } @@ -725,9 +746,13 @@ EXPORT_SYMBOL_GPL(pci_free_p2pmem); */ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr) { + struct pci_p2pdma *p2pdma; + if (!addr) return 0; - if (!pdev->p2pdma) + + p2pdma = rcu_dereference_protected(pdev->p2pdma, 1); + if (!p2pdma) return 0; /* @@ -735,7 +760,7 @@ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr) * bus address as the physical address. So gen_pool_virt_to_phys() * actually returns the bus address despite the misleading name. */ - return gen_pool_virt_to_phys(pdev->p2pdma->pool, (unsigned long)addr); + return gen_pool_virt_to_phys(p2pdma->pool, (unsigned long)addr); } EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus); @@ -806,19 +831,40 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl); */ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) { - if (pdev->p2pdma) - pdev->p2pdma->p2pmem_published = publish; + struct pci_p2pdma *p2pdma; + + rcu_read_lock(); + p2pdma = rcu_dereference(pdev->p2pdma); + if (p2pdma) + p2pdma->p2pmem_published = publish; + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(pci_p2pmem_publish); -static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct pci_dev *provider, - struct pci_dev *client) +static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap, + struct device *dev) { + enum pci_p2pdma_map_type type = PCI_P2PDMA_MAP_NOT_SUPPORTED; + struct pci_dev *provider = to_p2p_pgmap(pgmap)->provider; + struct pci_dev *client; + struct pci_p2pdma *p2pdma; + if (!provider->p2pdma) return PCI_P2PDMA_MAP_NOT_SUPPORTED; - return xa_to_value(xa_load(&provider->p2pdma->map_types, - map_types_idx(client))); + if (!dev_is_pci(dev)) + return PCI_P2PDMA_MAP_NOT_SUPPORTED; + + client = to_pci_dev(dev); + + rcu_read_lock(); + p2pdma = rcu_dereference(provider->p2pdma); + + if (p2pdma) + type = xa_to_value(xa_load(&p2pdma->map_types, + map_types_idx(client))); + rcu_read_unlock(); + return type; } static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap, @@ -853,14 +899,8 @@ int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg, { struct pci_p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(sg_page(sg)->pgmap); - struct pci_dev *client; - if (WARN_ON_ONCE(!dev_is_pci(dev))) - return 0; - - client = to_pci_dev(dev); - - switch (pci_p2pdma_map_type(p2p_pgmap->provider, client)) { + switch (pci_p2pdma_map_type(sg_page(sg)->pgmap, dev)) { case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE: return dma_map_sg_attrs(dev, sg, nents, dir, attrs); case PCI_P2PDMA_MAP_BUS_ADDR: @@ -884,17 +924,9 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs); void pci_p2pdma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - struct pci_p2pdma_pagemap *p2p_pgmap = - to_p2p_pgmap(sg_page(sg)->pgmap); enum pci_p2pdma_map_type map_type; - struct pci_dev *client; - if (WARN_ON_ONCE(!dev_is_pci(dev))) - return; - - client = to_pci_dev(dev); - - map_type = pci_p2pdma_map_type(p2p_pgmap->provider, client); + map_type = pci_p2pdma_map_type(sg_page(sg)->pgmap, dev); if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) dma_unmap_sg_attrs(dev, sg, nents, dir, attrs); diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index c32f3b7540e8..0c6446519640 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -139,14 +139,17 @@ enum acpi_attr_enum { ACPI_ATTR_INDEX_SHOW, }; -static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) +static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) { int len; + len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer, obj->buffer.length, UTF16_LITTLE_ENDIAN, - buf, PAGE_SIZE); - buf[len] = '\n'; + buf, PAGE_SIZE - 1); + buf[len++] = '\n'; + + return len; } static int dsm_get_label(struct device *dev, char *buf, @@ -154,7 +157,7 @@ static int dsm_get_label(struct device *dev, char *buf, { acpi_handle handle = ACPI_HANDLE(dev); union acpi_object *obj, *tmp; - int len = -1; + int len = 0; if (!handle) return -1; @@ -175,20 +178,19 @@ static int dsm_get_label(struct device *dev, char *buf, * this entry must return a null string. */ if (attr == ACPI_ATTR_INDEX_SHOW) { - scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value); + len = sysfs_emit(buf, "%llu\n", tmp->integer.value); } else if (attr == ACPI_ATTR_LABEL_SHOW) { if (tmp[1].type == ACPI_TYPE_STRING) - scnprintf(buf, PAGE_SIZE, "%s\n", - tmp[1].string.pointer); + len = sysfs_emit(buf, "%s\n", + tmp[1].string.pointer); else if (tmp[1].type == ACPI_TYPE_BUFFER) - dsm_label_utf16s_to_utf8s(tmp + 1, buf); + len = dsm_label_utf16s_to_utf8s(tmp + 1, buf); } - len = strlen(buf) > 0 ? strlen(buf) : -1; } ACPI_FREE(obj); - return len; + return len > 0 ? len : -1; } static ssize_t label_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index beb8d1f4fafe..5d63df7c1820 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -537,7 +537,7 @@ static ssize_t devspec_show(struct device *dev, if (np == NULL) return 0; - return sysfs_emit(buf, "%pOF", np); + return sysfs_emit(buf, "%pOF\n", np); } static DEVICE_ATTR_RO(devspec); #endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e3bb0d073352..aacf575c15cf 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5030,6 +5030,16 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) return pci_reset_hotplug_slot(dev->slot->hotplug, probe); } +static int pci_reset_bus_function(struct pci_dev *dev, int probe) +{ + int rc; + + rc = pci_dev_reset_slot_function(dev, probe); + if (rc != -ENOTTY) + return rc; + return pci_parent_bus_reset(dev, probe); +} + static void pci_dev_lock(struct pci_dev *dev) { pci_cfg_access_lock(dev); @@ -5152,10 +5162,7 @@ int __pci_reset_function_locked(struct pci_dev *dev) rc = pci_pm_reset(dev, 0); if (rc != -ENOTTY) return rc; - rc = pci_dev_reset_slot_function(dev, 0); - if (rc != -ENOTTY) - return rc; - return pci_parent_bus_reset(dev, 0); + return pci_reset_bus_function(dev, 0); } EXPORT_SYMBOL_GPL(__pci_reset_function_locked); @@ -5185,13 +5192,10 @@ int pci_probe_reset_function(struct pci_dev *dev) if (rc != -ENOTTY) return rc; rc = pci_pm_reset(dev, 1); - if (rc != -ENOTTY) - return rc; - rc = pci_dev_reset_slot_function(dev, 1); if (rc != -ENOTTY) return rc; - return pci_parent_bus_reset(dev, 1); + return pci_reset_bus_function(dev, 1); } /** @@ -6451,34 +6455,40 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf) spin_lock(&resource_alignment_lock); if (resource_alignment_param) - count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param); + count = sysfs_emit(buf, "%s\n", resource_alignment_param); spin_unlock(&resource_alignment_lock); - /* - * When set by the command line, resource_alignment_param will not - * have a trailing line feed, which is ugly. So conditionally add - * it here. - */ - if (count >= 2 && buf[count - 2] != '\n' && count < PAGE_SIZE - 1) { - buf[count - 1] = '\n'; - buf[count++] = 0; - } - return count; } static ssize_t resource_alignment_store(struct bus_type *bus, const char *buf, size_t count) { - char *param = kstrndup(buf, count, GFP_KERNEL); + char *param, *old, *end; + if (count >= (PAGE_SIZE - 1)) + return -EINVAL; + + param = kstrndup(buf, count, GFP_KERNEL); if (!param) return -ENOMEM; + end = strchr(param, '\n'); + if (end) + *end = '\0'; + spin_lock(&resource_alignment_lock); - kfree(resource_alignment_param); - resource_alignment_param = param; + old = resource_alignment_param; + if (strlen(param)) { + resource_alignment_param = param; + } else { + kfree(param); + resource_alignment_param = NULL; + } spin_unlock(&resource_alignment_lock); + + kfree(old); + return count; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 37c913bbc6e1..93dcdd431072 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -324,8 +324,8 @@ struct pci_sriov { /** * pci_dev_set_io_state - Set the new error state if possible. * - * @dev - pci device to set new error_state - * @new - the state we want dev to be in + * @dev: PCI device to set new error_state + * @new: the state we want dev to be in * * Must be called with device_lock held. * @@ -385,6 +385,8 @@ static inline bool pci_dev_is_disconnected(const struct pci_dev *dev) /* pci_dev priv_flags */ #define PCI_DEV_ADDED 0 +#define PCI_DPC_RECOVERED 1 +#define PCI_DPC_RECOVERING 2 static inline void pci_dev_assign_added(struct pci_dev *dev, bool added) { @@ -439,10 +441,12 @@ void pci_restore_dpc_state(struct pci_dev *dev); void pci_dpc_init(struct pci_dev *pdev); void dpc_process_error(struct pci_dev *pdev); pci_ers_result_t dpc_reset_link(struct pci_dev *pdev); +bool pci_dpc_recovered(struct pci_dev *pdev); #else static inline void pci_save_dpc_state(struct pci_dev *dev) {} static inline void pci_restore_dpc_state(struct pci_dev *dev) {} static inline void pci_dpc_init(struct pci_dev *pdev) {} +static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; } #endif #ifdef CONFIG_PCIEPORTBUS diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index ec943cee5ecc..df4ba9b384c2 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -529,21 +529,23 @@ static const char *aer_agent_string[] = { char *buf) \ { \ unsigned int i; \ - char *str = buf; \ struct pci_dev *pdev = to_pci_dev(dev); \ u64 *stats = pdev->aer_stats->stats_array; \ + size_t len = 0; \ \ for (i = 0; i < ARRAY_SIZE(strings_array); i++) { \ if (strings_array[i]) \ - str += sprintf(str, "%s %llu\n", \ - strings_array[i], stats[i]); \ + len += sysfs_emit_at(buf, len, "%s %llu\n", \ + strings_array[i], \ + stats[i]); \ else if (stats[i]) \ - str += sprintf(str, #stats_array "_bit[%d] %llu\n",\ - i, stats[i]); \ + len += sysfs_emit_at(buf, len, \ + #stats_array "_bit[%d] %llu\n",\ + i, stats[i]); \ } \ - str += sprintf(str, "TOTAL_%s %llu\n", total_string, \ - pdev->aer_stats->total_field); \ - return str-buf; \ + len += sysfs_emit_at(buf, len, "TOTAL_%s %llu\n", total_string, \ + pdev->aer_stats->total_field); \ + return len; \ } \ static DEVICE_ATTR_RO(name) @@ -563,7 +565,7 @@ aer_stats_dev_attr(aer_dev_nonfatal, dev_nonfatal_errs, char *buf) \ { \ struct pci_dev *pdev = to_pci_dev(dev); \ - return sprintf(buf, "%llu\n", pdev->aer_stats->field); \ + return sysfs_emit(buf, "%llu\n", pdev->aer_stats->field); \ } \ static DEVICE_ATTR_RO(name) @@ -983,7 +985,7 @@ static void aer_recover_work_func(struct work_struct *work) pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, entry.devfn); if (!pdev) { - pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n", + pr_err("no pci_dev for %04x:%02x:%02x.%x\n", entry.domain, entry.bus, PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); continue; @@ -1022,7 +1024,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, &aer_recover_ring_lock)) schedule_work(&aer_recover_work); else - pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", + pr_err("buffer overflow in recovery for %04x:%02x:%02x.%x\n", domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); } EXPORT_SYMBOL_GPL(aer_recover_queue); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index ac0557a305af..013a47f587ce 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1208,7 +1208,7 @@ static ssize_t aspm_attr_show_common(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); struct pcie_link_state *link = pcie_aspm_get_link(pdev); - return sprintf(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0); + return sysfs_emit(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0); } static ssize_t aspm_attr_store_common(struct device *dev, @@ -1265,7 +1265,7 @@ static ssize_t clkpm_show(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); struct pcie_link_state *link = pcie_aspm_get_link(pdev); - return sprintf(buf, "%d\n", link->clkpm_enabled); + return sysfs_emit(buf, "%d\n", link->clkpm_enabled); } static ssize_t clkpm_store(struct device *dev, diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index e05aba86a317..c556e7beafe3 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -71,6 +71,58 @@ void pci_restore_dpc_state(struct pci_dev *dev) pci_write_config_word(dev, dev->dpc_cap + PCI_EXP_DPC_CTL, *cap); } +static DECLARE_WAIT_QUEUE_HEAD(dpc_completed_waitqueue); + +#ifdef CONFIG_HOTPLUG_PCI_PCIE +static bool dpc_completed(struct pci_dev *pdev) +{ + u16 status; + + pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, &status); + if ((status != 0xffff) && (status & PCI_EXP_DPC_STATUS_TRIGGER)) + return false; + + if (test_bit(PCI_DPC_RECOVERING, &pdev->priv_flags)) + return false; + + return true; +} + +/** + * pci_dpc_recovered - whether DPC triggered and has recovered successfully + * @pdev: PCI device + * + * Return true if DPC was triggered for @pdev and has recovered successfully. + * Wait for recovery if it hasn't completed yet. Called from the PCIe hotplug + * driver to recognize and ignore Link Down/Up events caused by DPC. + */ +bool pci_dpc_recovered(struct pci_dev *pdev) +{ + struct pci_host_bridge *host; + + if (!pdev->dpc_cap) + return false; + + /* + * Synchronization between hotplug and DPC is not supported + * if DPC is owned by firmware and EDR is not enabled. + */ + host = pci_find_host_bridge(pdev->bus); + if (!host->native_dpc && !IS_ENABLED(CONFIG_PCIE_EDR)) + return false; + + /* + * Need a timeout in case DPC never completes due to failure of + * dpc_wait_rp_inactive(). The spec doesn't mandate a time limit, + * but reports indicate that DPC completes within 4 seconds. + */ + wait_event_timeout(dpc_completed_waitqueue, dpc_completed(pdev), + msecs_to_jiffies(4000)); + + return test_and_clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); +} +#endif /* CONFIG_HOTPLUG_PCI_PCIE */ + static int dpc_wait_rp_inactive(struct pci_dev *pdev) { unsigned long timeout = jiffies + HZ; @@ -91,8 +143,11 @@ static int dpc_wait_rp_inactive(struct pci_dev *pdev) pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) { + pci_ers_result_t ret; u16 cap; + set_bit(PCI_DPC_RECOVERING, &pdev->priv_flags); + /* * DPC disables the Link automatically in hardware, so it has * already been reset by the time we get here. @@ -106,18 +161,27 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) if (!pcie_wait_for_link(pdev, false)) pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n"); - if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) - return PCI_ERS_RESULT_DISCONNECT; + if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) { + clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); + ret = PCI_ERS_RESULT_DISCONNECT; + goto out; + } pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, PCI_EXP_DPC_STATUS_TRIGGER); if (!pcie_wait_for_link(pdev, true)) { pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n"); - return PCI_ERS_RESULT_DISCONNECT; + clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); + ret = PCI_ERS_RESULT_DISCONNECT; + } else { + set_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); + ret = PCI_ERS_RESULT_RECOVERED; } - - return PCI_ERS_RESULT_RECOVERED; +out: + clear_bit(PCI_DPC_RECOVERING, &pdev->priv_flags); + wake_up_all(&dpc_completed_waitqueue); + return ret; } static void dpc_process_rp_pio_error(struct pci_dev *pdev) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 76a2f33c6b48..79177ac37880 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2249,6 +2249,7 @@ static void pci_release_dev(struct device *dev) pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); bitmap_free(pci_dev->dma_alias_mask); + dev_dbg(dev, "device released\n"); kfree(pci_dev); } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 22b2bb1109c9..6d74386eadc2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -3656,6 +3657,16 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev) return; if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) return; + + /* + * SXIO/SXFP/SXLF turns off power to the Thunderbolt controller. + * We don't know how to turn it back on again, but firmware does, + * so we can only use SXIO/SXFP/SXLF if we're suspending via + * firmware. + */ + if (!pm_suspend_via_firmware()) + return; + bridge = ACPI_HANDLE(&dev->dev); if (!bridge) return; diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index d627dd9179b4..751a26668e3a 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -39,19 +39,19 @@ static const struct sysfs_ops pci_slot_sysfs_ops = { static ssize_t address_read_file(struct pci_slot *slot, char *buf) { if (slot->number == 0xff) - return sprintf(buf, "%04x:%02x\n", - pci_domain_nr(slot->bus), - slot->bus->number); - else - return sprintf(buf, "%04x:%02x:%02x\n", - pci_domain_nr(slot->bus), - slot->bus->number, - slot->number); + return sysfs_emit(buf, "%04x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number); + + return sysfs_emit(buf, "%04x:%02x:%02x\n", + pci_domain_nr(slot->bus), + slot->bus->number, + slot->number); } static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf) { - return sprintf(buf, "%s\n", pci_speed_string(speed)); + return sysfs_emit(buf, "%s\n", pci_speed_string(speed)); } static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index ba52459928f7..0b301f8be9ed 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -280,7 +280,7 @@ static ssize_t device_version_show(struct device *dev, ver = ioread32(&stdev->mmio_sys_info->device_version); - return sprintf(buf, "%x\n", ver); + return sysfs_emit(buf, "%x\n", ver); } static DEVICE_ATTR_RO(device_version); @@ -292,7 +292,7 @@ static ssize_t fw_version_show(struct device *dev, ver = ioread32(&stdev->mmio_sys_info->firmware_version); - return sprintf(buf, "%08x\n", ver); + return sysfs_emit(buf, "%08x\n", ver); } static DEVICE_ATTR_RO(fw_version); @@ -344,7 +344,7 @@ static ssize_t component_vendor_show(struct device *dev, /* component_vendor field not supported after gen3 */ if (stdev->gen != SWITCHTEC_GEN3) - return sprintf(buf, "none\n"); + return sysfs_emit(buf, "none\n"); return io_string_show(buf, &si->gen3.component_vendor, sizeof(si->gen3.component_vendor)); @@ -359,9 +359,9 @@ static ssize_t component_id_show(struct device *dev, /* component_id field not supported after gen3 */ if (stdev->gen != SWITCHTEC_GEN3) - return sprintf(buf, "none\n"); + return sysfs_emit(buf, "none\n"); - return sprintf(buf, "PM%04X\n", id); + return sysfs_emit(buf, "PM%04X\n", id); } static DEVICE_ATTR_RO(component_id); @@ -373,9 +373,9 @@ static ssize_t component_revision_show(struct device *dev, /* component_revision field not supported after gen3 */ if (stdev->gen != SWITCHTEC_GEN3) - return sprintf(buf, "255\n"); + return sysfs_emit(buf, "255\n"); - return sprintf(buf, "%d\n", rev); + return sysfs_emit(buf, "%d\n", rev); } static DEVICE_ATTR_RO(component_revision); @@ -384,7 +384,7 @@ static ssize_t partition_show(struct device *dev, { struct switchtec_dev *stdev = to_stdev(dev); - return sprintf(buf, "%d\n", stdev->partition); + return sysfs_emit(buf, "%d\n", stdev->partition); } static DEVICE_ATTR_RO(partition); @@ -393,7 +393,7 @@ static ssize_t partition_count_show(struct device *dev, { struct switchtec_dev *stdev = to_stdev(dev); - return sprintf(buf, "%d\n", stdev->partition_count); + return sysfs_emit(buf, "%d\n", stdev->partition_count); } static DEVICE_ATTR_RO(partition_count); diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 125e592af445..d8ecffe72f16 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -351,10 +351,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(at91_shdwc->shdwc_base)) { - dev_err(&pdev->dev, "Could not map reset controller address\n"); + if (IS_ERR(at91_shdwc->shdwc_base)) return PTR_ERR(at91_shdwc->shdwc_base); - } match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node); at91_shdwc->rcfg = match->data; diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index c5067eb75370..1c5af2fef142 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -90,6 +90,7 @@ static const struct of_device_id of_gpio_poweroff_match[] = { { .compatible = "gpio-poweroff", }, {}, }; +MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match); static struct platform_driver gpio_poweroff_driver = { .probe = gpio_poweroff_probe, diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c index 211eeef0c81a..c720112db704 100644 --- a/drivers/power/reset/keystone-reset.c +++ b/drivers/power/reset/keystone-reset.c @@ -71,6 +71,7 @@ static const struct of_device_id rsctrl_of_match[] = { {.compatible = "ti,keystone-reset", }, {}, }; +MODULE_DEVICE_TABLE(of, rsctrl_of_match); static int rsctrl_probe(struct platform_device *pdev) { diff --git a/drivers/power/reset/regulator-poweroff.c b/drivers/power/reset/regulator-poweroff.c index f697088e0ad1..20701203935f 100644 --- a/drivers/power/reset/regulator-poweroff.c +++ b/drivers/power/reset/regulator-poweroff.c @@ -64,6 +64,7 @@ static const struct of_device_id of_regulator_poweroff_match[] = { { .compatible = "regulator-poweroff", }, {}, }; +MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match); static struct platform_driver regulator_poweroff_driver = { .probe = regulator_poweroff_probe, diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index e696364126f1..11f5368e810e 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -712,7 +712,8 @@ config BATTERY_GOLDFISH config BATTERY_RT5033 tristate "RT5033 fuel gauge support" - depends on MFD_RT5033 + depends on I2C + select REGMAP_I2C help This adds support for battery fuel gauge in Richtek RT5033 PMIC. The fuelgauge calculates and determines the battery state of charge @@ -760,15 +761,6 @@ config CHARGER_UCS1002 Say Y to enable support for Microchip UCS1002 Programmable USB Port Power Controller with Charger Emulation. -config CHARGER_BD70528 - tristate "ROHM bd70528 charger driver" - depends on MFD_ROHM_BD70528 - select LINEAR_RANGES - help - Say Y here to enable support for getting battery status - information and altering charger configurations from charger - block of the ROHM BD70528 Power Management IC. - config CHARGER_BD99954 tristate "ROHM bd99954 charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a7309a3d1a47..33059a91f60c 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o -obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o +obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o @@ -96,7 +96,6 @@ obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o -obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 41c69a4f2a1f..0c940571e5b0 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -506,9 +506,6 @@ struct abx500_bm_data { int usb_safety_tmr_h; int bkup_bat_v; int bkup_bat_i; - bool autopower_cfg; - bool ac_enabled; - bool usb_enabled; bool no_maintenance; bool capacity_scaling; bool chg_unknown_bat; @@ -730,4 +727,8 @@ int ab8500_bm_of_probe(struct device *dev, struct device_node *np, struct abx500_bm_data *bm); +extern struct platform_driver ab8500_fg_driver; +extern struct platform_driver ab8500_btemp_driver; +extern struct platform_driver abx500_chargalg_driver; + #endif /* _AB8500_CHARGER_H_ */ diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h index 94a6f9068bc5..07e6ff50084f 100644 --- a/drivers/power/supply/ab8500-chargalg.h +++ b/drivers/power/supply/ab8500-chargalg.h @@ -15,7 +15,7 @@ * - POWER_SUPPLY_TYPE_USB, * because only them store as drv_data pointer to struct ux500_charger. */ -#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy) +#define psy_to_ux500_charger(x) power_supply_get_drvdata(x) /* Forward declaration */ struct ux500_charger; diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index fdfcd59fc43e..dbdcff32f353 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev) return 0; } -static int ab8500_btemp_remove(struct platform_device *pdev) -{ - struct ab8500_btemp *di = platform_get_drvdata(pdev); - int i, irq; - - /* Disable interrupts */ - for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) { - irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); - free_irq(irq, di); - } - - /* Delete the work queue */ - destroy_workqueue(di->btemp_wq); - - flush_scheduled_work(); - power_supply_unregister(di->btemp_psy); - - return 0; -} - static char *supply_interface[] = { "ab8500_chargalg", "ab8500_fg", @@ -966,9 +947,42 @@ static const struct power_supply_desc ab8500_btemp_desc = { .external_power_changed = ab8500_btemp_external_power_changed, }; +static int ab8500_btemp_bind(struct device *dev, struct device *master, + void *data) +{ + struct ab8500_btemp *di = dev_get_drvdata(dev); + + /* Create a work queue for the btemp */ + di->btemp_wq = + alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0); + if (di->btemp_wq == NULL) { + dev_err(dev, "failed to create work queue\n"); + return -ENOMEM; + } + + /* Kick off periodic temperature measurements */ + ab8500_btemp_periodic(di, true); + + return 0; +} + +static void ab8500_btemp_unbind(struct device *dev, struct device *master, + void *data) +{ + struct ab8500_btemp *di = dev_get_drvdata(dev); + + /* Delete the work queue */ + destroy_workqueue(di->btemp_wq); + flush_scheduled_work(); +} + +static const struct component_ops ab8500_btemp_component_ops = { + .bind = ab8500_btemp_bind, + .unbind = ab8500_btemp_unbind, +}; + static int ab8500_btemp_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct power_supply_config psy_cfg = {}; struct device *dev = &pdev->dev; struct ab8500_btemp *di; @@ -981,12 +995,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) di->bm = &ab8500_bm_data; - ret = ab8500_bm_of_probe(dev, np, di->bm); - if (ret) { - dev_err(dev, "failed to get battery information\n"); - return ret; - } - /* get parent data */ di->dev = dev; di->parent = dev_get_drvdata(pdev->dev.parent); @@ -1011,14 +1019,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev) psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.drv_data = di; - /* Create a work queue for the btemp */ - di->btemp_wq = - alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0); - if (di->btemp_wq == NULL) { - dev_err(dev, "failed to create work queue\n"); - return -ENOMEM; - } - /* Init work for measuring temperature periodically */ INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, ab8500_btemp_periodic_work); @@ -1031,7 +1031,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev) AB8500_BTEMP_HIGH_TH, &val); if (ret < 0) { dev_err(dev, "%s ab8500 read failed\n", __func__); - goto free_btemp_wq; + return ret; } switch (val) { case BTEMP_HIGH_TH_57_0: @@ -1050,30 +1050,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev) } /* Register BTEMP power supply class */ - di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc, - &psy_cfg); + di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc, + &psy_cfg); if (IS_ERR(di->btemp_psy)) { dev_err(dev, "failed to register BTEMP psy\n"); - ret = PTR_ERR(di->btemp_psy); - goto free_btemp_wq; + return PTR_ERR(di->btemp_psy); } /* Register interrupts */ for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) { irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); - if (irq < 0) { - ret = irq; - goto free_irq; - } + if (irq < 0) + return irq; - ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr, + ret = devm_request_threaded_irq(dev, irq, NULL, + ab8500_btemp_irq[i].isr, IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ab8500_btemp_irq[i].name, di); if (ret) { dev_err(dev, "failed to request %s IRQ %d: %d\n" , ab8500_btemp_irq[i].name, irq, ret); - goto free_irq; + return ret; } dev_dbg(dev, "Requested %s IRQ %d: %d\n", ab8500_btemp_irq[i].name, irq, ret); @@ -1081,23 +1079,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, di); - /* Kick off periodic temperature measurements */ - ab8500_btemp_periodic(di, true); list_add_tail(&di->node, &ab8500_btemp_list); - return ret; + return component_add(dev, &ab8500_btemp_component_ops); +} -free_irq: - /* We also have to free all successfully registered irqs */ - for (i = i - 1; i >= 0; i--) { - irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); - free_irq(irq, di); - } +static int ab8500_btemp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &ab8500_btemp_component_ops); - power_supply_unregister(di->btemp_psy); -free_btemp_wq: - destroy_workqueue(di->btemp_wq); - return ret; + return 0; } static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume); @@ -1106,8 +1097,9 @@ static const struct of_device_id ab8500_btemp_match[] = { { .compatible = "stericsson,ab8500-btemp", }, { }, }; +MODULE_DEVICE_TABLE(of, ab8500_btemp_match); -static struct platform_driver ab8500_btemp_driver = { +struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, .remove = ab8500_btemp_remove, .driver = { @@ -1116,20 +1108,6 @@ static struct platform_driver ab8500_btemp_driver = { .pm = &ab8500_btemp_pm_ops, }, }; - -static int __init ab8500_btemp_init(void) -{ - return platform_driver_register(&ab8500_btemp_driver); -} - -static void __exit ab8500_btemp_exit(void) -{ - platform_driver_unregister(&ab8500_btemp_driver); -} - -device_initcall(ab8500_btemp_init); -module_exit(ab8500_btemp_exit); - MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); MODULE_ALIAS("platform:ab8500-btemp"); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index a9be10eb2c22..fa49e12e5a60 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -414,6 +415,14 @@ disable_otp: static void ab8500_power_supply_changed(struct ab8500_charger *di, struct power_supply *psy) { + /* + * This happens if we get notifications or interrupts and + * the platform has been configured not to support one or + * other type of charging. + */ + if (!psy) + return; + if (di->autopower_cfg) { if (!di->usb.charger_connected && !di->ac.charger_connected && @@ -440,7 +449,15 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, if (!connected) di->flags.vbus_drop_end = false; - sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, "present"); + /* + * Sometimes the platform is configured not to support + * USB charging and no psy has been created, but we still + * will get these notifications. + */ + if (di->usb_chg.psy) { + sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, + "present"); + } if (connected) { mutex_lock(&di->charger_attached_mutex); @@ -3171,9 +3188,6 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, enum ab8500_usb_state bm_usb_state; unsigned mA = *((unsigned *)power); - if (!di) - return NOTIFY_DONE; - if (event != USB_EVENT_VBUS) { dev_dbg(di->dev, "not a standard host, returning\n"); return NOTIFY_DONE; @@ -3276,50 +3290,6 @@ static struct notifier_block charger_nb = { .notifier_call = ab8500_external_charger_prepare, }; -static int ab8500_charger_remove(struct platform_device *pdev) -{ - struct ab8500_charger *di = platform_get_drvdata(pdev); - int i, irq, ret; - - /* Disable AC charging */ - ab8500_charger_ac_en(&di->ac_chg, false, 0, 0); - - /* Disable USB charging */ - ab8500_charger_usb_en(&di->usb_chg, false, 0, 0); - - /* Disable interrupts */ - for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { - irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); - free_irq(irq, di); - } - - /* Backup battery voltage and current disable */ - ret = abx500_mask_and_set_register_interruptible(di->dev, - AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0); - if (ret < 0) - dev_err(di->dev, "%s mask and set failed\n", __func__); - - usb_unregister_notifier(di->usb_phy, &di->nb); - usb_put_phy(di->usb_phy); - - /* Delete the work queue */ - destroy_workqueue(di->charger_wq); - - /* Unregister external charger enable notifier */ - if (!di->ac_chg.enabled) - blocking_notifier_chain_unregister( - &charger_notifier_list, &charger_nb); - - flush_scheduled_work(); - if (di->usb_chg.enabled) - power_supply_unregister(di->usb_chg.psy); - - if (di->ac_chg.enabled && !di->ac_chg.external) - power_supply_unregister(di->ac_chg.psy); - - return 0; -} - static char *supply_interface[] = { "ab8500_chargalg", "ab8500_fg", @@ -3342,13 +3312,100 @@ static const struct power_supply_desc ab8500_usb_chg_desc = { .get_property = ab8500_charger_usb_get_property, }; +static int ab8500_charger_bind(struct device *dev) +{ + struct ab8500_charger *di = dev_get_drvdata(dev); + int ch_stat; + int ret; + + /* Create a work queue for the charger */ + di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq", + WQ_MEM_RECLAIM); + if (di->charger_wq == NULL) { + dev_err(dev, "failed to create work queue\n"); + return -ENOMEM; + } + + ch_stat = ab8500_charger_detect_chargers(di, false); + + if (ch_stat & AC_PW_CONN) { + if (is_ab8500(di->parent)) + queue_delayed_work(di->charger_wq, + &di->ac_charger_attached_work, + HZ); + } + if (ch_stat & USB_PW_CONN) { + if (is_ab8500(di->parent)) + queue_delayed_work(di->charger_wq, + &di->usb_charger_attached_work, + HZ); + di->vbus_detected = true; + di->vbus_detected_start = true; + queue_work(di->charger_wq, + &di->detect_usb_type_work); + } + + ret = component_bind_all(dev, di); + if (ret) { + dev_err(dev, "can't bind component devices\n"); + return ret; + } + + return 0; +} + +static void ab8500_charger_unbind(struct device *dev) +{ + struct ab8500_charger *di = dev_get_drvdata(dev); + int ret; + + /* Disable AC charging */ + ab8500_charger_ac_en(&di->ac_chg, false, 0, 0); + + /* Disable USB charging */ + ab8500_charger_usb_en(&di->usb_chg, false, 0, 0); + + /* Backup battery voltage and current disable */ + ret = abx500_mask_and_set_register_interruptible(di->dev, + AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0); + if (ret < 0) + dev_err(di->dev, "%s mask and set failed\n", __func__); + + /* Delete the work queue */ + destroy_workqueue(di->charger_wq); + + flush_scheduled_work(); + + /* Unbind fg, btemp, algorithm */ + component_unbind_all(dev, di); +} + +static const struct component_master_ops ab8500_charger_comp_ops = { + .bind = ab8500_charger_bind, + .unbind = ab8500_charger_unbind, +}; + +static struct platform_driver *const ab8500_charger_component_drivers[] = { + &ab8500_fg_driver, + &ab8500_btemp_driver, + &abx500_chargalg_driver, +}; + +static int ab8500_charger_compare_dev(struct device *dev, void *data) +{ + return dev == data; +} + static int ab8500_charger_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct component_match *match = NULL; struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {}; struct ab8500_charger *di; - int irq, i, charger_status, ret = 0, ch_stat; - struct device *dev = &pdev->dev; + int charger_status; + int i, irq; + int ret; di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); if (!di) @@ -3393,6 +3450,38 @@ static int ab8500_charger_probe(struct platform_device *pdev) return ret; } + /* + * VDD ADC supply needs to be enabled from this driver when there + * is a charger connected to avoid erroneous BTEMP_HIGH/LOW + * interrupts during charging + */ + di->regu = devm_regulator_get(dev, "vddadc"); + if (IS_ERR(di->regu)) { + ret = PTR_ERR(di->regu); + dev_err(dev, "failed to get vddadc regulator\n"); + return ret; + } + + /* Request interrupts */ + for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { + irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, + irq, NULL, ab8500_charger_irq[i].isr, + IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, + ab8500_charger_irq[i].name, di); + + if (ret != 0) { + dev_err(dev, "failed to request %s IRQ %d: %d\n" + , ab8500_charger_irq[i].name, irq, ret); + return ret; + } + dev_dbg(dev, "Requested %s IRQ %d: %d\n", + ab8500_charger_irq[i].name, irq, ret); + } + /* initialize lock */ spin_lock_init(&di->usb_state.usb_lock); mutex_init(&di->usb_ipt_crnt_lock); @@ -3419,14 +3508,16 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.max_out_curr = di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; - di->ac_chg.enabled = di->bm->ac_enabled; + /* + * The AB8505 only supports USB charging. If we are not the + * AB8505, register an AC charger. + * + * TODO: if this should be opt-in, add DT properties for this. + */ + if (!is_ab8505(di->parent)) + di->ac_chg.enabled = true; di->ac_chg.external = false; - /*notifier for external charger enabling*/ - if (!di->ac_chg.enabled) - blocking_notifier_chain_register( - &charger_notifier_list, &charger_nb); - /* USB supply */ /* ux500_charger sub-class */ di->usb_chg.ops.enable = &ab8500_charger_usb_en; @@ -3438,18 +3529,9 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.max_out_curr = di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; - di->usb_chg.enabled = di->bm->usb_enabled; di->usb_chg.external = false; di->usb_state.usb_current = -1; - /* Create a work queue for the charger */ - di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq", - WQ_MEM_RECLAIM); - if (di->charger_wq == NULL) { - dev_err(dev, "failed to create work queue\n"); - return -ENOMEM; - } - mutex_init(&di->charger_attached_mutex); /* Init work for HW failure check */ @@ -3500,61 +3582,32 @@ static int ab8500_charger_probe(struct platform_device *pdev) INIT_WORK(&di->check_usb_thermal_prot_work, ab8500_charger_check_usb_thermal_prot_work); - /* - * VDD ADC supply needs to be enabled from this driver when there - * is a charger connected to avoid erroneous BTEMP_HIGH/LOW - * interrupts during charging - */ - di->regu = devm_regulator_get(dev, "vddadc"); - if (IS_ERR(di->regu)) { - ret = PTR_ERR(di->regu); - dev_err(dev, "failed to get vddadc regulator\n"); - goto free_charger_wq; - } - /* Initialize OVV, and other registers */ ret = ab8500_charger_init_hw_registers(di); if (ret) { dev_err(dev, "failed to initialize ABB registers\n"); - goto free_charger_wq; + return ret; } /* Register AC charger class */ if (di->ac_chg.enabled) { - di->ac_chg.psy = power_supply_register(dev, + di->ac_chg.psy = devm_power_supply_register(dev, &ab8500_ac_chg_desc, &ac_psy_cfg); if (IS_ERR(di->ac_chg.psy)) { dev_err(dev, "failed to register AC charger\n"); - ret = PTR_ERR(di->ac_chg.psy); - goto free_charger_wq; + return PTR_ERR(di->ac_chg.psy); } } /* Register USB charger class */ - if (di->usb_chg.enabled) { - di->usb_chg.psy = power_supply_register(dev, - &ab8500_usb_chg_desc, - &usb_psy_cfg); - if (IS_ERR(di->usb_chg.psy)) { - dev_err(dev, "failed to register USB charger\n"); - ret = PTR_ERR(di->usb_chg.psy); - goto free_ac; - } - } - - di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(di->usb_phy)) { - dev_err(dev, "failed to get usb transceiver\n"); - ret = -EINVAL; - goto free_usb; - } - di->nb.notifier_call = ab8500_charger_usb_notifier_call; - ret = usb_register_notifier(di->usb_phy, &di->nb); - if (ret) { - dev_err(dev, "failed to register usb notifier\n"); - goto put_usb_phy; + di->usb_chg.psy = devm_power_supply_register(dev, + &ab8500_usb_chg_desc, + &usb_psy_cfg); + if (IS_ERR(di->usb_chg.psy)) { + dev_err(dev, "failed to register USB charger\n"); + return PTR_ERR(di->usb_chg.psy); } /* Identify the connected charger types during startup */ @@ -3566,84 +3619,93 @@ static int ab8500_charger_probe(struct platform_device *pdev) sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); } - if (charger_status & USB_PW_CONN) { - di->vbus_detected = true; - di->vbus_detected_start = true; - queue_work(di->charger_wq, - &di->detect_usb_type_work); - } - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { - irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); - if (irq < 0) { - ret = irq; - goto free_irq; - } - - ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr, - IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, - ab8500_charger_irq[i].name, di); - - if (ret != 0) { - dev_err(dev, "failed to request %s IRQ %d: %d\n" - , ab8500_charger_irq[i].name, irq, ret); - goto free_irq; - } - dev_dbg(dev, "Requested %s IRQ %d: %d\n", - ab8500_charger_irq[i].name, irq, ret); - } - platform_set_drvdata(pdev, di); - mutex_lock(&di->charger_attached_mutex); + /* Create something that will match the subdrivers when we bind */ + for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) { + struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver; + struct device *p = NULL, *d; - ch_stat = ab8500_charger_detect_chargers(di, false); - - if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) { - if (is_ab8500(di->parent)) - queue_delayed_work(di->charger_wq, - &di->ac_charger_attached_work, - HZ); + while ((d = platform_find_device_by_driver(p, drv))) { + put_device(p); + component_match_add(dev, &match, + ab8500_charger_compare_dev, d); + p = d; + } + put_device(p); } - if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) { - if (is_ab8500(di->parent)) - queue_delayed_work(di->charger_wq, - &di->usb_charger_attached_work, - HZ); + if (!match) { + dev_err(dev, "no matching components\n"); + return -ENODEV; + } + if (IS_ERR(match)) { + dev_err(dev, "could not create component match\n"); + return PTR_ERR(match); } - mutex_unlock(&di->charger_attached_mutex); + /* Notifier for external charger enabling */ + if (!di->ac_chg.enabled) + blocking_notifier_chain_register( + &charger_notifier_list, &charger_nb); - return ret; -free_irq: + di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); + if (IS_ERR_OR_NULL(di->usb_phy)) { + dev_err(dev, "failed to get usb transceiver\n"); + ret = -EINVAL; + goto out_charger_notifier; + } + di->nb.notifier_call = ab8500_charger_usb_notifier_call; + ret = usb_register_notifier(di->usb_phy, &di->nb); + if (ret) { + dev_err(dev, "failed to register usb notifier\n"); + goto put_usb_phy; + } + + + ret = component_master_add_with_match(&pdev->dev, + &ab8500_charger_comp_ops, + match); + if (ret) { + dev_err(dev, "failed to add component master\n"); + goto free_notifier; + } + + return 0; + +free_notifier: usb_unregister_notifier(di->usb_phy, &di->nb); - - /* We also have to free all successfully registered irqs */ - for (i = i - 1; i >= 0; i--) { - irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); - free_irq(irq, di); - } put_usb_phy: usb_put_phy(di->usb_phy); -free_usb: - if (di->usb_chg.enabled) - power_supply_unregister(di->usb_chg.psy); -free_ac: - if (di->ac_chg.enabled) - power_supply_unregister(di->ac_chg.psy); -free_charger_wq: - destroy_workqueue(di->charger_wq); +out_charger_notifier: + if (!di->ac_chg.enabled) + blocking_notifier_chain_unregister( + &charger_notifier_list, &charger_nb); return ret; } +static int ab8500_charger_remove(struct platform_device *pdev) +{ + struct ab8500_charger *di = platform_get_drvdata(pdev); + + component_master_del(&pdev->dev, &ab8500_charger_comp_ops); + + usb_unregister_notifier(di->usb_phy, &di->nb); + usb_put_phy(di->usb_phy); + if (!di->ac_chg.enabled) + blocking_notifier_chain_unregister( + &charger_notifier_list, &charger_nb); + + return 0; +} + static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume); static const struct of_device_id ab8500_charger_match[] = { { .compatible = "stericsson,ab8500-charger", }, { }, }; +MODULE_DEVICE_TABLE(of, ab8500_charger_match); static struct platform_driver ab8500_charger_driver = { .probe = ab8500_charger_probe, @@ -3657,15 +3719,24 @@ static struct platform_driver ab8500_charger_driver = { static int __init ab8500_charger_init(void) { + int ret; + + ret = platform_register_drivers(ab8500_charger_component_drivers, + ARRAY_SIZE(ab8500_charger_component_drivers)); + if (ret) + return ret; + return platform_driver_register(&ab8500_charger_driver); } static void __exit ab8500_charger_exit(void) { + platform_unregister_drivers(ab8500_charger_component_drivers, + ARRAY_SIZE(ab8500_charger_component_drivers)); platform_driver_unregister(&ab8500_charger_driver); } -subsys_initcall_sync(ab8500_charger_init); +module_init(ab8500_charger_init); module_exit(ab8500_charger_exit); MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 0c7c01a0d979..3d45ed0157c6 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -59,7 +60,7 @@ ((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1)))); /** - * struct ab8500_fg_interrupts - ab8500 fg interupts + * struct ab8500_fg_interrupts - ab8500 fg interrupts * @name: name of the interrupt * @isr function pointer to the isr */ @@ -2980,27 +2981,6 @@ static int __maybe_unused ab8500_fg_suspend(struct device *dev) return 0; } -static int ab8500_fg_remove(struct platform_device *pdev) -{ - int ret = 0; - struct ab8500_fg *di = platform_get_drvdata(pdev); - - list_del(&di->node); - - /* Disable coulomb counter */ - ret = ab8500_fg_coulomb_counter(di, false); - if (ret) - dev_err(di->dev, "failed to disable coulomb counter\n"); - - destroy_workqueue(di->fg_wq); - ab8500_fg_sysfs_exit(di); - - flush_scheduled_work(); - ab8500_fg_sysfs_psy_remove_attrs(di); - power_supply_unregister(di->fg_psy); - return ret; -} - /* ab8500 fg driver interrupts and their respective isr */ static struct ab8500_fg_interrupts ab8500_fg_irq[] = { {"NCONV_ACCU", ab8500_fg_cc_convend_handler}, @@ -3024,11 +3004,50 @@ static const struct power_supply_desc ab8500_fg_desc = { .external_power_changed = ab8500_fg_external_power_changed, }; +static int ab8500_fg_bind(struct device *dev, struct device *master, + void *data) +{ + struct ab8500_fg *di = dev_get_drvdata(dev); + + /* Create a work queue for running the FG algorithm */ + di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM); + if (di->fg_wq == NULL) { + dev_err(dev, "failed to create work queue\n"); + return -ENOMEM; + } + + /* Start the coulomb counter */ + ab8500_fg_coulomb_counter(di, true); + /* Run the FG algorithm */ + queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); + + return 0; +} + +static void ab8500_fg_unbind(struct device *dev, struct device *master, + void *data) +{ + struct ab8500_fg *di = dev_get_drvdata(dev); + int ret; + + /* Disable coulomb counter */ + ret = ab8500_fg_coulomb_counter(di, false); + if (ret) + dev_err(dev, "failed to disable coulomb counter\n"); + + destroy_workqueue(di->fg_wq); + flush_scheduled_work(); +} + +static const struct component_ops ab8500_fg_component_ops = { + .bind = ab8500_fg_bind, + .unbind = ab8500_fg_unbind, +}; + static int ab8500_fg_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - struct power_supply_config psy_cfg = {}; struct device *dev = &pdev->dev; + struct power_supply_config psy_cfg = {}; struct ab8500_fg *di; int i, irq; int ret = 0; @@ -3039,12 +3058,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) di->bm = &ab8500_bm_data; - ret = ab8500_bm_of_probe(dev, np, di->bm); - if (ret) { - dev_err(dev, "failed to get battery information\n"); - return ret; - } - mutex_init(&di->cc_lock); /* get parent data */ @@ -3074,13 +3087,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT); ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT); - /* Create a work queue for running the FG algorithm */ - di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM); - if (di->fg_wq == NULL) { - dev_err(dev, "failed to create work queue\n"); - return -ENOMEM; - } - /* Init work for running the fg algorithm instantly */ INIT_WORK(&di->fg_work, ab8500_fg_instant_work); @@ -3113,7 +3119,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) ret = ab8500_fg_init_hw_registers(di); if (ret) { dev_err(dev, "failed to initialize registers\n"); - goto free_inst_curr_wq; + return ret; } /* Consider battery unknown until we're informed otherwise */ @@ -3121,15 +3127,13 @@ static int ab8500_fg_probe(struct platform_device *pdev) di->flags.batt_id_received = false; /* Register FG power supply class */ - di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg); + di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg); if (IS_ERR(di->fg_psy)) { dev_err(dev, "failed to register FG psy\n"); - ret = PTR_ERR(di->fg_psy); - goto free_inst_curr_wq; + return PTR_ERR(di->fg_psy); } di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer); - ab8500_fg_coulomb_counter(di, true); /* * Initialize completion used to notify completion and start @@ -3141,19 +3145,18 @@ static int ab8500_fg_probe(struct platform_device *pdev) /* Register primary interrupt handlers */ for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) { irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); - if (irq < 0) { - ret = irq; - goto free_irq; - } + if (irq < 0) + return irq; - ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr, + ret = devm_request_threaded_irq(dev, irq, NULL, + ab8500_fg_irq[i].isr, IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, ab8500_fg_irq[i].name, di); if (ret != 0) { dev_err(dev, "failed to request %s IRQ %d: %d\n", ab8500_fg_irq[i].name, irq, ret); - goto free_irq; + return ret; } dev_dbg(dev, "Requested %s IRQ %d: %d\n", ab8500_fg_irq[i].name, irq, ret); @@ -3168,14 +3171,14 @@ static int ab8500_fg_probe(struct platform_device *pdev) ret = ab8500_fg_sysfs_init(di); if (ret) { dev_err(dev, "failed to create sysfs entry\n"); - goto free_irq; + return ret; } ret = ab8500_fg_sysfs_psy_create_attrs(di); if (ret) { dev_err(dev, "failed to create FG psy\n"); ab8500_fg_sysfs_exit(di); - goto free_irq; + return ret; } /* Calibrate the fg first time */ @@ -3185,24 +3188,21 @@ static int ab8500_fg_probe(struct platform_device *pdev) /* Use room temp as default value until we get an update from driver. */ di->bat_temp = 210; - /* Run the FG algorithm */ - queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); - list_add_tail(&di->node, &ab8500_fg_list); - return ret; + return component_add(dev, &ab8500_fg_component_ops); +} -free_irq: - /* We also have to free all registered irqs */ - while (--i >= 0) { - /* Last assignment of i from primary interrupt handlers */ - irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); - free_irq(irq, di); - } +static int ab8500_fg_remove(struct platform_device *pdev) +{ + int ret = 0; + struct ab8500_fg *di = platform_get_drvdata(pdev); + + component_del(&pdev->dev, &ab8500_fg_component_ops); + list_del(&di->node); + ab8500_fg_sysfs_exit(di); + ab8500_fg_sysfs_psy_remove_attrs(di); - power_supply_unregister(di->fg_psy); -free_inst_curr_wq: - destroy_workqueue(di->fg_wq); return ret; } @@ -3212,8 +3212,9 @@ static const struct of_device_id ab8500_fg_match[] = { { .compatible = "stericsson,ab8500-fg", }, { }, }; +MODULE_DEVICE_TABLE(of, ab8500_fg_match); -static struct platform_driver ab8500_fg_driver = { +struct platform_driver ab8500_fg_driver = { .probe = ab8500_fg_probe, .remove = ab8500_fg_remove, .driver = { @@ -3222,20 +3223,6 @@ static struct platform_driver ab8500_fg_driver = { .pm = &ab8500_fg_pm_ops, }, }; - -static int __init ab8500_fg_init(void) -{ - return platform_driver_register(&ab8500_fg_driver); -} - -static void __exit ab8500_fg_exit(void) -{ - platform_driver_unregister(&ab8500_fg_driver); -} - -subsys_initcall_sync(ab8500_fg_init); -module_exit(ab8500_fg_exit); - MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); MODULE_ALIAS("platform:ab8500-fg"); diff --git a/drivers/power/supply/abx500_chargalg.c b/drivers/power/supply/abx500_chargalg.c index f5b792243727..a17849bfacbf 100644 --- a/drivers/power/supply/abx500_chargalg.c +++ b/drivers/power/supply/abx500_chargalg.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1943,28 +1944,6 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev) return 0; } -static int abx500_chargalg_remove(struct platform_device *pdev) -{ - struct abx500_chargalg *di = platform_get_drvdata(pdev); - - /* sysfs interface to enable/disbale charging from user space */ - abx500_chargalg_sysfs_exit(di); - - hrtimer_cancel(&di->safety_timer); - hrtimer_cancel(&di->maintenance_timer); - - cancel_delayed_work_sync(&di->chargalg_periodic_work); - cancel_delayed_work_sync(&di->chargalg_wd_work); - cancel_work_sync(&di->chargalg_work); - - /* Delete the work queue */ - destroy_workqueue(di->chargalg_wq); - - power_supply_unregister(di->chargalg_psy); - - return 0; -} - static char *supply_interface[] = { "ab8500_fg", }; @@ -1978,29 +1957,63 @@ static const struct power_supply_desc abx500_chargalg_desc = { .external_power_changed = abx500_chargalg_external_power_changed, }; +static int abx500_chargalg_bind(struct device *dev, struct device *master, + void *data) +{ + struct abx500_chargalg *di = dev_get_drvdata(dev); + + /* Create a work queue for the chargalg */ + di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq", + WQ_MEM_RECLAIM); + if (di->chargalg_wq == NULL) { + dev_err(di->dev, "failed to create work queue\n"); + return -ENOMEM; + } + + /* Run the charging algorithm */ + queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0); + + return 0; +} + +static void abx500_chargalg_unbind(struct device *dev, struct device *master, + void *data) +{ + struct abx500_chargalg *di = dev_get_drvdata(dev); + + /* Stop all timers and work */ + hrtimer_cancel(&di->safety_timer); + hrtimer_cancel(&di->maintenance_timer); + + cancel_delayed_work_sync(&di->chargalg_periodic_work); + cancel_delayed_work_sync(&di->chargalg_wd_work); + cancel_work_sync(&di->chargalg_work); + + /* Delete the work queue */ + destroy_workqueue(di->chargalg_wq); + flush_scheduled_work(); +} + +static const struct component_ops abx500_chargalg_component_ops = { + .bind = abx500_chargalg_bind, + .unbind = abx500_chargalg_unbind, +}; + static int abx500_chargalg_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct power_supply_config psy_cfg = {}; struct abx500_chargalg *di; int ret = 0; - di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); - if (!di) { - dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__); + di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); + if (!di) return -ENOMEM; - } di->bm = &ab8500_bm_data; - ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); - if (ret) { - dev_err(&pdev->dev, "failed to get battery information\n"); - return ret; - } - /* get device struct and parent */ - di->dev = &pdev->dev; + di->dev = dev; di->parent = dev_get_drvdata(pdev->dev.parent); psy_cfg.supplied_to = supply_interface; @@ -2016,14 +2029,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev) di->maintenance_timer.function = abx500_chargalg_maintenance_timer_expired; - /* Create a work queue for the chargalg */ - di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq", - WQ_MEM_RECLAIM); - if (di->chargalg_wq == NULL) { - dev_err(di->dev, "failed to create work queue\n"); - return -ENOMEM; - } - /* Init work for chargalg */ INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work, abx500_chargalg_periodic_work); @@ -2037,12 +2042,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev) di->chg_info.prev_conn_chg = -1; /* Register chargalg power supply class */ - di->chargalg_psy = power_supply_register(di->dev, &abx500_chargalg_desc, + di->chargalg_psy = devm_power_supply_register(di->dev, + &abx500_chargalg_desc, &psy_cfg); if (IS_ERR(di->chargalg_psy)) { dev_err(di->dev, "failed to register chargalg psy\n"); - ret = PTR_ERR(di->chargalg_psy); - goto free_chargalg_wq; + return PTR_ERR(di->chargalg_psy); } platform_set_drvdata(pdev, di); @@ -2051,21 +2056,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev) ret = abx500_chargalg_sysfs_init(di); if (ret) { dev_err(di->dev, "failed to create sysfs entry\n"); - goto free_psy; + return ret; } di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH; - /* Run the charging algorithm */ - queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0); - dev_info(di->dev, "probe success\n"); - return ret; + return component_add(dev, &abx500_chargalg_component_ops); +} -free_psy: - power_supply_unregister(di->chargalg_psy); -free_chargalg_wq: - destroy_workqueue(di->chargalg_wq); - return ret; +static int abx500_chargalg_remove(struct platform_device *pdev) +{ + struct abx500_chargalg *di = platform_get_drvdata(pdev); + + component_del(&pdev->dev, &abx500_chargalg_component_ops); + + /* sysfs interface to enable/disable charging from user space */ + abx500_chargalg_sysfs_exit(di); + + return 0; } static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume); @@ -2075,7 +2083,7 @@ static const struct of_device_id ab8500_chargalg_match[] = { { }, }; -static struct platform_driver abx500_chargalg_driver = { +struct platform_driver abx500_chargalg_driver = { .probe = abx500_chargalg_probe, .remove = abx500_chargalg_remove, .driver = { @@ -2084,9 +2092,6 @@ static struct platform_driver abx500_chargalg_driver = { .pm = &abx500_chargalg_pm_ops, }, }; - -module_platform_driver(abx500_chargalg_driver); - MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); MODULE_ALIAS("platform:abx500-chargalg"); diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index e84b6e4da14a..18a9db0df4b1 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -40,6 +40,7 @@ #define AXP209_FG_PERCENT GENMASK(6, 0) #define AXP22X_FG_VALID BIT(7) +#define AXP20X_CHRG_CTRL1_ENABLE BIT(7) #define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5) #define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5) #define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5) @@ -468,7 +469,18 @@ static int axp20x_battery_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: return axp20x_set_max_constant_charge_current(axp20x_batt, val->intval); + case POWER_SUPPLY_PROP_STATUS: + switch (val->intval) { + case POWER_SUPPLY_STATUS_CHARGING: + return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, + AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE); + case POWER_SUPPLY_STATUS_DISCHARGING: + case POWER_SUPPLY_STATUS_NOT_CHARGING: + return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, + AXP20X_CHRG_CTRL1_ENABLE, 0); + } + fallthrough; default: return -EINVAL; } @@ -491,7 +503,8 @@ static enum power_supply_property axp20x_battery_props[] = { static int axp20x_battery_prop_writeable(struct power_supply *psy, enum power_supply_property psp) { - return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN || + return psp == POWER_SUPPLY_PROP_STATUS || + psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN || psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 39e16ecb7638..2ba2d8d6b8e6 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -142,9 +142,7 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg) for (i = 0; i < NR_RETRY_CNT; i++) { ret = regmap_read(info->regmap, reg, &val); - if (ret == -EBUSY) - continue; - else + if (ret != -EBUSY) break; } @@ -676,7 +674,7 @@ intr_failed: * detection reports one despite it not being there. * Please keep this listed sorted alphabetically. */ -static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { +static const struct dmi_system_id axp288_no_battery_list[] = { { /* ACEPC T8 Cherry Trail Z8350 mini PC */ .matches = { @@ -723,15 +721,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MEEGOPAD T02"), }, }, - { - /* Meegopad T08 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Default string"), - DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by OEM."), - DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), - DMI_MATCH(DMI_BOARD_VERSION, "V1.1"), - }, - }, { /* Mele PCG03 Mini PC */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"), @@ -745,6 +734,15 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), } }, + { + /* Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"), + DMI_MATCH(DMI_CHASSIS_TYPE, "3"), + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + DMI_MATCH(DMI_BIOS_VERSION, "5.11"), + }, + }, {} }; @@ -764,7 +762,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) }; unsigned int val; - if (dmi_check_system(axp288_fuel_gauge_blacklist)) + if (dmi_check_system(axp288_no_battery_list)) return -ENODEV; /* diff --git a/drivers/power/supply/bd70528-charger.c b/drivers/power/supply/bd70528-charger.c deleted file mode 100644 index 7c1f0b99c71b..000000000000 --- a/drivers/power/supply/bd70528-charger.c +++ /dev/null @@ -1,710 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// -// Copyright (C) 2018 ROHM Semiconductors -// -// power-supply driver for ROHM BD70528 PMIC - -/* - * BD70528 charger HW state machine. - * - * The thermal shutdown state is not drawn. From any other state but - * battery error and suspend it is possible to go to TSD/TMP states - * if temperature is out of bounds. - * - * CHG_RST = H - * or CHG_EN=L - * or (DCIN2_UVLO=L && DCIN1_UVLO=L) - * or (DCIN2_OVLO=H & DCIN1_UVKLO=L) - * - * +--------------+ +--------------+ - * | | | | - * | Any state +-------> | Suspend | - * | | | | - * +--------------+ +------+-------+ - * | - * CHG_EN = H && BAT_DET = H && | - * No errors (temp, bat_ov, UVLO, | - * OVLO...) | - * | - * BAT_OV or +---------v----------+ - * (DBAT && TTRI) | | - * +-----------------+ Trickle Charge | <---------------+ - * | | | | - * | +-------+------------+ | - * | | | - * | | ^ | - * | V_BAT > VTRI_TH | | VBAT < VTRI_TH - 50mV | - * | | | | - * | v | | - * | | | - * | BAT_OV or +----------+----+ | - * | (DBAT && TFST) | | | - * | +----------------+ Fast Charge | | - * | | | | | - * v v +----+----------+ | - * | | - *+----------------+ ILIM_DET=L | ^ ILIM_DET | - *| | & CV_DET=H | | or CV_DET=L | - *| Battery Error | & VBAT > | | or VBAT < VRECHG_TH | - *| | VRECHG_TH | | or IBAT > IFST/x | - *+----------------+ & IBAT < | | | - * IFST/x v | | - * ^ | | - * | +---------+-+ | - * | | | | - * +-------------------+ Top OFF | | - * BAT_OV = H or | | | - * (DBAT && TFST) +-----+-----+ | - * | | - * Stay top-off for 15s | | - * v | - * | - * +--------+ | - * | | | - * | Done +-------------------------+ - * | | - * +--------+ VBAT < VRECHG_TH - */ - -#include -#include -#include -#include -#include -#include -#include - -#define CHG_STAT_SUSPEND 0x0 -#define CHG_STAT_TRICKLE 0x1 -#define CHG_STAT_FAST 0x3 -#define CHG_STAT_TOPOFF 0xe -#define CHG_STAT_DONE 0xf -#define CHG_STAT_OTP_TRICKLE 0x10 -#define CHG_STAT_OTP_FAST 0x11 -#define CHG_STAT_OTP_DONE 0x12 -#define CHG_STAT_TSD_TRICKLE 0x20 -#define CHG_STAT_TSD_FAST 0x21 -#define CHG_STAT_TSD_TOPOFF 0x22 -#define CHG_STAT_BAT_ERR 0x7f - -static const char *bd70528_charger_model = "BD70528"; -static const char *bd70528_charger_manufacturer = "ROHM Semiconductors"; - -#define BD_ERR_IRQ_HND(_name_, _wrn_) \ -static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg) \ -{ \ - struct power_supply *psy = (struct power_supply *)arg; \ - \ - power_supply_changed(psy); \ - dev_err(&psy->dev, (_wrn_)); \ - \ - return IRQ_HANDLED; \ -} - -#define BD_INFO_IRQ_HND(_name_, _wrn_) \ -static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg) \ -{ \ - struct power_supply *psy = (struct power_supply *)arg; \ - \ - power_supply_changed(psy); \ - dev_dbg(&psy->dev, (_wrn_)); \ - \ - return IRQ_HANDLED; \ -} - -#define BD_IRQ_HND(_name_) bd0528_##_name_##_interrupt - -struct bd70528_psy { - struct regmap *regmap; - struct device *dev; - struct power_supply *psy; -}; - -BD_ERR_IRQ_HND(BAT_OV_DET, "Battery overvoltage detected\n"); -BD_ERR_IRQ_HND(DBAT_DET, "Dead battery detected\n"); -BD_ERR_IRQ_HND(COLD_DET, "Battery cold\n"); -BD_ERR_IRQ_HND(HOT_DET, "Battery hot\n"); -BD_ERR_IRQ_HND(CHG_TSD, "Charger thermal shutdown\n"); -BD_ERR_IRQ_HND(DCIN2_OV_DET, "DCIN2 overvoltage detected\n"); - -BD_INFO_IRQ_HND(BAT_OV_RES, "Battery voltage back to normal\n"); -BD_INFO_IRQ_HND(COLD_RES, "Battery temperature back to normal\n"); -BD_INFO_IRQ_HND(HOT_RES, "Battery temperature back to normal\n"); -BD_INFO_IRQ_HND(BAT_RMV, "Battery removed\n"); -BD_INFO_IRQ_HND(BAT_DET, "Battery detected\n"); -BD_INFO_IRQ_HND(DCIN2_OV_RES, "DCIN2 voltage back to normal\n"); -BD_INFO_IRQ_HND(DCIN2_RMV, "DCIN2 removed\n"); -BD_INFO_IRQ_HND(DCIN2_DET, "DCIN2 detected\n"); -BD_INFO_IRQ_HND(DCIN1_RMV, "DCIN1 removed\n"); -BD_INFO_IRQ_HND(DCIN1_DET, "DCIN1 detected\n"); - -struct irq_name_pair { - const char *n; - irqreturn_t (*h)(int irq, void *arg); -}; - -static int bd70528_get_irqs(struct platform_device *pdev, - struct bd70528_psy *bdpsy) -{ - int irq, i, ret; - unsigned int mask; - static const struct irq_name_pair bd70528_chg_irqs[] = { - { .n = "bd70528-bat-ov-res", .h = BD_IRQ_HND(BAT_OV_RES) }, - { .n = "bd70528-bat-ov-det", .h = BD_IRQ_HND(BAT_OV_DET) }, - { .n = "bd70528-bat-dead", .h = BD_IRQ_HND(DBAT_DET) }, - { .n = "bd70528-bat-warmed", .h = BD_IRQ_HND(COLD_RES) }, - { .n = "bd70528-bat-cold", .h = BD_IRQ_HND(COLD_DET) }, - { .n = "bd70528-bat-cooled", .h = BD_IRQ_HND(HOT_RES) }, - { .n = "bd70528-bat-hot", .h = BD_IRQ_HND(HOT_DET) }, - { .n = "bd70528-chg-tshd", .h = BD_IRQ_HND(CHG_TSD) }, - { .n = "bd70528-bat-removed", .h = BD_IRQ_HND(BAT_RMV) }, - { .n = "bd70528-bat-detected", .h = BD_IRQ_HND(BAT_DET) }, - { .n = "bd70528-dcin2-ov-res", .h = BD_IRQ_HND(DCIN2_OV_RES) }, - { .n = "bd70528-dcin2-ov-det", .h = BD_IRQ_HND(DCIN2_OV_DET) }, - { .n = "bd70528-dcin2-removed", .h = BD_IRQ_HND(DCIN2_RMV) }, - { .n = "bd70528-dcin2-detected", .h = BD_IRQ_HND(DCIN2_DET) }, - { .n = "bd70528-dcin1-removed", .h = BD_IRQ_HND(DCIN1_RMV) }, - { .n = "bd70528-dcin1-detected", .h = BD_IRQ_HND(DCIN1_DET) }, - }; - - for (i = 0; i < ARRAY_SIZE(bd70528_chg_irqs); i++) { - irq = platform_get_irq_byname(pdev, bd70528_chg_irqs[i].n); - if (irq < 0) { - dev_err(&pdev->dev, "Bad IRQ information for %s (%d)\n", - bd70528_chg_irqs[i].n, irq); - return irq; - } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - bd70528_chg_irqs[i].h, - IRQF_ONESHOT, - bd70528_chg_irqs[i].n, - bdpsy->psy); - - if (ret) - return ret; - } - /* - * BD70528 irq controller is not touching the main mask register. - * So enable the charger block interrupts at main level. We can just - * leave them enabled as irq-controller should disable irqs - * from sub-registers when IRQ is disabled or freed. - */ - mask = BD70528_REG_INT_BAT1_MASK | BD70528_REG_INT_BAT2_MASK; - ret = regmap_update_bits(bdpsy->regmap, - BD70528_REG_INT_MAIN_MASK, mask, 0); - if (ret) - dev_err(&pdev->dev, "Failed to enable charger IRQs\n"); - - return ret; -} - -static int bd70528_get_charger_status(struct bd70528_psy *bdpsy, int *val) -{ - int ret; - unsigned int v; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v); - if (ret) { - dev_err(bdpsy->dev, "Charger state read failure %d\n", - ret); - return ret; - } - - switch (v & BD70528_MASK_CHG_STAT) { - case CHG_STAT_SUSPEND: - /* Maybe we should check the CHG_TTRI_EN? */ - case CHG_STAT_OTP_TRICKLE: - case CHG_STAT_OTP_FAST: - case CHG_STAT_OTP_DONE: - case CHG_STAT_TSD_TRICKLE: - case CHG_STAT_TSD_FAST: - case CHG_STAT_TSD_TOPOFF: - case CHG_STAT_BAT_ERR: - *val = POWER_SUPPLY_STATUS_NOT_CHARGING; - break; - case CHG_STAT_DONE: - *val = POWER_SUPPLY_STATUS_FULL; - break; - case CHG_STAT_TRICKLE: - case CHG_STAT_FAST: - case CHG_STAT_TOPOFF: - *val = POWER_SUPPLY_STATUS_CHARGING; - break; - default: - *val = POWER_SUPPLY_STATUS_UNKNOWN; - break; - } - - return 0; -} - -static int bd70528_get_charge_type(struct bd70528_psy *bdpsy, int *val) -{ - int ret; - unsigned int v; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v); - if (ret) { - dev_err(bdpsy->dev, "Charger state read failure %d\n", - ret); - return ret; - } - - switch (v & BD70528_MASK_CHG_STAT) { - case CHG_STAT_TRICKLE: - *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; - break; - case CHG_STAT_FAST: - case CHG_STAT_TOPOFF: - *val = POWER_SUPPLY_CHARGE_TYPE_FAST; - break; - case CHG_STAT_DONE: - case CHG_STAT_SUSPEND: - /* Maybe we should check the CHG_TTRI_EN? */ - case CHG_STAT_OTP_TRICKLE: - case CHG_STAT_OTP_FAST: - case CHG_STAT_OTP_DONE: - case CHG_STAT_TSD_TRICKLE: - case CHG_STAT_TSD_FAST: - case CHG_STAT_TSD_TOPOFF: - case CHG_STAT_BAT_ERR: - *val = POWER_SUPPLY_CHARGE_TYPE_NONE; - break; - default: - *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; - break; - } - - return 0; -} - -static int bd70528_get_battery_health(struct bd70528_psy *bdpsy, int *val) -{ - int ret; - unsigned int v; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v); - if (ret) { - dev_err(bdpsy->dev, "Battery state read failure %d\n", - ret); - return ret; - } - /* No battery? */ - if (!(v & BD70528_MASK_CHG_BAT_DETECT)) - *val = POWER_SUPPLY_HEALTH_DEAD; - else if (v & BD70528_MASK_CHG_BAT_OVERVOLT) - *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - else if (v & BD70528_MASK_CHG_BAT_TIMER) - *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; - else - *val = POWER_SUPPLY_HEALTH_GOOD; - - return 0; -} - -static int bd70528_get_online(struct bd70528_psy *bdpsy, int *val) -{ - int ret; - unsigned int v; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_IN_STAT, &v); - if (ret) { - dev_err(bdpsy->dev, "DC1 IN state read failure %d\n", - ret); - return ret; - } - - *val = (v & BD70528_MASK_CHG_DCIN1_UVLO) ? 1 : 0; - - return 0; -} - -static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val) -{ - int ret; - unsigned int v; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v); - if (ret) { - dev_err(bdpsy->dev, "Battery state read failure %d\n", - ret); - return ret; - } - - *val = (v & BD70528_MASK_CHG_BAT_DETECT) ? 1 : 0; - - return 0; -} - -static const struct linear_range current_limit_ranges[] = { - { - .min = 5, - .step = 1, - .min_sel = 0, - .max_sel = 0x22, - }, - { - .min = 40, - .step = 5, - .min_sel = 0x23, - .max_sel = 0x26, - }, - { - .min = 60, - .step = 20, - .min_sel = 0x27, - .max_sel = 0x2d, - }, - { - .min = 200, - .step = 50, - .min_sel = 0x2e, - .max_sel = 0x34, - }, - { - .min = 500, - .step = 0, - .min_sel = 0x35, - .max_sel = 0x3f, - }, -}; - -/* - * BD70528 would support setting and getting own charge current/ - * voltage for low temperatures. The driver currently only reads - * the charge current at room temperature. We do set both though. - */ -static const struct linear_range warm_charge_curr[] = { - { - .min = 10, - .step = 10, - .min_sel = 0, - .max_sel = 0x12, - }, - { - .min = 200, - .step = 25, - .min_sel = 0x13, - .max_sel = 0x1f, - }, -}; - -/* - * Cold charge current selectors are identical to warm charge current - * selectors. The difference is that only smaller currents are available - * at cold charge range. - */ -#define MAX_COLD_CHG_CURR_SEL 0x15 -#define MAX_WARM_CHG_CURR_SEL 0x1f -#define MIN_CHG_CURR_SEL 0x0 - -static int get_charge_current(struct bd70528_psy *bdpsy, int *ma) -{ - unsigned int sel; - int ret; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CHG_CURR_WARM, - &sel); - if (ret) { - dev_err(bdpsy->dev, - "Charge current reading failed (%d)\n", ret); - return ret; - } - - sel &= BD70528_MASK_CHG_CHG_CURR; - - ret = linear_range_get_value_array(&warm_charge_curr[0], - ARRAY_SIZE(warm_charge_curr), - sel, ma); - if (ret) { - dev_err(bdpsy->dev, - "Unknown charge current value 0x%x\n", - sel); - } - - return ret; -} - -static int get_current_limit(struct bd70528_psy *bdpsy, int *ma) -{ - unsigned int sel; - int ret; - - ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_DCIN_ILIM, - &sel); - - if (ret) { - dev_err(bdpsy->dev, - "Input current limit reading failed (%d)\n", ret); - return ret; - } - - sel &= BD70528_MASK_CHG_DCIN_ILIM; - - ret = linear_range_get_value_array(¤t_limit_ranges[0], - ARRAY_SIZE(current_limit_ranges), - sel, ma); - if (ret) { - /* Unspecified values mean 500 mA */ - *ma = 500; - } - return 0; -} - -static enum power_supply_property bd70528_charger_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_CHARGE_TYPE, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_MANUFACTURER, -}; - -static int bd70528_charger_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy); - int ret = 0; - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - return bd70528_get_charger_status(bdpsy, &val->intval); - case POWER_SUPPLY_PROP_CHARGE_TYPE: - return bd70528_get_charge_type(bdpsy, &val->intval); - case POWER_SUPPLY_PROP_HEALTH: - return bd70528_get_battery_health(bdpsy, &val->intval); - case POWER_SUPPLY_PROP_PRESENT: - return bd70528_get_present(bdpsy, &val->intval); - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - ret = get_current_limit(bdpsy, &val->intval); - val->intval *= 1000; - return ret; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - ret = get_charge_current(bdpsy, &val->intval); - val->intval *= 1000; - return ret; - case POWER_SUPPLY_PROP_ONLINE: - return bd70528_get_online(bdpsy, &val->intval); - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = bd70528_charger_model; - return 0; - case POWER_SUPPLY_PROP_MANUFACTURER: - val->strval = bd70528_charger_manufacturer; - return 0; - default: - break; - } - - return -EINVAL; -} - -static int bd70528_prop_is_writable(struct power_supply *psy, - enum power_supply_property psp) -{ - switch (psp) { - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - return 1; - default: - break; - } - return 0; -} - -static int set_charge_current(struct bd70528_psy *bdpsy, int ma) -{ - unsigned int reg; - int ret = 0, tmpret; - bool found; - - if (ma > 500) { - dev_warn(bdpsy->dev, - "Requested charge current %u exceed maximum (500mA)\n", - ma); - reg = MAX_WARM_CHG_CURR_SEL; - goto set; - } - if (ma < 10) { - dev_err(bdpsy->dev, - "Requested charge current %u smaller than min (10mA)\n", - ma); - reg = MIN_CHG_CURR_SEL; - ret = -EINVAL; - goto set; - } - -/* - * For BD70528 voltage/current limits we happily accept any value which - * belongs the range. We could check if value matching the selector is - * desired by computing the range min + (sel - sel_low) * range step - but - * I guess it is enough if we use voltage/current which is closest (below) - * the requested? - */ - - ret = linear_range_get_selector_low_array(warm_charge_curr, - ARRAY_SIZE(warm_charge_curr), - ma, ®, &found); - if (ret) { - dev_err(bdpsy->dev, - "Unsupported charge current %u mA\n", ma); - reg = MIN_CHG_CURR_SEL; - goto set; - } - if (!found) { - /* - * There was a gap in supported values and we hit it. - * Yet a smaller value was found so we use it. - */ - dev_warn(bdpsy->dev, - "Unsupported charge current %u mA\n", ma); - } -set: - - tmpret = regmap_update_bits(bdpsy->regmap, - BD70528_REG_CHG_CHG_CURR_WARM, - BD70528_MASK_CHG_CHG_CURR, reg); - if (tmpret) - dev_err(bdpsy->dev, - "Charge current write failure (%d)\n", tmpret); - - if (reg > MAX_COLD_CHG_CURR_SEL) - reg = MAX_COLD_CHG_CURR_SEL; - - if (!tmpret) - tmpret = regmap_update_bits(bdpsy->regmap, - BD70528_REG_CHG_CHG_CURR_COLD, - BD70528_MASK_CHG_CHG_CURR, reg); - - if (!ret) - ret = tmpret; - - return ret; -} - -#define MAX_CURR_LIMIT_SEL 0x34 -#define MIN_CURR_LIMIT_SEL 0x0 - -static int set_current_limit(struct bd70528_psy *bdpsy, int ma) -{ - unsigned int reg; - int ret = 0, tmpret; - bool found; - - if (ma > 500) { - dev_warn(bdpsy->dev, - "Requested current limit %u exceed maximum (500mA)\n", - ma); - reg = MAX_CURR_LIMIT_SEL; - goto set; - } - if (ma < 5) { - dev_err(bdpsy->dev, - "Requested current limit %u smaller than min (5mA)\n", - ma); - reg = MIN_CURR_LIMIT_SEL; - ret = -EINVAL; - goto set; - } - - ret = linear_range_get_selector_low_array(current_limit_ranges, - ARRAY_SIZE(current_limit_ranges), - ma, ®, &found); - if (ret) { - dev_err(bdpsy->dev, "Unsupported current limit %umA\n", ma); - reg = MIN_CURR_LIMIT_SEL; - goto set; - } - if (!found) { - /* - * There was a gap in supported values and we hit it. - * We found a smaller value from ranges and use it. - * Warn user though. - */ - dev_warn(bdpsy->dev, "Unsupported current limit %umA\n", ma); - } - -set: - tmpret = regmap_update_bits(bdpsy->regmap, - BD70528_REG_CHG_DCIN_ILIM, - BD70528_MASK_CHG_DCIN_ILIM, reg); - - if (!ret) - ret = tmpret; - - return ret; -} - -static int bd70528_charger_set_property(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *val) -{ - struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy); - - switch (psp) { - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - return set_current_limit(bdpsy, val->intval / 1000); - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - return set_charge_current(bdpsy, val->intval / 1000); - default: - break; - } - return -EINVAL; -} - -static const struct power_supply_desc bd70528_charger_desc = { - .name = "bd70528-charger", - .type = POWER_SUPPLY_TYPE_MAINS, - .properties = bd70528_charger_props, - .num_properties = ARRAY_SIZE(bd70528_charger_props), - .get_property = bd70528_charger_get_property, - .set_property = bd70528_charger_set_property, - .property_is_writeable = bd70528_prop_is_writable, -}; - -static int bd70528_power_probe(struct platform_device *pdev) -{ - struct bd70528_psy *bdpsy; - struct power_supply_config cfg = {}; - - bdpsy = devm_kzalloc(&pdev->dev, sizeof(*bdpsy), GFP_KERNEL); - if (!bdpsy) - return -ENOMEM; - - bdpsy->regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!bdpsy->regmap) { - dev_err(&pdev->dev, "No regmap found for chip\n"); - return -EINVAL; - } - bdpsy->dev = &pdev->dev; - - platform_set_drvdata(pdev, bdpsy); - cfg.drv_data = bdpsy; - cfg.of_node = pdev->dev.parent->of_node; - - bdpsy->psy = devm_power_supply_register(&pdev->dev, - &bd70528_charger_desc, &cfg); - if (IS_ERR(bdpsy->psy)) { - dev_err(&pdev->dev, "failed: power supply register\n"); - return PTR_ERR(bdpsy->psy); - } - - return bd70528_get_irqs(pdev, bdpsy); -} - -static struct platform_driver bd70528_power = { - .driver = { - .name = "bd70528-power" - }, - .probe = bd70528_power_probe, -}; - -module_platform_driver(bd70528_power); - -MODULE_AUTHOR("Matti Vaittinen "); -MODULE_DESCRIPTION("BD70528 power-supply driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bd70528-power"); diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 852e86bfe2fb..35ff0c8fe96f 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -5,11 +5,10 @@ * Author: Mark A. Greer */ +#include #include #include #include -#include -#include #include #include #include @@ -1959,7 +1958,6 @@ static const struct i2c_device_id bq24190_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); -#ifdef CONFIG_OF static const struct of_device_id bq24190_of_match[] = { { .compatible = "ti,bq24190", }, { .compatible = "ti,bq24192", }, @@ -1968,11 +1966,6 @@ static const struct of_device_id bq24190_of_match[] = { { }, }; MODULE_DEVICE_TABLE(of, bq24190_of_match); -#else -static const struct of_device_id bq24190_of_match[] = { - { }, -}; -#endif static struct i2c_driver bq24190_driver = { .probe = bq24190_probe, @@ -1981,7 +1974,7 @@ static struct i2c_driver bq24190_driver = { .driver = { .name = "bq24190-charger", .pm = &bq24190_pm_ops, - .of_match_table = of_match_ptr(bq24190_of_match), + .of_match_table = bq24190_of_match, }, }; module_i2c_driver(bq24190_driver); diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 45da870aecca..d67edb760c94 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1279,6 +1279,7 @@ static const struct of_device_id charger_manager_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, charger_manager_match); static struct charger_desc *of_cm_parse_desc(struct device *dev) { diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index a3fc0084cda0..8d62d4241da3 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -667,10 +667,23 @@ static int cpcap_battery_get_property(struct power_supply *psy, if (!empty->voltage) return -ENODATA; val->intval = empty->counter_uah - latest->counter_uah; - if (val->intval < 0) + if (val->intval < 0) { + /* Assume invalid config if CHARGE_NOW is -20% */ + if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) { + empty->voltage = 0; + ddata->charge_full = 0; + return -ENODATA; + } val->intval = 0; - else if (ddata->charge_full && ddata->charge_full < val->intval) + } else if (ddata->charge_full && ddata->charge_full < val->intval) { + /* Assume invalid config if CHARGE_NOW exceeds CHARGE_FULL by 20% */ + if (val->intval > (6*ddata->charge_full)/5) { + empty->voltage = 0; + ddata->charge_full = 0; + return -ENODATA; + } val->intval = ddata->charge_full; + } break; case POWER_SUPPLY_PROP_CHARGE_FULL: if (!ddata->charge_full) @@ -747,7 +760,7 @@ static int cpcap_battery_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: if (val->intval < 0) return -EINVAL; - if (val->intval > ddata->config.info.charge_full_design) + if (val->intval > (6*ddata->config.info.charge_full_design)/5) return -EINVAL; ddata->charge_full = val->intval; diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index df01abc49ce8..60e0ce105a29 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -173,23 +173,6 @@ static enum power_supply_property cpcap_charger_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, }; -/* No battery always shows temperature of -40000 */ -static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata) -{ - struct iio_channel *channel; - int error, temperature; - - channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET]; - error = iio_read_channel_processed(channel, &temperature); - if (error < 0) { - dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); - - return false; - } - - return temperature > -20000 && temperature < 60000; -} - static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata) { struct iio_channel *channel; @@ -700,11 +683,29 @@ static void cpcap_usb_detect(struct work_struct *work) if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) && s.chrgcurr1) { - int max_current = 532000; + int max_current; int vchrg, ichrg; + union power_supply_propval val; + struct power_supply *battery; - if (cpcap_charger_battery_found(ddata)) + battery = power_supply_get_by_name("battery"); + if (IS_ERR_OR_NULL(battery)) { + dev_err(ddata->dev, "battery power_supply not available %li\n", + PTR_ERR(battery)); + return; + } + + error = power_supply_get_property(battery, POWER_SUPPLY_PROP_PRESENT, &val); + power_supply_put(battery); + if (error) + goto out_err; + + if (val.intval) { max_current = 1596000; + } else { + dev_info(ddata->dev, "battery not inserted, charging disabled\n"); + max_current = 0; + } if (max_current > ddata->limit_current) max_current = ddata->limit_current; diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 1aab868adabf..3cea92e28dc3 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -142,13 +141,10 @@ struct max17040_chip { struct regmap *regmap; struct delayed_work work; struct power_supply *battery; - struct max17040_platform_data *pdata; struct chip_data data; /* battery capacity */ int soc; - /* State Of Charge */ - int status; /* Low alert threshold from 32% to 1% of the State of Charge */ u32 low_soc_alert; /* some devices return twice the capacity */ @@ -221,26 +217,7 @@ static int max17040_get_version(struct max17040_chip *chip) static int max17040_get_online(struct max17040_chip *chip) { - return chip->pdata && chip->pdata->battery_online ? - chip->pdata->battery_online() : 1; -} - -static int max17040_get_status(struct max17040_chip *chip) -{ - if (!chip->pdata || !chip->pdata->charger_online - || !chip->pdata->charger_enable) - return POWER_SUPPLY_STATUS_UNKNOWN; - - if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL) - return POWER_SUPPLY_STATUS_FULL; - - if (chip->pdata->charger_online()) - if (chip->pdata->charger_enable()) - return POWER_SUPPLY_STATUS_CHARGING; - else - return POWER_SUPPLY_STATUS_NOT_CHARGING; - else - return POWER_SUPPLY_STATUS_DISCHARGING; + return 1; } static int max17040_get_of_data(struct max17040_chip *chip) @@ -283,7 +260,6 @@ static int max17040_get_of_data(struct max17040_chip *chip) static void max17040_check_changes(struct max17040_chip *chip) { chip->soc = max17040_get_soc(chip); - chip->status = max17040_get_status(chip); } static void max17040_queue_work(struct max17040_chip *chip) @@ -302,17 +278,16 @@ static void max17040_stop_work(void *data) static void max17040_work(struct work_struct *work) { struct max17040_chip *chip; - int last_soc, last_status; + int last_soc; chip = container_of(work, struct max17040_chip, work.work); - /* store SOC and status to check changes */ + /* store SOC to check changes */ last_soc = chip->soc; - last_status = chip->status; max17040_check_changes(chip); /* check changes and send uevent */ - if (last_soc != chip->soc || last_status != chip->status) + if (last_soc != chip->soc) power_supply_changed(chip->battery); max17040_queue_work(chip); @@ -361,12 +336,10 @@ static irqreturn_t max17040_thread_handler(int id, void *dev) static int max17040_enable_alert_irq(struct max17040_chip *chip) { struct i2c_client *client = chip->client; - unsigned int flags; int ret; - flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - max17040_thread_handler, flags, + max17040_thread_handler, IRQF_ONESHOT, chip->battery->desc->name, chip); return ret; @@ -415,9 +388,6 @@ static int max17040_get_property(struct power_supply *psy, struct max17040_chip *chip = power_supply_get_drvdata(psy); switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = max17040_get_status(chip); - break; case POWER_SUPPLY_PROP_ONLINE: val->intval = max17040_get_online(chip); break; @@ -444,7 +414,6 @@ static const struct regmap_config max17040_regmap = { }; static enum power_supply_property max17040_battery_props[] = { - POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CAPACITY, @@ -480,7 +449,6 @@ static int max17040_probe(struct i2c_client *client, chip->client = client; chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap); - chip->pdata = client->dev.platform_data; chip_id = (enum chip_id) id->driver_data; if (client->dev.of_node) { ret = max17040_get_of_data(chip); diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 1d7326cd8fc6..ce2041b30a06 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -1104,7 +1104,7 @@ static int max17042_probe(struct i2c_client *client, } if (client->irq) { - unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + unsigned int flags = IRQF_ONESHOT; /* * On ACPI systems the IRQ may be handled by ACPI-event code, diff --git a/drivers/power/supply/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c deleted file mode 100644 index f86bbbeaff6c..000000000000 --- a/drivers/power/supply/pm2301_charger.c +++ /dev/null @@ -1,1249 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2012 ST Ericsson. - * - * Power supply driver for ST Ericsson pm2xxx_charger charger - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ab8500-bm.h" -#include "ab8500-chargalg.h" -#include "pm2301_charger.h" - -#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \ - struct pm2xxx_charger, ac_chg) -#define SLEEP_MIN 50 -#define SLEEP_MAX 100 -#define PM2XXX_AUTOSUSPEND_DELAY 500 - -static int pm2xxx_interrupt_registers[] = { - PM2XXX_REG_INT1, - PM2XXX_REG_INT2, - PM2XXX_REG_INT3, - PM2XXX_REG_INT4, - PM2XXX_REG_INT5, - PM2XXX_REG_INT6, -}; - -static enum power_supply_property pm2xxx_charger_ac_props[] = { - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_VOLTAGE_AVG, -}; - -static int pm2xxx_charger_voltage_map[] = { - 3500, - 3525, - 3550, - 3575, - 3600, - 3625, - 3650, - 3675, - 3700, - 3725, - 3750, - 3775, - 3800, - 3825, - 3850, - 3875, - 3900, - 3925, - 3950, - 3975, - 4000, - 4025, - 4050, - 4075, - 4100, - 4125, - 4150, - 4175, - 4200, - 4225, - 4250, - 4275, - 4300, -}; - -static int pm2xxx_charger_current_map[] = { - 200, - 200, - 400, - 600, - 800, - 1000, - 1200, - 1400, - 1600, - 1800, - 2000, - 2200, - 2400, - 2600, - 2800, - 3000, -}; - -static void set_lpn_pin(struct pm2xxx_charger *pm2) -{ - if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) { - gpio_set_value(pm2->lpn_pin, 1); - usleep_range(SLEEP_MIN, SLEEP_MAX); - } -} - -static void clear_lpn_pin(struct pm2xxx_charger *pm2) -{ - if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) - gpio_set_value(pm2->lpn_pin, 0); -} - -static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val) -{ - int ret; - - /* wake up the device */ - pm_runtime_get_sync(pm2->dev); - - ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg, - 1, val); - if (ret < 0) - dev_err(pm2->dev, "Error reading register at 0x%x\n", reg); - else - ret = 0; - - pm_runtime_put_sync(pm2->dev); - - return ret; -} - -static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val) -{ - int ret; - - /* wake up the device */ - pm_runtime_get_sync(pm2->dev); - - ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg, - 1, &val); - if (ret < 0) - dev_err(pm2->dev, "Error writing register at 0x%x\n", reg); - else - ret = 0; - - pm_runtime_put_sync(pm2->dev); - - return ret; -} - -static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2) -{ - int ret; - - /* Enable charging */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2, - (PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA)); - - return ret; -} - -static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2) -{ - int ret; - - /* Disable SW EOC ctrl */ - ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, PM2XXX_SWCTRL_HW); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - return ret; - } - - /* Disable charging */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2, - (PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS)); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - return ret; - } - - return 0; -} - -static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val) -{ - queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work); - - return 0; -} - - -static int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val) -{ - queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work); - - return 0; -} - -static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val) -{ - dev_err(pm2->dev, "Overvoltage detected\n"); - pm2->flags.ovv = true; - power_supply_changed(pm2->ac_chg.psy); - - /* Schedule a new HW failure check */ - queue_delayed_work(pm2->charger_wq, &pm2->check_hw_failure_work, 0); - - return 0; -} - -static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val) -{ - dev_dbg(pm2->dev , "20 minutes watchdog expired\n"); - - pm2->ac.wd_expired = true; - power_supply_changed(pm2->ac_chg.psy); - - return 0; -} - -static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val) -{ - int ret; - - switch (val) { - case PM2XXX_INT1_ITVBATLOWR: - dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n"); - /* Enable SW EOC ctrl */ - ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, - PM2XXX_SWCTRL_SW); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - return ret; - } - break; - - case PM2XXX_INT1_ITVBATLOWF: - dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n"); - /* Disable SW EOC ctrl */ - ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, - PM2XXX_SWCTRL_HW); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - return ret; - } - break; - - default: - dev_err(pm2->dev, "Unknown VBAT level\n"); - } - - return 0; -} - -static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val) -{ - dev_dbg(pm2->dev, "battery disconnected\n"); - - return 0; -} - -static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val) -{ - int ret; - - ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val); - - if (ret < 0) { - dev_err(pm2->dev, "Charger detection failed\n"); - goto out; - } - - *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG); - -out: - return ret; -} - -static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val) -{ - - int ret; - u8 read_val; - - /* - * Since we can't be sure that the events are received - * synchronously, we have the check if the main charger is - * connected by reading the interrupt source register. - */ - ret = pm2xxx_charger_detection(pm2, &read_val); - - if ((ret == 0) && read_val) { - pm2->ac.charger_connected = 1; - pm2->ac_conn = true; - queue_work(pm2->charger_wq, &pm2->ac_work); - } - - - return ret; -} - -static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2, - int val) -{ - pm2->ac.charger_connected = 0; - queue_work(pm2->charger_wq, &pm2->ac_work); - - return 0; -} - -static int pm2_int_reg0(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - int ret = 0; - - if (val & PM2XXX_INT1_ITVBATLOWR) { - ret = pm2xxx_charger_vbat_lsig_mngt(pm2, - PM2XXX_INT1_ITVBATLOWR); - if (ret < 0) - goto out; - } - - if (val & PM2XXX_INT1_ITVBATLOWF) { - ret = pm2xxx_charger_vbat_lsig_mngt(pm2, - PM2XXX_INT1_ITVBATLOWF); - if (ret < 0) - goto out; - } - - if (val & PM2XXX_INT1_ITVBATDISCONNECT) { - ret = pm2xxx_charger_bat_disc_mngt(pm2, - PM2XXX_INT1_ITVBATDISCONNECT); - if (ret < 0) - goto out; - } -out: - return ret; -} - -static int pm2_int_reg1(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - int ret = 0; - - if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) { - dev_dbg(pm2->dev , "Main charger plugged\n"); - ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val & - (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)); - } - - if (val & - (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) { - dev_dbg(pm2->dev , "Main charger unplugged\n"); - ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val & - (PM2XXX_INT2_ITVPWR1UNPLUG | - PM2XXX_INT2_ITVPWR2UNPLUG)); - } - - return ret; -} - -static int pm2_int_reg2(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - int ret = 0; - - if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD) - ret = pm2xxx_charger_wd_exp_mngt(pm2, val); - - if (val & (PM2XXX_INT3_ITCHPRECHARGEWD | - PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) { - dev_dbg(pm2->dev, - "Watchdog occurred for precharge, CC and CV charge\n"); - } - - return ret; -} - -static int pm2_int_reg3(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - int ret = 0; - - if (val & (PM2XXX_INT4_ITCHARGINGON)) { - dev_dbg(pm2->dev , - "charging operation has started\n"); - } - - if (val & (PM2XXX_INT4_ITVRESUME)) { - dev_dbg(pm2->dev, - "battery discharged down to VResume threshold\n"); - } - - if (val & (PM2XXX_INT4_ITBATTFULL)) { - dev_dbg(pm2->dev , "battery fully detected\n"); - } - - if (val & (PM2XXX_INT4_ITCVPHASE)) { - dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n"); - } - - if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) { - pm2->failure_case = VPWR_OVV; - ret = pm2xxx_charger_ovv_mngt(pm2, val & - (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)); - dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n"); - } - - if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD | - PM2XXX_INT4_S_ITBATTEMPHOT)) { - ret = pm2xxx_charger_batt_therm_mngt(pm2, val & - (PM2XXX_INT4_S_ITBATTEMPCOLD | - PM2XXX_INT4_S_ITBATTEMPHOT)); - dev_dbg(pm2->dev, "BTEMP is too Low/High\n"); - } - - return ret; -} - -static int pm2_int_reg4(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - int ret = 0; - - if (val & PM2XXX_INT5_ITVSYSTEMOVV) { - pm2->failure_case = VSYSTEM_OVV; - ret = pm2xxx_charger_ovv_mngt(pm2, val & - PM2XXX_INT5_ITVSYSTEMOVV); - dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n"); - } - - if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL | - PM2XXX_INT5_ITTHERMALWARNINGRISE | - PM2XXX_INT5_ITTHERMALSHUTDOWNFALL | - PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) { - dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n"); - ret = pm2xxx_charger_die_therm_mngt(pm2, val & - (PM2XXX_INT5_ITTHERMALWARNINGFALL | - PM2XXX_INT5_ITTHERMALWARNINGRISE | - PM2XXX_INT5_ITTHERMALSHUTDOWNFALL | - PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)); - } - - return ret; -} - -static int pm2_int_reg5(void *pm2_data, int val) -{ - struct pm2xxx_charger *pm2 = pm2_data; - - if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) { - dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n"); - } - - if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE | - PM2XXX_INT6_ITVPWR1VALIDRISE | - PM2XXX_INT6_ITVPWR2VALIDFALL | - PM2XXX_INT6_ITVPWR1VALIDFALL)) { - dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n"); - } - - return 0; -} - -static irqreturn_t pm2xxx_irq_int(int irq, void *data) -{ - struct pm2xxx_charger *pm2 = data; - struct pm2xxx_interrupts *interrupt = pm2->pm2_int; - int i; - - /* wake up the device */ - pm_runtime_get_sync(pm2->dev); - - do { - for (i = 0; i < PM2XXX_NUM_INT_REG; i++) { - pm2xxx_reg_read(pm2, - pm2xxx_interrupt_registers[i], - &(interrupt->reg[i])); - - if (interrupt->reg[i] > 0) - interrupt->handler[i](pm2, interrupt->reg[i]); - } - } while (gpio_get_value(pm2->pdata->gpio_irq_number) == 0); - - pm_runtime_mark_last_busy(pm2->dev); - pm_runtime_put_autosuspend(pm2->dev); - - return IRQ_HANDLED; -} - -static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2) -{ - int ret = 0; - u8 val; - - if (pm2->ac.charger_connected && pm2->ac.charger_online) { - - ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__); - goto out; - } - - if (val & PM2XXX_INT4_S_ITCVPHASE) - ret = PM2XXX_CONST_VOLT; - else - ret = PM2XXX_CONST_CURR; - } -out: - return ret; -} - -static int pm2xxx_current_to_regval(int curr) -{ - int i; - - if (curr < pm2xxx_charger_current_map[0]) - return 0; - - for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) { - if (curr < pm2xxx_charger_current_map[i]) - return (i - 1); - } - - i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1; - if (curr == pm2xxx_charger_current_map[i]) - return i; - else - return -EINVAL; -} - -static int pm2xxx_voltage_to_regval(int curr) -{ - int i; - - if (curr < pm2xxx_charger_voltage_map[0]) - return 0; - - for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) { - if (curr < pm2xxx_charger_voltage_map[i]) - return i - 1; - } - - i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1; - if (curr == pm2xxx_charger_voltage_map[i]) - return i; - else - return -EINVAL; -} - -static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger, - int ich_out) -{ - int ret; - int curr_index; - struct pm2xxx_charger *pm2; - u8 val; - - if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) - pm2 = to_pm2xxx_charger_ac_device_info(charger); - else - return -ENXIO; - - curr_index = pm2xxx_current_to_regval(ich_out); - if (curr_index < 0) { - dev_err(pm2->dev, - "Charger current too high, charging not started\n"); - return -ENXIO; - } - - ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val); - if (ret >= 0) { - val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK; - val |= curr_index; - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val); - if (ret < 0) { - dev_err(pm2->dev, - "%s write failed\n", __func__); - } - } - else - dev_err(pm2->dev, "%s read failed\n", __func__); - - return ret; -} - -static int pm2xxx_charger_ac_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct pm2xxx_charger *pm2; - - pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy)); - - switch (psp) { - case POWER_SUPPLY_PROP_HEALTH: - if (pm2->flags.mainextchnotok) - val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; - else if (pm2->ac.wd_expired) - val->intval = POWER_SUPPLY_HEALTH_DEAD; - else if (pm2->flags.main_thermal_prot) - val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; - else if (pm2->flags.ovv) - val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - else - val->intval = POWER_SUPPLY_HEALTH_GOOD; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = pm2->ac.charger_online; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = pm2->ac.charger_connected; - break; - case POWER_SUPPLY_PROP_VOLTAGE_AVG: - pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2); - val->intval = pm2->ac.cv_active; - break; - default: - return -EINVAL; - } - return 0; -} - -static int pm2xxx_charging_init(struct pm2xxx_charger *pm2) -{ - int ret = 0; - - /* enable CC and CV watchdog */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3, - (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN)); - if( ret < 0) - return ret; - - /* enable precharge watchdog */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4, - PM2XXX_CH_WD_PRECH_PHASE_60MIN); - - /* Disable auto timeout */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5, - PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN); - - /* - * EOC current level = 100mA - * Precharge current level = 100mA - * CC current level = 1000mA - */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, - (PM2XXX_DIR_CH_CC_CURRENT_1000MA | - PM2XXX_CH_PRECH_CURRENT_100MA | - PM2XXX_CH_EOC_CURRENT_100MA)); - - /* - * recharge threshold = 3.8V - * Precharge to CC threshold = 2.9V - */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7, - (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8)); - - /* float voltage charger level = 4.2V */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, - PM2XXX_CH_VOLT_4_2); - - /* Voltage drop between VBAT and VSYS in HW charging = 300mV */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9, - (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS | - PM2XXX_CH_CC_REDUCED_CURRENT_IDENT | - PM2XXX_CH_CC_MODEDROP_DIS)); - - /* Input charger level of over voltage = 10V */ - ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2, - PM2XXX_VPWR2_OVV_10); - ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1, - PM2XXX_VPWR1_OVV_10); - - /* Input charger drop */ - ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2, - (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS | - PM2XXX_VPWR2_DROP_DIS)); - ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1, - (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS | - PM2XXX_VPWR1_DROP_DIS)); - - /* Disable battery low monitoring */ - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG, - PM2XXX_VBAT_LOW_MONITORING_ENA); - - return ret; -} - -static int pm2xxx_charger_ac_en(struct ux500_charger *charger, - int enable, int vset, int iset) -{ - int ret; - int volt_index; - int curr_index; - u8 val; - - struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger); - - if (enable) { - if (!pm2->ac.charger_connected) { - dev_dbg(pm2->dev, "AC charger not connected\n"); - return -ENXIO; - } - - dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset); - if (!pm2->vddadc_en_ac) { - ret = regulator_enable(pm2->regu); - if (ret) - dev_warn(pm2->dev, - "Failed to enable vddadc regulator\n"); - else - pm2->vddadc_en_ac = true; - } - - ret = pm2xxx_charging_init(pm2); - if (ret < 0) { - dev_err(pm2->dev, "%s charging init failed\n", - __func__); - goto error_occured; - } - - volt_index = pm2xxx_voltage_to_regval(vset); - curr_index = pm2xxx_current_to_regval(iset); - - if (volt_index < 0 || curr_index < 0) { - dev_err(pm2->dev, - "Charger voltage or current too high, " - "charging not started\n"); - return -ENXIO; - } - - ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__); - goto error_occured; - } - val &= ~PM2XXX_CH_VOLT_MASK; - val |= volt_index; - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - goto error_occured; - } - - ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__); - goto error_occured; - } - val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK; - val |= curr_index; - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__); - goto error_occured; - } - - if (!pm2->bat->enable_overshoot) { - ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx read failed\n", - __func__); - goto error_occured; - } - val |= PM2XXX_ANTI_OVERSHOOT_EN; - ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx write failed\n", - __func__); - goto error_occured; - } - } - - ret = pm2xxx_charging_enable_mngt(pm2); - if (ret < 0) { - dev_err(pm2->dev, "Failed to enable" - "pm2xxx ac charger\n"); - goto error_occured; - } - - pm2->ac.charger_online = 1; - } else { - pm2->ac.charger_online = 0; - pm2->ac.wd_expired = false; - - /* Disable regulator if enabled */ - if (pm2->vddadc_en_ac) { - regulator_disable(pm2->regu); - pm2->vddadc_en_ac = false; - } - - ret = pm2xxx_charging_disable_mngt(pm2); - if (ret < 0) { - dev_err(pm2->dev, "failed to disable" - "pm2xxx ac charger\n"); - goto error_occured; - } - - dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n"); - } - power_supply_changed(pm2->ac_chg.psy); - -error_occured: - return ret; -} - -static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger) -{ - int ret; - struct pm2xxx_charger *pm2; - - if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) - pm2 = to_pm2xxx_charger_ac_device_info(charger); - else - return -ENXIO; - - ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER); - if (ret) - dev_err(pm2->dev, "Failed to kick WD!\n"); - - return ret; -} - -static void pm2xxx_charger_ac_work(struct work_struct *work) -{ - struct pm2xxx_charger *pm2 = container_of(work, - struct pm2xxx_charger, ac_work); - - - power_supply_changed(pm2->ac_chg.psy); - sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present"); -}; - -static void pm2xxx_charger_check_hw_failure_work(struct work_struct *work) -{ - u8 reg_value; - - struct pm2xxx_charger *pm2 = container_of(work, - struct pm2xxx_charger, check_hw_failure_work.work); - - if (pm2->flags.ovv) { - pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, ®_value); - - if (!(reg_value & (PM2XXX_INT4_S_ITVPWR1OVV | - PM2XXX_INT4_S_ITVPWR2OVV))) { - pm2->flags.ovv = false; - power_supply_changed(pm2->ac_chg.psy); - } - } - - /* If we still have a failure, schedule a new check */ - if (pm2->flags.ovv) { - queue_delayed_work(pm2->charger_wq, - &pm2->check_hw_failure_work, round_jiffies(HZ)); - } -} - -static void pm2xxx_charger_check_main_thermal_prot_work( - struct work_struct *work) -{ - int ret; - u8 val; - - struct pm2xxx_charger *pm2 = container_of(work, struct pm2xxx_charger, - check_main_thermal_prot_work); - - /* Check if die temp warning is still active */ - ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT5, &val); - if (ret < 0) { - dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__); - return; - } - if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGRISE - | PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE)) - pm2->flags.main_thermal_prot = true; - else if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGFALL - | PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL)) - pm2->flags.main_thermal_prot = false; - - power_supply_changed(pm2->ac_chg.psy); -} - -static struct pm2xxx_interrupts pm2xxx_int = { - .handler[0] = pm2_int_reg0, - .handler[1] = pm2_int_reg1, - .handler[2] = pm2_int_reg2, - .handler[3] = pm2_int_reg3, - .handler[4] = pm2_int_reg4, - .handler[5] = pm2_int_reg5, -}; - -static struct pm2xxx_irq pm2xxx_charger_irq[] = { - {"PM2XXX_IRQ_INT", pm2xxx_irq_int}, -}; - -static int __maybe_unused pm2xxx_wall_charger_resume(struct device *dev) -{ - struct i2c_client *i2c_client = to_i2c_client(dev); - struct pm2xxx_charger *pm2; - - pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client); - set_lpn_pin(pm2); - - /* If we still have a HW failure, schedule a new check */ - if (pm2->flags.ovv) - queue_delayed_work(pm2->charger_wq, - &pm2->check_hw_failure_work, 0); - - return 0; -} - -static int __maybe_unused pm2xxx_wall_charger_suspend(struct device *dev) -{ - struct i2c_client *i2c_client = to_i2c_client(dev); - struct pm2xxx_charger *pm2; - - pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client); - clear_lpn_pin(pm2); - - /* Cancel any pending HW failure check */ - if (delayed_work_pending(&pm2->check_hw_failure_work)) - cancel_delayed_work(&pm2->check_hw_failure_work); - - flush_work(&pm2->ac_work); - flush_work(&pm2->check_main_thermal_prot_work); - - return 0; -} - -static int __maybe_unused pm2xxx_runtime_suspend(struct device *dev) -{ - struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev); - struct pm2xxx_charger *pm2; - - pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client); - clear_lpn_pin(pm2); - - return 0; -} - -static int __maybe_unused pm2xxx_runtime_resume(struct device *dev) -{ - struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev); - struct pm2xxx_charger *pm2; - - pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client); - - if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0) - set_lpn_pin(pm2); - - return 0; -} - -static const struct dev_pm_ops pm2xxx_pm_ops __maybe_unused = { - SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend, - pm2xxx_wall_charger_resume) - SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL) -}; - -static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) -{ - struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data; - struct power_supply_config psy_cfg = {}; - struct pm2xxx_charger *pm2; - int ret = 0; - u8 val; - int i; - - if (!pl_data) { - dev_err(&i2c_client->dev, "No platform data supplied\n"); - return -EINVAL; - } - - pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL); - if (!pm2) { - dev_err(&i2c_client->dev, "pm2xxx_charger allocation failed\n"); - return -ENOMEM; - } - - /* get parent data */ - pm2->dev = &i2c_client->dev; - - pm2->pm2_int = &pm2xxx_int; - - /* get charger spcific platform data */ - if (!pl_data->wall_charger) { - dev_err(pm2->dev, "no charger platform data supplied\n"); - ret = -EINVAL; - goto free_device_info; - } - - pm2->pdata = pl_data->wall_charger; - - /* get battery specific platform data */ - if (!pl_data->battery) { - dev_err(pm2->dev, "no battery platform data supplied\n"); - ret = -EINVAL; - goto free_device_info; - } - - pm2->bat = pl_data->battery; - - if (!i2c_check_functionality(i2c_client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_READ_WORD_DATA)) { - ret = -ENODEV; - dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n"); - goto free_device_info; - } - - pm2->config.pm2xxx_i2c = i2c_client; - pm2->config.pm2xxx_id = (struct i2c_device_id *) id; - i2c_set_clientdata(i2c_client, pm2); - - /* AC supply */ - /* power_supply base class */ - pm2->ac_chg_desc.name = pm2->pdata->label; - pm2->ac_chg_desc.type = POWER_SUPPLY_TYPE_MAINS; - pm2->ac_chg_desc.properties = pm2xxx_charger_ac_props; - pm2->ac_chg_desc.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props); - pm2->ac_chg_desc.get_property = pm2xxx_charger_ac_get_property; - - psy_cfg.supplied_to = pm2->pdata->supplied_to; - psy_cfg.num_supplicants = pm2->pdata->num_supplicants; - /* pm2xxx_charger sub-class */ - pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en; - pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick; - pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current; - pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[ - ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1]; - pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[ - ARRAY_SIZE(pm2xxx_charger_current_map) - 1]; - pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL; - pm2->ac_chg.enabled = true; - pm2->ac_chg.external = true; - - /* Create a work queue for the charger */ - pm2->charger_wq = alloc_ordered_workqueue("pm2xxx_charger_wq", - WQ_MEM_RECLAIM); - if (pm2->charger_wq == NULL) { - ret = -ENOMEM; - dev_err(pm2->dev, "failed to create work queue\n"); - goto free_device_info; - } - - /* Init work for charger detection */ - INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work); - - /* Init work for checking HW status */ - INIT_WORK(&pm2->check_main_thermal_prot_work, - pm2xxx_charger_check_main_thermal_prot_work); - - /* Init work for HW failure check */ - INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work, - pm2xxx_charger_check_hw_failure_work); - - /* - * VDD ADC supply needs to be enabled from this driver when there - * is a charger connected to avoid erroneous BTEMP_HIGH/LOW - * interrupts during charging - */ - pm2->regu = regulator_get(pm2->dev, "vddadc"); - if (IS_ERR(pm2->regu)) { - ret = PTR_ERR(pm2->regu); - dev_err(pm2->dev, "failed to get vddadc regulator\n"); - goto free_charger_wq; - } - - /* Register AC charger class */ - pm2->ac_chg.psy = power_supply_register(pm2->dev, &pm2->ac_chg_desc, - &psy_cfg); - if (IS_ERR(pm2->ac_chg.psy)) { - dev_err(pm2->dev, "failed to register AC charger\n"); - ret = PTR_ERR(pm2->ac_chg.psy); - goto free_regulator; - } - - /* Register interrupts */ - ret = request_threaded_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), - NULL, - pm2xxx_charger_irq[0].isr, - pm2->pdata->irq_type | IRQF_ONESHOT, - pm2xxx_charger_irq[0].name, pm2); - - if (ret != 0) { - dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n", - pm2xxx_charger_irq[0].name, - gpio_to_irq(pm2->pdata->gpio_irq_number), ret); - goto unregister_pm2xxx_charger; - } - - ret = pm_runtime_set_active(pm2->dev); - if (ret) - dev_err(pm2->dev, "set active Error\n"); - - pm_runtime_enable(pm2->dev); - pm_runtime_set_autosuspend_delay(pm2->dev, PM2XXX_AUTOSUSPEND_DELAY); - pm_runtime_use_autosuspend(pm2->dev); - pm_runtime_resume(pm2->dev); - - /* pm interrupt can wake up system */ - ret = enable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number)); - if (ret) { - dev_err(pm2->dev, "failed to set irq wake\n"); - goto unregister_pm2xxx_interrupt; - } - - mutex_init(&pm2->lock); - - if (gpio_is_valid(pm2->pdata->lpn_gpio)) { - /* get lpn GPIO from platform data */ - pm2->lpn_pin = pm2->pdata->lpn_gpio; - - /* - * Charger detection mechanism requires pulling up the LPN pin - * while i2c communication if Charger is not connected - * LPN pin of PM2301 is GPIO60 of AB9540 - */ - ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio"); - - if (ret < 0) { - dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n"); - goto disable_pm2_irq_wake; - } - ret = gpio_direction_output(pm2->lpn_pin, 0); - if (ret < 0) { - dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n"); - goto free_gpio; - } - set_lpn_pin(pm2); - } - - /* read interrupt registers */ - for (i = 0; i < PM2XXX_NUM_INT_REG; i++) - pm2xxx_reg_read(pm2, - pm2xxx_interrupt_registers[i], - &val); - - ret = pm2xxx_charger_detection(pm2, &val); - - if ((ret == 0) && val) { - pm2->ac.charger_connected = 1; - ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON, - AB8500_MAIN_CH_DET); - pm2->ac_conn = true; - power_supply_changed(pm2->ac_chg.psy); - sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present"); - } - - return 0; - -free_gpio: - if (gpio_is_valid(pm2->lpn_pin)) - gpio_free(pm2->lpn_pin); -disable_pm2_irq_wake: - disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number)); -unregister_pm2xxx_interrupt: - /* disable interrupt */ - free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2); -unregister_pm2xxx_charger: - /* unregister power supply */ - power_supply_unregister(pm2->ac_chg.psy); -free_regulator: - /* disable the regulator */ - regulator_put(pm2->regu); -free_charger_wq: - destroy_workqueue(pm2->charger_wq); -free_device_info: - kfree(pm2); - - return ret; -} - -static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client) -{ - struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client); - - /* Disable pm_runtime */ - pm_runtime_disable(pm2->dev); - /* Disable AC charging */ - pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0); - - /* Disable wake by pm interrupt */ - disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number)); - - /* Disable interrupts */ - free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2); - - /* Delete the work queue */ - destroy_workqueue(pm2->charger_wq); - - flush_scheduled_work(); - - /* disable the regulator */ - regulator_put(pm2->regu); - - power_supply_unregister(pm2->ac_chg.psy); - - if (gpio_is_valid(pm2->lpn_pin)) - gpio_free(pm2->lpn_pin); - - kfree(pm2); - - return 0; -} - -static const struct i2c_device_id pm2xxx_id[] = { - { "pm2301", 0 }, - { } -}; - -MODULE_DEVICE_TABLE(i2c, pm2xxx_id); - -static struct i2c_driver pm2xxx_charger_driver = { - .probe = pm2xxx_wall_charger_probe, - .remove = pm2xxx_wall_charger_remove, - .driver = { - .name = "pm2xxx-wall_charger", - .pm = IS_ENABLED(CONFIG_PM) ? &pm2xxx_pm_ops : NULL, - }, - .id_table = pm2xxx_id, -}; - -static int __init pm2xxx_charger_init(void) -{ - return i2c_add_driver(&pm2xxx_charger_driver); -} - -static void __exit pm2xxx_charger_exit(void) -{ - i2c_del_driver(&pm2xxx_charger_driver); -} - -device_initcall_sync(pm2xxx_charger_init); -module_exit(pm2xxx_charger_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay"); -MODULE_DESCRIPTION("PM2xxx charger management driver"); diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c index dee520f0fdf5..819061918b2a 100644 --- a/drivers/power/supply/rn5t618_power.c +++ b/drivers/power/supply/rn5t618_power.c @@ -37,8 +37,27 @@ #define CHG_STATE_NO_BAT2 13 #define CHG_STATE_CHG_READY_VUSB 14 +#define GCHGDET_TYPE_MASK 0x30 +#define GCHGDET_TYPE_SDP 0x00 +#define GCHGDET_TYPE_CDP 0x10 +#define GCHGDET_TYPE_DCP 0x20 + #define FG_ENABLE 1 +/* + * Formula seems accurate for battery current, but for USB current around 70mA + * per step was seen on Kobo Clara HD but all sources show the same formula + * also fur USB current. To avoid accidentially unwanted high currents we stick + * to that formula + */ +#define TO_CUR_REG(x) ((x) / 100000 - 1) +#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000) +#define CHG_MIN_CUR 100000 +#define CHG_MAX_CUR 1800000 +#define ADP_MAX_CUR 2500000 +#define USB_MAX_CUR 1400000 + + struct rn5t618_power_info { struct rn5t618 *rn5t618; struct platform_device *pdev; @@ -48,12 +67,24 @@ struct rn5t618_power_info { int irq; }; +static enum power_supply_usb_type rn5t618_usb_types[] = { + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_DCP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_UNKNOWN +}; + static enum power_supply_property rn5t618_usb_props[] = { + /* input current limit is not very accurate */ + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, }; static enum power_supply_property rn5t618_adp_props[] = { + /* input current limit is not very accurate */ + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, }; @@ -69,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = { POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, }; @@ -258,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info, return 0; } +static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info, + const union power_supply_propval *val) +{ + if (val->intval < CHG_MIN_CUR) + return -EINVAL; + + if (val->intval >= CHG_MAX_CUR) + return -EINVAL; + + return regmap_update_bits(info->rn5t618->regmap, + RN5T618_CHGISET, + 0x1F, TO_CUR_REG(val->intval)); +} + +static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET, + ®val); + if (ret < 0) + return ret; + + val->intval = FROM_CUR_REG(regval); + + return 0; +} + static int rn5t618_battery_charge_full(struct rn5t618_power_info *info, union power_supply_propval *val) { @@ -323,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + ret = rn5t618_battery_get_current_limit(info, val); + break; case POWER_SUPPLY_PROP_CHARGE_FULL: ret = rn5t618_battery_charge_full(info, val); break; @@ -336,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy, return ret; } +static int rn5t618_battery_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct rn5t618_power_info *info = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + return rn5t618_battery_set_current_limit(info, val); + default: + return -EINVAL; + } +} + +static int rn5t618_battery_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + return true; + default: + return false; + } +} + static int rn5t618_adp_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct rn5t618_power_info *info = power_supply_get_drvdata(psy); unsigned int chgstate; + unsigned int regval; bool online; int ret; @@ -364,6 +455,14 @@ static int rn5t618_adp_get_property(struct power_supply *psy, if (val->intval != POWER_SUPPLY_STATUS_CHARGING) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = regmap_read(info->rn5t618->regmap, + RN5T618_REGISET1, ®val); + if (ret < 0) + return ret; + + val->intval = FROM_CUR_REG(regval); break; default: return -EINVAL; @@ -372,12 +471,79 @@ static int rn5t618_adp_get_property(struct power_supply *psy, return 0; } +static int rn5t618_adp_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct rn5t618_power_info *info = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + if (val->intval > ADP_MAX_CUR) + return -EINVAL; + + if (val->intval < CHG_MIN_CUR) + return -EINVAL; + + ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1, + TO_CUR_REG(val->intval)); + if (ret < 0) + return ret; + + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rn5t618_adp_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + +static int rc5t619_usb_get_type(struct rn5t618_power_info *info, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, ®val); + if (ret < 0) + return ret; + + switch (regval & GCHGDET_TYPE_MASK) { + case GCHGDET_TYPE_SDP: + val->intval = POWER_SUPPLY_USB_TYPE_SDP; + break; + case GCHGDET_TYPE_CDP: + val->intval = POWER_SUPPLY_USB_TYPE_CDP; + break; + case GCHGDET_TYPE_DCP: + val->intval = POWER_SUPPLY_USB_TYPE_DCP; + break; + default: + val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN; + } + + return 0; +} + static int rn5t618_usb_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct rn5t618_power_info *info = power_supply_get_drvdata(psy); unsigned int chgstate; + unsigned int regval; bool online; int ret; @@ -400,6 +566,28 @@ static int rn5t618_usb_get_property(struct power_supply *psy, if (val->intval != POWER_SUPPLY_STATUS_CHARGING) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case POWER_SUPPLY_PROP_USB_TYPE: + if (!online || (info->rn5t618->variant != RC5T619)) + return -ENODATA; + + return rc5t619_usb_get_type(info, val); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1, + ®val); + if (ret < 0) + return ret; + + val->intval = 0; + if (regval & 2) { + ret = regmap_read(info->rn5t618->regmap, + RN5T618_REGISET2, + ®val); + if (ret < 0) + return ret; + + val->intval = FROM_CUR_REG(regval); + } break; default: return -EINVAL; @@ -408,12 +596,53 @@ static int rn5t618_usb_get_property(struct power_supply *psy, return 0; } +static int rn5t618_usb_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct rn5t618_power_info *info = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + if (val->intval > USB_MAX_CUR) + return -EINVAL; + + if (val->intval < CHG_MIN_CUR) + return -EINVAL; + + ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2, + 0xE0 | TO_CUR_REG(val->intval)); + if (ret < 0) + return ret; + + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rn5t618_usb_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + static const struct power_supply_desc rn5t618_battery_desc = { .name = "rn5t618-battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = rn5t618_battery_props, .num_properties = ARRAY_SIZE(rn5t618_battery_props), .get_property = rn5t618_battery_get_property, + .set_property = rn5t618_battery_set_property, + .property_is_writeable = rn5t618_battery_property_is_writeable, }; static const struct power_supply_desc rn5t618_adp_desc = { @@ -422,14 +651,20 @@ static const struct power_supply_desc rn5t618_adp_desc = { .properties = rn5t618_adp_props, .num_properties = ARRAY_SIZE(rn5t618_adp_props), .get_property = rn5t618_adp_get_property, + .set_property = rn5t618_adp_set_property, + .property_is_writeable = rn5t618_adp_property_is_writeable, }; static const struct power_supply_desc rn5t618_usb_desc = { .name = "rn5t618-usb", .type = POWER_SUPPLY_TYPE_USB, + .usb_types = rn5t618_usb_types, + .num_usb_types = ARRAY_SIZE(rn5t618_usb_types), .properties = rn5t618_usb_props, .num_properties = ARRAY_SIZE(rn5t618_usb_props), .get_property = rn5t618_usb_get_property, + .set_property = rn5t618_usb_set_property, + .property_is_writeable = rn5t618_usb_property_is_writeable, }; static irqreturn_t rn5t618_charger_irq(int irq, void *data) diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index f330452341f0..9ad0afe83d1b 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c @@ -164,9 +164,16 @@ static const struct i2c_device_id rt5033_battery_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); +static const struct of_device_id rt5033_battery_of_match[] = { + { .compatible = "richtek,rt5033-battery", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5033_battery_of_match); + static struct i2c_driver rt5033_battery_driver = { .driver = { .name = "rt5033-battery", + .of_match_table = rt5033_battery_of_match, }, .probe = rt5033_battery_probe, .remove = rt5033_battery_remove, diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 8d7a10730e43..f84dbaab283a 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -189,6 +189,14 @@ static const enum power_supply_property sbs_properties[] = { /* Supports special manufacturer commands from TI BQ20Z65 and BQ20Z75 IC. */ #define SBS_FLAGS_TI_BQ20ZX5 BIT(0) +static const enum power_supply_property string_properties[] = { + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_MODEL_NAME, +}; + +#define NR_STRING_BUFFERS ARRAY_SIZE(string_properties) + struct sbs_info { struct i2c_client *client; struct power_supply *power_supply; @@ -202,11 +210,32 @@ struct sbs_info { struct delayed_work work; struct mutex mode_lock; u32 flags; + int technology; + char strings[NR_STRING_BUFFERS][I2C_SMBUS_BLOCK_MAX + 1]; }; -static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; -static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1]; -static char chemistry[I2C_SMBUS_BLOCK_MAX + 1]; +static char *sbs_get_string_buf(struct sbs_info *chip, + enum power_supply_property psp) +{ + int i = 0; + + for (i = 0; i < NR_STRING_BUFFERS; i++) + if (string_properties[i] == psp) + return chip->strings[i]; + + return ERR_PTR(-EINVAL); +} + +static void sbs_invalidate_cached_props(struct sbs_info *chip) +{ + int i = 0; + + chip->technology = -1; + + for (i = 0; i < NR_STRING_BUFFERS; i++) + chip->strings[i][0] = 0; +} + static bool force_load; static int sbs_read_word_data(struct i2c_client *client, u8 address); @@ -244,6 +273,7 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present) chip->is_present = false; /* Disable PEC when no device is present */ client->flags &= ~I2C_CLIENT_PEC; + sbs_invalidate_cached_props(chip); return 0; } @@ -640,17 +670,45 @@ static int sbs_get_battery_property(struct i2c_client *client, return 0; } -static int sbs_get_battery_string_property(struct i2c_client *client, - int reg_offset, enum power_supply_property psp, char *val) +static int sbs_get_property_index(struct i2c_client *client, + enum power_supply_property psp) { - s32 ret; + int count; - ret = sbs_read_string_data(client, sbs_data[reg_offset].addr, val); + for (count = 0; count < ARRAY_SIZE(sbs_data); count++) + if (psp == sbs_data[count].psp) + return count; - if (ret < 0) - return ret; + dev_warn(&client->dev, + "%s: Invalid Property - %d\n", __func__, psp); - return 0; + return -EINVAL; +} + +static const char *sbs_get_constant_string(struct sbs_info *chip, + enum power_supply_property psp) +{ + int ret; + char *buf; + u8 addr; + + buf = sbs_get_string_buf(chip, psp); + if (IS_ERR(buf)) + return buf; + + if (!buf[0]) { + ret = sbs_get_property_index(chip->client, psp); + if (ret < 0) + return ERR_PTR(ret); + + addr = sbs_data[ret].addr; + + ret = sbs_read_string_data(chip->client, addr, buf); + if (ret < 0) + return ERR_PTR(ret); + } + + return buf; } static void sbs_unit_adjustment(struct i2c_client *client, @@ -773,48 +831,36 @@ static int sbs_get_battery_serial_number(struct i2c_client *client, return 0; } -static int sbs_get_property_index(struct i2c_client *client, - enum power_supply_property psp) -{ - int count; - for (count = 0; count < ARRAY_SIZE(sbs_data); count++) - if (psp == sbs_data[count].psp) - return count; - - dev_warn(&client->dev, - "%s: Invalid Property - %d\n", __func__, psp); - - return -EINVAL; -} - -static int sbs_get_chemistry(struct i2c_client *client, +static int sbs_get_chemistry(struct sbs_info *chip, union power_supply_propval *val) { - enum power_supply_property psp = POWER_SUPPLY_PROP_TECHNOLOGY; - int ret; + const char *chemistry; - ret = sbs_get_property_index(client, psp); - if (ret < 0) - return ret; + if (chip->technology != -1) { + val->intval = chip->technology; + return 0; + } - ret = sbs_get_battery_string_property(client, ret, psp, - chemistry); - if (ret < 0) - return ret; + chemistry = sbs_get_constant_string(chip, POWER_SUPPLY_PROP_TECHNOLOGY); + + if (IS_ERR(chemistry)) + return PTR_ERR(chemistry); if (!strncasecmp(chemistry, "LION", 4)) - val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + chip->technology = POWER_SUPPLY_TECHNOLOGY_LION; else if (!strncasecmp(chemistry, "LiP", 3)) - val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; + chip->technology = POWER_SUPPLY_TECHNOLOGY_LIPO; else if (!strncasecmp(chemistry, "NiCd", 4)) - val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd; + chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd; else if (!strncasecmp(chemistry, "NiMH", 4)) - val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; + chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH; else - val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; + chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; - if (val->intval == POWER_SUPPLY_TECHNOLOGY_UNKNOWN) - dev_warn(&client->dev, "Unknown chemistry: %s\n", chemistry); + if (chip->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN) + dev_warn(&chip->client->dev, "Unknown chemistry: %s\n", chemistry); + + val->intval = chip->technology; return 0; } @@ -858,6 +904,7 @@ static int sbs_get_property(struct power_supply *psy, int ret = 0; struct sbs_info *chip = power_supply_get_drvdata(psy); struct i2c_client *client = chip->client; + const char *str; if (chip->gpio_detect) { ret = gpiod_get_value_cansleep(chip->gpio_detect); @@ -883,7 +930,7 @@ static int sbs_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_TECHNOLOGY: - ret = sbs_get_chemistry(client, val); + ret = sbs_get_chemistry(chip, val); if (ret < 0) break; @@ -935,23 +982,12 @@ static int sbs_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_MODEL_NAME: - ret = sbs_get_property_index(client, psp); - if (ret < 0) - break; - - ret = sbs_get_battery_string_property(client, ret, psp, - model_name); - val->strval = model_name; - break; - case POWER_SUPPLY_PROP_MANUFACTURER: - ret = sbs_get_property_index(client, psp); - if (ret < 0) - break; - - ret = sbs_get_battery_string_property(client, ret, psp, - manufacturer); - val->strval = manufacturer; + str = sbs_get_constant_string(chip, psp); + if (IS_ERR(str)) + ret = PTR_ERR(str); + else + val->strval = str; break; case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: @@ -1098,6 +1134,7 @@ static int sbs_probe(struct i2c_client *client) psy_cfg.of_node = client->dev.of_node; psy_cfg.drv_data = chip; chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN; + sbs_invalidate_cached_props(chip); mutex_init(&chip->mode_lock); /* use pdata if available, fall back to DT properties, diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c index 335cb857ef30..288b79836c13 100644 --- a/drivers/power/supply/sc2731_charger.c +++ b/drivers/power/supply/sc2731_charger.c @@ -524,6 +524,7 @@ static const struct of_device_id sc2731_charger_of_match[] = { { .compatible = "sprd,sc2731-charger", }, { } }; +MODULE_DEVICE_TABLE(of, sc2731_charger_of_match); static struct platform_driver sc2731_charger_driver = { .driver = { diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 9c627618c224..1ae8374e1ceb 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -1342,6 +1342,7 @@ static const struct of_device_id sc27xx_fgu_of_match[] = { { .compatible = "sprd,sc2731-fgu", }, { } }; +MODULE_DEVICE_TABLE(of, sc27xx_fgu_of_match); static struct platform_driver sc27xx_fgu_driver = { .probe = sc27xx_fgu_probe, diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c index 3376f42d46c3..df240420f2de 100644 --- a/drivers/power/supply/smb347-charger.c +++ b/drivers/power/supply/smb347-charger.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c index 7efa431a62b2..5ec2e6bb2465 100644 --- a/drivers/power/supply/surface_battery.c +++ b/drivers/power/supply/surface_battery.c @@ -345,6 +345,16 @@ static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_eve struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif); int status; + /* + * We cannot use strict matching when registering the notifier as the + * EC expects us to register it against instance ID 0. Strict matching + * would thus drop events, as those may have non-zero instance IDs in + * this subsystem. So we need to check the instance ID of the event + * here manually. + */ + if (event->instance_id != bat->sdev->uid.instance) + return 0; + dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n", event->command_id, event->instance_id, event->target_id); @@ -720,8 +730,8 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic bat->notif.base.fn = spwr_notify_bat; bat->notif.event.reg = registry; bat->notif.event.id.target_category = sdev->uid.category; - bat->notif.event.id.instance = 0; - bat->notif.event.mask = SSAM_EVENT_MASK_STRICT; + bat->notif.event.id.instance = 0; /* need to register with instance 0 */ + bat->notif.event.mask = SSAM_EVENT_MASK_TARGET; bat->notif.event.flags = SSAM_EVENT_SEQUENCED; bat->psy_desc.name = bat->name; diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c index 81a5b79822c9..a060c36c7766 100644 --- a/drivers/power/supply/surface_charger.c +++ b/drivers/power/supply/surface_charger.c @@ -66,7 +66,7 @@ struct spwr_ac_device { static int spwr_ac_update_unlocked(struct spwr_ac_device *ac) { - u32 old = ac->state; + __le32 old = ac->state; int status; lockdep_assert_held(&ac->lock); diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index c4d5c0667137..35e894f4a379 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -126,8 +126,7 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) { struct pwm_device *pwm; - /* check, whether the driver supports a third cell for flags */ - if (pc->of_pwm_n_cells < 3) + if (pc->of_pwm_n_cells < 2) return ERR_PTR(-EINVAL); /* flags in the third cell are optional */ @@ -144,46 +143,29 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) pwm->args.period = args->args[1]; pwm->args.polarity = PWM_POLARITY_NORMAL; - if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) - pwm->args.polarity = PWM_POLARITY_INVERSED; + if (pc->of_pwm_n_cells >= 3) { + if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) + pwm->args.polarity = PWM_POLARITY_INVERSED; + } return pwm; } EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); -static struct pwm_device * -of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) -{ - struct pwm_device *pwm; - - /* sanity check driver support */ - if (pc->of_pwm_n_cells < 2) - return ERR_PTR(-EINVAL); - - /* all cells are required */ - if (args->args_count != pc->of_pwm_n_cells) - return ERR_PTR(-EINVAL); - - if (args->args[0] >= pc->npwm) - return ERR_PTR(-EINVAL); - - pwm = pwm_request_from_chip(pc, args->args[0], NULL); - if (IS_ERR(pwm)) - return pwm; - - pwm->args.period = args->args[1]; - - return pwm; -} - static void of_pwmchip_add(struct pwm_chip *chip) { if (!chip->dev || !chip->dev->of_node) return; if (!chip->of_xlate) { - chip->of_xlate = of_pwm_simple_xlate; - chip->of_pwm_n_cells = 2; + u32 pwm_cells; + + if (of_property_read_u32(chip->dev->of_node, "#pwm-cells", + &pwm_cells)) + pwm_cells = 2; + + chip->of_xlate = of_pwm_xlate_with_flags; + chip->of_pwm_n_cells = pwm_cells; } of_node_get(chip->dev->of_node); @@ -324,22 +306,10 @@ EXPORT_SYMBOL_GPL(pwmchip_add); */ int pwmchip_remove(struct pwm_chip *chip) { - unsigned int i; - int ret = 0; - pwmchip_sysfs_unexport(chip); mutex_lock(&pwm_lock); - for (i = 0; i < chip->npwm; i++) { - struct pwm_device *pwm = &chip->pwms[i]; - - if (test_bit(PWMF_REQUESTED, &pwm->flags)) { - ret = -EBUSY; - goto out; - } - } - list_del_init(&chip->list); if (IS_ENABLED(CONFIG_OF)) @@ -347,12 +317,31 @@ int pwmchip_remove(struct pwm_chip *chip) free_pwms(chip); -out: mutex_unlock(&pwm_lock); - return ret; + + return 0; } EXPORT_SYMBOL_GPL(pwmchip_remove); +static void devm_pwmchip_remove(void *data) +{ + struct pwm_chip *chip = data; + + pwmchip_remove(chip); +} + +int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip) +{ + int ret; + + ret = pwmchip_add(chip); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); +} +EXPORT_SYMBOL_GPL(devm_pwmchip_add); + /** * pwm_request() - request a PWM device * @pwm: global PWM device index @@ -554,7 +543,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) if (state->period == pwm->state.period && state->duty_cycle == pwm->state.duty_cycle && state->polarity == pwm->state.polarity && - state->enabled == pwm->state.enabled) + state->enabled == pwm->state.enabled && + state->usage_power == pwm->state.usage_power) return 0; if (chip->ops->apply) { @@ -709,14 +699,14 @@ int pwm_adjust_config(struct pwm_device *pwm) } EXPORT_SYMBOL_GPL(pwm_adjust_config); -static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) +static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode) { struct pwm_chip *chip; mutex_lock(&pwm_lock); list_for_each_entry(chip, &pwm_chips, list) - if (chip->dev && chip->dev->of_node == np) { + if (chip->dev && dev_fwnode(chip->dev) == fwnode) { mutex_unlock(&pwm_lock); return chip; } @@ -795,7 +785,7 @@ struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, return ERR_PTR(err); } - pc = of_node_to_pwmchip(args.np); + pc = fwnode_to_pwmchip(of_fwnode_handle(args.np)); if (IS_ERR(pc)) { if (PTR_ERR(pc) != -EPROBE_DEFER) pr_err("%s(): PWM chip not found\n", __func__); @@ -837,31 +827,9 @@ put: } EXPORT_SYMBOL_GPL(of_pwm_get); -#if IS_ENABLED(CONFIG_ACPI) -static struct pwm_chip *device_to_pwmchip(struct device *dev) -{ - struct pwm_chip *chip; - - mutex_lock(&pwm_lock); - - list_for_each_entry(chip, &pwm_chips, list) { - struct acpi_device *adev = ACPI_COMPANION(chip->dev); - - if ((chip->dev == dev) || (adev && &adev->dev == dev)) { - mutex_unlock(&pwm_lock); - return chip; - } - } - - mutex_unlock(&pwm_lock); - - return ERR_PTR(-EPROBE_DEFER); -} -#endif - /** * acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI - * @fwnode: firmware node to get the "pwm" property from + * @fwnode: firmware node to get the "pwms" property from * * Returns the PWM device parsed from the fwnode and index specified in the * "pwms" property or a negative error-code on failure. @@ -876,12 +844,10 @@ static struct pwm_chip *device_to_pwmchip(struct device *dev) * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded * error code on failure. */ -static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode) +static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode) { - struct pwm_device *pwm = ERR_PTR(-ENODEV); -#if IS_ENABLED(CONFIG_ACPI) + struct pwm_device *pwm; struct fwnode_reference_args args; - struct acpi_device *acpi; struct pwm_chip *chip; int ret; @@ -891,14 +857,10 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode) if (ret < 0) return ERR_PTR(ret); - acpi = to_acpi_device_node(args.fwnode); - if (!acpi) - return ERR_PTR(-EINVAL); - if (args.nargs < 2) return ERR_PTR(-EPROTO); - chip = device_to_pwmchip(&acpi->dev); + chip = fwnode_to_pwmchip(args.fwnode); if (IS_ERR(chip)) return ERR_CAST(chip); @@ -911,7 +873,6 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode) if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED) pwm->args.polarity = PWM_POLARITY_INVERSED; -#endif return pwm; } @@ -967,6 +928,7 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num) */ struct pwm_device *pwm_get(struct device *dev, const char *con_id) { + const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL; const char *dev_id = dev ? dev_name(dev) : NULL; struct pwm_device *pwm; struct pwm_chip *chip; @@ -977,12 +939,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) int err; /* look up via DT first */ - if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) - return of_pwm_get(dev, dev->of_node, con_id); + if (is_of_node(fwnode)) + return of_pwm_get(dev, to_of_node(fwnode), con_id); /* then lookup via ACPI */ - if (dev && is_acpi_node(dev->fwnode)) { - pwm = acpi_pwm_get(dev->fwnode); + if (is_acpi_node(fwnode)) { + pwm = acpi_pwm_get(fwnode); if (!IS_ERR(pwm) || PTR_ERR(pwm) != -ENOENT) return pwm; } @@ -1103,9 +1065,9 @@ out: } EXPORT_SYMBOL_GPL(pwm_put); -static void devm_pwm_release(struct device *dev, void *res) +static void devm_pwm_release(void *pwm) { - pwm_put(*(struct pwm_device **)res); + pwm_put(pwm); } /** @@ -1121,19 +1083,16 @@ static void devm_pwm_release(struct device *dev, void *res) */ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) { - struct pwm_device **ptr, *pwm; - - ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct pwm_device *pwm; + int ret; pwm = pwm_get(dev, con_id); - if (!IS_ERR(pwm)) { - *ptr = pwm; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } + if (IS_ERR(pwm)) + return pwm; + + ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm); + if (ret) + return ERR_PTR(ret); return pwm; } @@ -1154,19 +1113,16 @@ EXPORT_SYMBOL_GPL(devm_pwm_get); struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, const char *con_id) { - struct pwm_device **ptr, *pwm; - - ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct pwm_device *pwm; + int ret; pwm = of_pwm_get(dev, np, con_id); - if (!IS_ERR(pwm)) { - *ptr = pwm; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } + if (IS_ERR(pwm)) + return pwm; + + ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm); + if (ret) + return ERR_PTR(ret); return pwm; } @@ -1188,53 +1144,24 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id) { - struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV); - - ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct pwm_device *pwm = ERR_PTR(-ENODEV); + int ret; if (is_of_node(fwnode)) pwm = of_pwm_get(dev, to_of_node(fwnode), con_id); else if (is_acpi_node(fwnode)) pwm = acpi_pwm_get(fwnode); + if (IS_ERR(pwm)) + return pwm; - if (!IS_ERR(pwm)) { - *ptr = pwm; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } + ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm); + if (ret) + return ERR_PTR(ret); return pwm; } EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get); -static int devm_pwm_match(struct device *dev, void *res, void *data) -{ - struct pwm_device **p = res; - - if (WARN_ON(!p || !*p)) - return 0; - - return *p == data; -} - -/** - * devm_pwm_put() - resource managed pwm_put() - * @dev: device for PWM consumer - * @pwm: PWM device - * - * Release a PWM previously allocated using devm_pwm_get(). Calling this - * function is usually not needed because devm-allocated resources are - * automatically released on driver detach. - */ -void devm_pwm_put(struct device *dev, struct pwm_device *pwm) -{ - WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm)); -} -EXPORT_SYMBOL_GPL(devm_pwm_put); - #ifdef CONFIG_DEBUG_FS static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) { @@ -1259,6 +1186,9 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) seq_printf(s, " polarity: %s", state.polarity ? "inverse" : "normal"); + if (state.usage_power) + seq_puts(s, " usage_power"); + seq_puts(s, "\n"); } } diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 6ab597e54005..4459325d3650 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -266,8 +266,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) chip->chip.ops = &atmel_hlcdc_pwm_ops; chip->chip.dev = dev; chip->chip.npwm = 1; - chip->chip.of_xlate = of_pwm_xlate_with_flags; - chip->chip.of_pwm_n_cells = 3; ret = pwmchip_add(&chip->chip); if (ret) { diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 8451d3e846be..bf398f21484d 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -469,8 +469,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) tcbpwm->chip.dev = &pdev->dev; tcbpwm->chip.ops = &atmel_tcb_pwm_ops; - tcbpwm->chip.of_xlate = of_pwm_xlate_with_flags; - tcbpwm->chip.of_pwm_n_cells = 3; tcbpwm->chip.npwm = NPWM; tcbpwm->channel = channel; tcbpwm->regmap = regmap; diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 29b5ad03f715..a8162bae3e8a 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -436,8 +436,6 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.dev = &pdev->dev; atmel_pwm->chip.ops = &atmel_pwm_ops; - atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags; - atmel_pwm->chip.of_pwm_n_cells = 3; atmel_pwm->chip.npwm = 4; ret = pwmchip_add(&atmel_pwm->chip); diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index edd2ce1760ab..0226bf697f09 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -210,8 +210,6 @@ static int iproc_pwmc_probe(struct platform_device *pdev) ip->chip.dev = &pdev->dev; ip->chip.ops = &iproc_pwm_ops; ip->chip.npwm = 4; - ip->chip.of_xlate = of_pwm_xlate_with_flags; - ip->chip.of_pwm_n_cells = 3; ip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ip->base)) diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 800b9edf2e71..8c85c66ea5c9 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -272,8 +272,6 @@ static int kona_pwmc_probe(struct platform_device *pdev) kp->chip.dev = &pdev->dev; kp->chip.ops = &kona_pwm_ops; kp->chip.npwm = 6; - kp->chip.of_xlate = of_pwm_xlate_with_flags; - kp->chip.of_pwm_n_cells = 3; kp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kp->base)) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index fc240d5b8121..50b8594be31d 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -159,8 +159,6 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &bcm2835_pwm_ops; pc->chip.npwm = 2; - pc->chip.of_xlate = of_pwm_xlate_with_flags; - pc->chip.of_pwm_n_cells = 3; platform_set_drvdata(pdev, pc); diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index acb6fbc3cc32..5537b5f6dd5d 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -56,17 +56,17 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct berlin_pwm_chip, chip); } -static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, +static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *bpc, unsigned int channel, unsigned long offset) { - return readl_relaxed(chip->base + channel * 0x10 + offset); + return readl_relaxed(bpc->base + channel * 0x10 + offset); } -static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, +static inline void berlin_pwm_writel(struct berlin_pwm_chip *bpc, unsigned int channel, u32 value, unsigned long offset) { - writel_relaxed(value, chip->base + channel * 0x10 + offset); + writel_relaxed(value, bpc->base + channel * 0x10 + offset); } static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) @@ -87,15 +87,15 @@ static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) kfree(channel); } -static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, - int duty_ns, int period_ns) +static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + u64 duty_ns, u64 period_ns) { - struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip); bool prescale_4096 = false; u32 value, duty, period; u64 cycles; - cycles = clk_get_rate(pwm->clk); + cycles = clk_get_rate(bpc->clk); cycles *= period_ns; do_div(cycles, NSEC_PER_SEC); @@ -112,68 +112,101 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, do_div(cycles, period_ns); duty = cycles; - value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); + value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL); if (prescale_4096) value |= BERLIN_PWM_PRESCALE_4096; else value &= ~BERLIN_PWM_PRESCALE_4096; - berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); + berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL); - berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); - berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT); + berlin_pwm_writel(bpc, pwm->hwpwm, duty, BERLIN_PWM_DUTY); + berlin_pwm_writel(bpc, pwm->hwpwm, period, BERLIN_PWM_TCNT); return 0; } static int berlin_pwm_set_polarity(struct pwm_chip *chip, - struct pwm_device *pwm_dev, + struct pwm_device *pwm, enum pwm_polarity polarity) { - struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip); u32 value; - value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); + value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL); if (polarity == PWM_POLARITY_NORMAL) value &= ~BERLIN_PWM_INVERT_POLARITY; else value |= BERLIN_PWM_INVERT_POLARITY; - berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); + berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL); return 0; } -static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) +static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip); u32 value; - value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); + value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN); value |= BERLIN_PWM_ENABLE; - berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); + berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN); return 0; } static void berlin_pwm_disable(struct pwm_chip *chip, - struct pwm_device *pwm_dev) + struct pwm_device *pwm) { - struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); + struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip); u32 value; - value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); + value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN); value &= ~BERLIN_PWM_ENABLE; - berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); + berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN); +} + +static int berlin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + bool enabled = pwm->state.enabled; + + if (state->polarity != pwm->state.polarity) { + if (enabled) { + berlin_pwm_disable(chip, pwm); + enabled = false; + } + + err = berlin_pwm_set_polarity(chip, pwm, state->polarity); + if (err) + return err; + } + + if (!state->enabled) { + if (enabled) + berlin_pwm_disable(chip, pwm); + return 0; + } + + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) { + err = berlin_pwm_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + } + + if (!enabled) + return berlin_pwm_enable(chip, pwm); + + return 0; } static const struct pwm_ops berlin_pwm_ops = { .request = berlin_pwm_request, .free = berlin_pwm_free, - .config = berlin_pwm_config, - .set_polarity = berlin_pwm_set_polarity, - .enable = berlin_pwm_enable, - .disable = berlin_pwm_disable, + .apply = berlin_pwm_apply, .owner = THIS_MODULE, }; @@ -185,99 +218,97 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match); static int berlin_pwm_probe(struct platform_device *pdev) { - struct berlin_pwm_chip *pwm; + struct berlin_pwm_chip *bpc; int ret; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) + bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL); + if (!bpc) return -ENOMEM; - pwm->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(pwm->base)) - return PTR_ERR(pwm->base); + bpc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bpc->base)) + return PTR_ERR(bpc->base); - pwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); + bpc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(bpc->clk)) + return PTR_ERR(bpc->clk); - ret = clk_prepare_enable(pwm->clk); + ret = clk_prepare_enable(bpc->clk); if (ret) return ret; - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &berlin_pwm_ops; - pwm->chip.npwm = 4; - pwm->chip.of_xlate = of_pwm_xlate_with_flags; - pwm->chip.of_pwm_n_cells = 3; + bpc->chip.dev = &pdev->dev; + bpc->chip.ops = &berlin_pwm_ops; + bpc->chip.npwm = 4; - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&bpc->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - clk_disable_unprepare(pwm->clk); + clk_disable_unprepare(bpc->clk); return ret; } - platform_set_drvdata(pdev, pwm); + platform_set_drvdata(pdev, bpc); return 0; } static int berlin_pwm_remove(struct platform_device *pdev) { - struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev); - int ret; + struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev); - ret = pwmchip_remove(&pwm->chip); - clk_disable_unprepare(pwm->clk); + pwmchip_remove(&bpc->chip); - return ret; + clk_disable_unprepare(bpc->clk); + + return 0; } #ifdef CONFIG_PM_SLEEP static int berlin_pwm_suspend(struct device *dev) { - struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); + struct berlin_pwm_chip *bpc = dev_get_drvdata(dev); unsigned int i; - for (i = 0; i < pwm->chip.npwm; i++) { + for (i = 0; i < bpc->chip.npwm; i++) { struct berlin_pwm_channel *channel; - channel = pwm_get_chip_data(&pwm->chip.pwms[i]); + channel = pwm_get_chip_data(&bpc->chip.pwms[i]); if (!channel) continue; - channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE); - channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL); - channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY); - channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT); + channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE); + channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL); + channel->duty = berlin_pwm_readl(bpc, i, BERLIN_PWM_DUTY); + channel->tcnt = berlin_pwm_readl(bpc, i, BERLIN_PWM_TCNT); } - clk_disable_unprepare(pwm->clk); + clk_disable_unprepare(bpc->clk); return 0; } static int berlin_pwm_resume(struct device *dev) { - struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); + struct berlin_pwm_chip *bpc = dev_get_drvdata(dev); unsigned int i; int ret; - ret = clk_prepare_enable(pwm->clk); + ret = clk_prepare_enable(bpc->clk); if (ret) return ret; - for (i = 0; i < pwm->chip.npwm; i++) { + for (i = 0; i < bpc->chip.npwm; i++) { struct berlin_pwm_channel *channel; - channel = pwm_get_chip_data(&pwm->chip.pwms[i]); + channel = pwm_get_chip_data(&bpc->chip.pwms[i]); if (!channel) continue; - berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL); - berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY); - berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT); - berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE); + berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL); + berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY); + berlin_pwm_writel(bpc, i, channel->tcnt, BERLIN_PWM_TCNT); + berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_ENABLE); } return 0; diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c index f3d17a590305..d7ad88685830 100644 --- a/drivers/pwm/pwm-clps711x.c +++ b/drivers/pwm/pwm-clps711x.c @@ -134,16 +134,7 @@ static int clps711x_pwm_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); - platform_set_drvdata(pdev, priv); - - return pwmchip_add(&priv->chip); -} - -static int clps711x_pwm_remove(struct platform_device *pdev) -{ - struct clps711x_chip *priv = platform_get_drvdata(pdev); - - return pwmchip_remove(&priv->chip); + return devm_pwmchip_add(&pdev->dev, &priv->chip); } static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = { @@ -158,7 +149,6 @@ static struct platform_driver clps711x_pwm_driver = { .of_match_table = of_match_ptr(clps711x_pwm_dt_ids), }, .probe = clps711x_pwm_probe, - .remove = clps711x_pwm_remove, }; module_platform_driver(clps711x_pwm_driver); diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 02522a9a3073..7b357d1cf642 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -173,21 +173,11 @@ static int crystalcove_pwm_probe(struct platform_device *pdev) /* get the PMIC regmap */ pwm->regmap = pmic->regmap; - platform_set_drvdata(pdev, pwm); - - return pwmchip_add(&pwm->chip); -} - -static int crystalcove_pwm_remove(struct platform_device *pdev) -{ - struct crystalcove_pwm *pwm = platform_get_drvdata(pdev); - - return pwmchip_remove(&pwm->chip); + return devm_pwmchip_add(&pdev->dev, &pwm->chip); } static struct platform_driver crystalcove_pwm_driver = { .probe = crystalcove_pwm_probe, - .remove = crystalcove_pwm_remove, .driver = { .name = "crystal_cove_pwm", }, diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index 4ca70794ad96..8a3d781e6514 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -58,111 +58,112 @@ static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) ep93xx_pwm_release_gpio(pdev); } -static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { + int ret; struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); - void __iomem *base = ep93xx_pwm->base; - unsigned long long c; - unsigned long period_cycles; - unsigned long duty_cycles; - unsigned long term; - int ret = 0; + bool enabled = state->enabled; + + if (state->polarity != pwm->state.polarity) { + if (enabled) { + writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); + clk_disable_unprepare(ep93xx_pwm->clk); + enabled = false; + } + + /* + * The clock needs to be enabled to access the PWM registers. + * Polarity can only be changed when the PWM is disabled. + */ + ret = clk_prepare_enable(ep93xx_pwm->clk); + if (ret) + return ret; + + if (state->polarity == PWM_POLARITY_INVERSED) + writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT); + else + writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT); + + clk_disable_unprepare(ep93xx_pwm->clk); + } + + if (!state->enabled) { + if (enabled) { + writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); + clk_disable_unprepare(ep93xx_pwm->clk); + } + + return 0; + } + + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) { + struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); + void __iomem *base = ep93xx_pwm->base; + unsigned long long c; + unsigned long period_cycles; + unsigned long duty_cycles; + unsigned long term; + + /* + * The clock needs to be enabled to access the PWM registers. + * Configuration can be changed at any time. + */ + if (!pwm_is_enabled(pwm)) { + ret = clk_prepare_enable(ep93xx_pwm->clk); + if (ret) + return ret; + } + + c = clk_get_rate(ep93xx_pwm->clk); + c *= state->period; + do_div(c, 1000000000); + period_cycles = c; + + c = period_cycles; + c *= state->duty_cycle; + do_div(c, state->period); + duty_cycles = c; + + if (period_cycles < 0x10000 && duty_cycles < 0x10000) { + term = readw(base + EP93XX_PWMx_TERM_COUNT); + + /* Order is important if PWM is running */ + if (period_cycles > term) { + writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); + writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); + } else { + writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); + writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); + } + ret = 0; + } else { + ret = -EINVAL; + } + + if (!pwm_is_enabled(pwm)) + clk_disable_unprepare(ep93xx_pwm->clk); - /* - * The clock needs to be enabled to access the PWM registers. - * Configuration can be changed at any time. - */ - if (!pwm_is_enabled(pwm)) { - ret = clk_enable(ep93xx_pwm->clk); if (ret) return ret; } - c = clk_get_rate(ep93xx_pwm->clk); - c *= period_ns; - do_div(c, 1000000000); - period_cycles = c; + if (!enabled) { + ret = clk_prepare_enable(ep93xx_pwm->clk); + if (ret) + return ret; - c = period_cycles; - c *= duty_ns; - do_div(c, period_ns); - duty_cycles = c; - - if (period_cycles < 0x10000 && duty_cycles < 0x10000) { - term = readw(base + EP93XX_PWMx_TERM_COUNT); - - /* Order is important if PWM is running */ - if (period_cycles > term) { - writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); - writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); - } else { - writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); - writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); - } - } else { - ret = -EINVAL; + writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); } - if (!pwm_is_enabled(pwm)) - clk_disable(ep93xx_pwm->clk); - - return ret; -} - -static int ep93xx_pwm_polarity(struct pwm_chip *chip, struct pwm_device *pwm, - enum pwm_polarity polarity) -{ - struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); - int ret; - - /* - * The clock needs to be enabled to access the PWM registers. - * Polarity can only be changed when the PWM is disabled. - */ - ret = clk_enable(ep93xx_pwm->clk); - if (ret) - return ret; - - if (polarity == PWM_POLARITY_INVERSED) - writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT); - else - writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT); - - clk_disable(ep93xx_pwm->clk); - return 0; } -static int ep93xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); - int ret; - - ret = clk_enable(ep93xx_pwm->clk); - if (ret) - return ret; - - writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); - - return 0; -} - -static void ep93xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); - - writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); - clk_disable(ep93xx_pwm->clk); -} - static const struct pwm_ops ep93xx_pwm_ops = { .request = ep93xx_pwm_request, .free = ep93xx_pwm_free, - .config = ep93xx_pwm_config, - .set_polarity = ep93xx_pwm_polarity, - .enable = ep93xx_pwm_enable, - .disable = ep93xx_pwm_disable, + .apply = ep93xx_pwm_apply, .owner = THIS_MODULE, }; diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 0e1ae9469eda..96ccd772280c 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -451,8 +451,6 @@ static int fsl_pwm_probe(struct platform_device *pdev) fpc->chip.ops = &fsl_pwm_ops; - fpc->chip.of_xlate = of_pwm_xlate_with_flags; - fpc->chip.of_pwm_n_cells = 3; fpc->chip.npwm = 8; ret = pwmchip_add(&fpc->chip); diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 82d17fc75c21..4a6e9ad3c0ff 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -206,8 +206,6 @@ static int hibvt_pwm_probe(struct platform_device *pdev) pwm_chip->chip.ops = &hibvt_pwm_ops; pwm_chip->chip.dev = &pdev->dev; pwm_chip->chip.npwm = soc->num_pwms; - pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags; - pwm_chip->chip.of_pwm_n_cells = 3; pwm_chip->soc = soc; pwm_chip->base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index cc37054589cc..11b16ecc4f96 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -156,7 +156,7 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip); int ret; - ret = pm_runtime_get_sync(chip->dev); + ret = pm_runtime_resume_and_get(chip->dev); if (ret < 0) return ret; diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index 97c9133b6876..dbb50493abdd 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -363,8 +363,6 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev) tpm->chip.dev = &pdev->dev; tpm->chip.ops = &imx_tpm_pwm_ops; - tpm->chip.of_xlate = of_pwm_xlate_with_flags; - tpm->chip.of_pwm_n_cells = 3; /* get number of channels */ val = readl(tpm->base + PWM_IMX_TPM_PARAM); diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index c957b365448e..bcd849496f8d 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -141,8 +141,6 @@ static int pwm_imx1_probe(struct platform_device *pdev) if (!imx) return -ENOMEM; - platform_set_drvdata(pdev, imx); - imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imx->clk_ipg)) return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg), @@ -161,16 +159,7 @@ static int pwm_imx1_probe(struct platform_device *pdev) if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); - return pwmchip_add(&imx->chip); -} - -static int pwm_imx1_remove(struct platform_device *pdev) -{ - struct pwm_imx1_chip *imx = platform_get_drvdata(pdev); - - pwm_imx1_clk_disable_unprepare(&imx->chip); - - return pwmchip_remove(&imx->chip); + return devm_pwmchip_add(&pdev->dev, &imx->chip); } static struct platform_driver pwm_imx1_driver = { @@ -179,7 +168,6 @@ static struct platform_driver pwm_imx1_driver = { .of_match_table = pwm_imx1_dt_ids, }, .probe = pwm_imx1_probe, - .remove = pwm_imx1_remove, }; module_platform_driver(pwm_imx1_driver); diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index ba695115c160..f6588a96fbd9 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -329,9 +329,6 @@ static int pwm_imx27_probe(struct platform_device *pdev) imx->chip.dev = &pdev->dev; imx->chip.npwm = 1; - imx->chip.of_xlate = of_pwm_xlate_with_flags; - imx->chip.of_pwm_n_cells = 3; - imx->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 5b6bdcdcecf5..990e7904c7f1 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -244,8 +244,6 @@ static int jz4740_pwm_probe(struct platform_device *pdev) jz4740->chip.dev = dev; jz4740->chip.ops = &jz4740_pwm_ops; jz4740->chip.npwm = info->num_pwms; - jz4740->chip.of_xlate = of_pwm_xlate_with_flags; - jz4740->chip.of_pwm_n_cells = 3; platform_set_drvdata(pdev, jz4740); diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index b643ac61a2e7..8e461f3baa05 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -371,8 +371,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm->chip.dev = &pdev->dev; lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops; lpc18xx_pwm->chip.npwm = 16; - lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags; - lpc18xx_pwm->chip.of_pwm_n_cells = 3; /* SCT counter must be in unify (32 bit) mode */ lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG, diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c index cf749ea0de9f..c893ec3d2fb4 100644 --- a/drivers/pwm/pwm-lpss-pci.c +++ b/drivers/pwm/pwm-lpss-pci.c @@ -69,12 +69,8 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev, static void pwm_lpss_remove_pci(struct pci_dev *pdev) { - struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); - pm_runtime_forbid(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - - pwm_lpss_remove(lpwm); } #ifdef CONFIG_PM diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 986786be1e49..928570430cef 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -85,10 +85,8 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev) static int pwm_lpss_remove_platform(struct platform_device *pdev) { - struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); - pm_runtime_disable(&pdev->dev); - return pwm_lpss_remove(lpwm); + return 0; } static const struct acpi_device_id pwm_lpss_acpi_match[] = { diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 58b4031524af..36d4e83e6b79 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -236,7 +236,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, lpwm->chip.ops = &pwm_lpss_ops; lpwm->chip.npwm = info->npwm; - ret = pwmchip_add(&lpwm->chip); + ret = devm_pwmchip_add(dev, &lpwm->chip); if (ret) { dev_err(dev, "failed to add PWM chip: %d\n", ret); return ERR_PTR(ret); @@ -252,12 +252,6 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, } EXPORT_SYMBOL_GPL(pwm_lpss_probe); -int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) -{ - return pwmchip_remove(&lpwm->chip); -} -EXPORT_SYMBOL_GPL(pwm_lpss_remove); - MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 70db7e389d66..8b3476f25e06 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -35,6 +35,5 @@ struct pwm_lpss_boardinfo { struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); -int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); #endif /* __PWM_LPSS_H */ diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 9eb060613cb4..3cf3bcf5ddfc 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -551,8 +551,6 @@ static int meson_pwm_probe(struct platform_device *pdev) meson->chip.dev = &pdev->dev; meson->chip.ops = &meson_pwm_ops; meson->chip.npwm = MESON_NUM_PWMS; - meson->chip.of_xlate = of_pwm_xlate_with_flags; - meson->chip.of_pwm_n_cells = 3; meson->data = of_device_get_match_data(&pdev->dev); @@ -560,31 +558,21 @@ static int meson_pwm_probe(struct platform_device *pdev) if (err < 0) return err; - err = pwmchip_add(&meson->chip); + err = devm_pwmchip_add(&pdev->dev, &meson->chip); if (err < 0) { dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err); return err; } - platform_set_drvdata(pdev, meson); - return 0; } -static int meson_pwm_remove(struct platform_device *pdev) -{ - struct meson_pwm *meson = platform_get_drvdata(pdev); - - return pwmchip_remove(&meson->chip); -} - static struct platform_driver meson_pwm_driver = { .driver = { .name = "meson-pwm", .of_match_table = meson_pwm_matches, }, .probe = meson_pwm_probe, - .remove = meson_pwm_remove, }; module_platform_driver(meson_pwm_driver); diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 0266e84e982c..a22180803bd7 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -138,8 +138,6 @@ static int mxs_pwm_probe(struct platform_device *pdev) mxs->chip.dev = &pdev->dev; mxs->chip.ops = &mxs_pwm_ops; - mxs->chip.of_xlate = of_pwm_xlate_with_flags; - mxs->chip.of_pwm_n_cells = 3; ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); if (ret < 0) { diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 612b3c859295..507a2d945b90 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -404,8 +404,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) omap->chip.dev = &pdev->dev; omap->chip.ops = &pwm_omap_dmtimer_ops; omap->chip.npwm = 1; - omap->chip.of_xlate = of_pwm_xlate_with_flags; - omap->chip.of_pwm_n_cells = 3; mutex_init(&omap->mutex); diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 7c9f174de64e..42ed770b432c 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -23,11 +23,11 @@ #include /* - * Because the PCA9685 has only one prescaler per chip, changing the period of - * one channel affects the period of all 16 PWM outputs! - * However, the ratio between each configured duty cycle and the chip-wide - * period remains constant, because the OFF time is set in proportion to the - * counter range. + * Because the PCA9685 has only one prescaler per chip, only the first channel + * that is enabled is allowed to change the prescale register. + * PWM channels requested afterwards must use a period that results in the same + * prescale setting as the one set by the first requested channel. + * GPIOs do not count as enabled PWMs as they are not using the prescaler. */ #define PCA9685_MODE1 0x00 @@ -78,8 +78,9 @@ struct pca9685 { struct pwm_chip chip; struct regmap *regmap; -#if IS_ENABLED(CONFIG_GPIOLIB) struct mutex lock; + DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1); +#if IS_ENABLED(CONFIG_GPIOLIB) struct gpio_chip gpio; DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1); #endif @@ -90,51 +91,120 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip) return container_of(chip, struct pca9685, chip); } +/* This function is supposed to be called with the lock mutex held */ +static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel) +{ + /* No PWM enabled: Change allowed */ + if (bitmap_empty(pca->pwms_enabled, PCA9685_MAXCHAN + 1)) + return true; + /* More than one PWM enabled: Change not allowed */ + if (bitmap_weight(pca->pwms_enabled, PCA9685_MAXCHAN + 1) > 1) + return false; + /* + * Only one PWM enabled: Change allowed if the PWM about to + * be changed is the one that is already enabled + */ + return test_bit(channel, pca->pwms_enabled); +} + +static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned int *val) +{ + struct device *dev = pca->chip.dev; + int err; + + err = regmap_read(pca->regmap, reg, val); + if (err) + dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, ERR_PTR(err)); + + return err; +} + +static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int val) +{ + struct device *dev = pca->chip.dev; + int err; + + err = regmap_write(pca->regmap, reg, val); + if (err) + dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err)); + + return err; +} + /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */ static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int duty) { + struct pwm_device *pwm = &pca->chip.pwms[channel]; + unsigned int on, off; + if (duty == 0) { /* Set the full OFF bit, which has the highest precedence */ - regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL); + pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL); + return; } else if (duty >= PCA9685_COUNTER_RANGE) { /* Set the full ON bit and clear the full OFF bit */ - regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL); - regmap_write(pca->regmap, REG_OFF_H(channel), 0); - } else { - /* Set OFF time (clears the full OFF bit) */ - regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff); - regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf); - /* Clear the full ON bit */ - regmap_write(pca->regmap, REG_ON_H(channel), 0); + pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL); + pca9685_write_reg(pca, REG_OFF_H(channel), 0); + return; } + + + if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) { + /* + * If usage_power is set, the pca9685 driver will phase shift + * the individual channels relative to their channel number. + * This improves EMI because the enabled channels no longer + * turn on at the same time, while still maintaining the + * configured duty cycle / power output. + */ + on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN; + } else + on = 0; + + off = (on + duty) % PCA9685_COUNTER_RANGE; + + /* Set ON time (clears full ON bit) */ + pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff); + pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf); + /* Set OFF time (clears full OFF bit) */ + pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff); + pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf); } static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel) { - unsigned int off_h = 0, val = 0; + struct pwm_device *pwm = &pca->chip.pwms[channel]; + unsigned int off = 0, on = 0, val = 0; if (WARN_ON(channel >= PCA9685_MAXCHAN)) { /* HW does not support reading state of "all LEDs" channel */ return 0; } - regmap_read(pca->regmap, LED_N_OFF_H(channel), &off_h); - if (off_h & LED_FULL) { + pca9685_read_reg(pca, LED_N_OFF_H(channel), &off); + if (off & LED_FULL) { /* Full OFF bit is set */ return 0; } - regmap_read(pca->regmap, LED_N_ON_H(channel), &val); - if (val & LED_FULL) { + pca9685_read_reg(pca, LED_N_ON_H(channel), &on); + if (on & LED_FULL) { /* Full ON bit is set */ return PCA9685_COUNTER_RANGE; } - if (regmap_read(pca->regmap, LED_N_OFF_L(channel), &val)) { - /* Reset val to 0 in case reading LED_N_OFF_L failed */ + pca9685_read_reg(pca, LED_N_OFF_L(channel), &val); + off = ((off & 0xf) << 8) | (val & 0xff); + if (!pwm->state.usage_power) + return off; + + /* Read ON register to calculate duty cycle of staggered output */ + if (pca9685_read_reg(pca, LED_N_ON_L(channel), &val)) { + /* Reset val to 0 in case reading LED_N_ON_L failed */ val = 0; } - return ((off_h & 0xf) << 8) | (val & 0xff); + on = ((on & 0xf) << 8) | (val & 0xff); + return (off - on) & (PCA9685_COUNTER_RANGE - 1); } #if IS_ENABLED(CONFIG_GPIOLIB) @@ -240,8 +310,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca) { struct device *dev = pca->chip.dev; - mutex_init(&pca->lock); - pca->gpio.label = dev_name(dev); pca->gpio.parent = dev; pca->gpio.request = pca9685_pwm_gpio_request; @@ -277,16 +345,23 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca) static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable) { - regmap_update_bits(pca->regmap, PCA9685_MODE1, - MODE1_SLEEP, enable ? MODE1_SLEEP : 0); + struct device *dev = pca->chip.dev; + int err = regmap_update_bits(pca->regmap, PCA9685_MODE1, + MODE1_SLEEP, enable ? MODE1_SLEEP : 0); + if (err) { + dev_err(dev, "regmap_update_bits of register 0x%x failed: %pe\n", + PCA9685_MODE1, ERR_PTR(err)); + return; + } + if (!enable) { /* Wait 500us for the oscillator to be back up */ udelay(500); } } -static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) +static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { struct pca9685 *pca = to_pca(chip); unsigned long long duty, prescale; @@ -307,8 +382,14 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } - regmap_read(pca->regmap, PCA9685_PRESCALE, &val); + pca9685_read_reg(pca, PCA9685_PRESCALE, &val); if (prescale != val) { + if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) { + dev_err(chip->dev, + "pwm not changed: periods of enabled pwms must match!\n"); + return -EBUSY; + } + /* * Putting the chip briefly into SLEEP mode * at this point won't interfere with the @@ -319,7 +400,7 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, pca9685_set_sleep_mode(pca, true); /* Change the chip-wide output frequency */ - regmap_write(pca->regmap, PCA9685_PRESCALE, prescale); + pca9685_write_reg(pca, PCA9685_PRESCALE, prescale); /* Wake the chip up */ pca9685_set_sleep_mode(pca, false); @@ -331,6 +412,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } +static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct pca9685 *pca = to_pca(chip); + int ret; + + mutex_lock(&pca->lock); + ret = __pca9685_pwm_apply(chip, pwm, state); + if (ret == 0) { + if (state->enabled) + set_bit(pwm->hwpwm, pca->pwms_enabled); + else + clear_bit(pwm->hwpwm, pca->pwms_enabled); + } + mutex_unlock(&pca->lock); + + return ret; +} + static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { @@ -339,7 +439,7 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, unsigned int val = 0; /* Calculate (chip-wide) period from prescale value */ - regmap_read(pca->regmap, PCA9685_PRESCALE, &val); + pca9685_read_reg(pca, PCA9685_PRESCALE, &val); /* * PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000. * The following calculation is therefore only a multiplication @@ -372,6 +472,14 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm)) return -EBUSY; + + if (pwm->hwpwm < PCA9685_MAXCHAN) { + /* PWMs - except the "all LEDs" channel - default to enabled */ + mutex_lock(&pca->lock); + set_bit(pwm->hwpwm, pca->pwms_enabled); + mutex_unlock(&pca->lock); + } + pm_runtime_get_sync(chip->dev); return 0; @@ -381,7 +489,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct pca9685 *pca = to_pca(chip); + mutex_lock(&pca->lock); pca9685_pwm_set_duty(pca, pwm->hwpwm, 0); + clear_bit(pwm->hwpwm, pca->pwms_enabled); + mutex_unlock(&pca->lock); + pm_runtime_put(chip->dev); pca9685_pwm_clear_inuse(pca, pwm->hwpwm); } @@ -422,7 +534,11 @@ static int pca9685_pwm_probe(struct i2c_client *client, i2c_set_clientdata(client, pca); - regmap_read(pca->regmap, PCA9685_MODE2, ®); + mutex_init(&pca->lock); + + ret = pca9685_read_reg(pca, PCA9685_MODE2, ®); + if (ret) + return ret; if (device_property_read_bool(&client->dev, "invert")) reg |= MODE2_INVRT; @@ -434,16 +550,20 @@ static int pca9685_pwm_probe(struct i2c_client *client, else reg |= MODE2_OUTDRV; - regmap_write(pca->regmap, PCA9685_MODE2, reg); + ret = pca9685_write_reg(pca, PCA9685_MODE2, reg); + if (ret) + return ret; /* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */ - regmap_read(pca->regmap, PCA9685_MODE1, ®); + pca9685_read_reg(pca, PCA9685_MODE1, ®); reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3); - regmap_write(pca->regmap, PCA9685_MODE1, reg); + pca9685_write_reg(pca, PCA9685_MODE1, reg); - /* Reset OFF registers to POR default */ - regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL); - regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL); + /* Reset OFF/ON registers to POR default */ + pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, LED_FULL); + pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_H, LED_FULL); + pca9685_write_reg(pca, PCA9685_ALL_LED_ON_L, 0); + pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, 0); pca->chip.ops = &pca9685_pwm_ops; /* Add an extra channel for ALL_LED */ diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index cfb683827d32..e091a528e33c 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -165,7 +165,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); - struct pxa_pwm_chip *pwm; + struct pxa_pwm_chip *pc; int ret = 0; if (IS_ENABLED(CONFIG_OF) && id == NULL) @@ -174,46 +174,44 @@ static int pwm_probe(struct platform_device *pdev) if (id == NULL) return -EINVAL; - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (pwm == NULL) + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (pc == NULL) return -ENOMEM; - pwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); + pc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pc->clk)) + return PTR_ERR(pc->clk); - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &pxa_pwm_ops; - pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; + pc->chip.dev = &pdev->dev; + pc->chip.ops = &pxa_pwm_ops; + pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; if (IS_ENABLED(CONFIG_OF)) { - pwm->chip.of_xlate = pxa_pwm_of_xlate; - pwm->chip.of_pwm_n_cells = 1; + pc->chip.of_xlate = pxa_pwm_of_xlate; + pc->chip.of_pwm_n_cells = 1; } - pwm->mmio_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(pwm->mmio_base)) - return PTR_ERR(pwm->mmio_base); + pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pc->mmio_base)) + return PTR_ERR(pc->mmio_base); - ret = pwmchip_add(&pwm->chip); + ret = pwmchip_add(&pc->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); return ret; } - platform_set_drvdata(pdev, pwm); + platform_set_drvdata(pdev, pc); return 0; } static int pwm_remove(struct platform_device *pdev) { - struct pxa_pwm_chip *chip; + struct pxa_pwm_chip *pc; - chip = platform_get_drvdata(pdev); - if (chip == NULL) - return -ENODEV; + pc = platform_get_drvdata(pdev); - return pwmchip_remove(&chip->chip); + return pwmchip_remove(&pc->chip); } static struct platform_driver pwm_driver = { diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index e2959fae0969..b853e7942605 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -408,8 +408,6 @@ static int tpu_probe(struct platform_device *pdev) tpu->chip.dev = &pdev->dev; tpu->chip.ops = &tpu_pwm_ops; - tpu->chip.of_xlate = of_pwm_xlate_with_flags; - tpu->chip.of_pwm_n_cells = 3; tpu->chip.npwm = TPU_CHANNEL_MAX; pm_runtime_enable(&pdev->dev); diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 301785fa293e..cbe900877724 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -354,11 +354,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev) pc->chip.ops = &rockchip_pwm_ops; pc->chip.npwm = 1; - if (pc->data->supports_polarity) { - pc->chip.of_xlate = of_pwm_xlate_with_flags; - pc->chip.of_pwm_n_cells = 3; - } - enable_conf = pc->data->enable_conf; ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); enabled = (ctrl & enable_conf) == enable_conf; diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 515489fa4f6d..f6c528f02d43 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -526,9 +526,6 @@ static int pwm_samsung_probe(struct platform_device *pdev) ret = pwm_samsung_parse_dt(chip); if (ret) return ret; - - chip->chip.of_xlate = of_pwm_xlate_with_flags; - chip->chip.of_pwm_n_cells = 3; } else { if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data specified\n"); diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 688737f091ac..420edc4aa94a 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -242,8 +242,6 @@ static int pwm_sifive_probe(struct platform_device *pdev) chip = &ddata->chip; chip->dev = dev; chip->ops = &pwm_sifive_ops; - chip->of_xlate = of_pwm_xlate_with_flags; - chip->of_pwm_n_cells = 3; chip->npwm = 4; ddata->regs = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 1a1cedfd11ce..48c31dac2f32 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -75,7 +75,7 @@ static inline void spear_pwm_writel(struct spear_pwm_chip *chip, } static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + u64 duty_ns, u64 period_ns) { struct spear_pwm_chip *pc = to_spear_pwm_chip(chip); u64 val, div, clk_rate; @@ -163,10 +163,35 @@ static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable(pc->clk); } +static int spear_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + int err; + + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) { + if (pwm->state.enabled) + spear_pwm_disable(chip, pwm); + return 0; + } + + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) { + err = spear_pwm_config(chip, pwm, state->duty_cycle, state->period); + if (err) + return err; + } + + if (!pwm->state.enabled) + return spear_pwm_enable(chip, pwm); + + return 0; +} + static const struct pwm_ops spear_pwm_ops = { - .config = spear_pwm_config, - .enable = spear_pwm_enable, - .disable = spear_pwm_disable, + .apply = spear_pwm_apply, .owner = THIS_MODULE, }; @@ -228,14 +253,13 @@ static int spear_pwm_probe(struct platform_device *pdev) static int spear_pwm_remove(struct platform_device *pdev) { struct spear_pwm_chip *pc = platform_get_drvdata(pdev); - int i; - for (i = 0; i < NUM_PWM; i++) - pwm_disable(&pc->chip.pwms[i]); + pwmchip_remove(&pc->chip); /* clk was prepared in probe, hence unprepare it here */ clk_unprepare(pc->clk); - return pwmchip_remove(&pc->chip); + + return 0; } static const struct of_device_id spear_pwm_of_match[] = { diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 98c479dfae31..f2a85e8dd941 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -284,7 +284,9 @@ static int sprd_pwm_remove(struct platform_device *pdev) { struct sprd_pwm_chip *spc = platform_get_drvdata(pdev); - return pwmchip_remove(&spc->chip); + pwmchip_remove(&spc->chip); + + return 0; } static const struct of_device_id sprd_pwm_of_match[] = { diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index af08f564ef1d..93dd03618465 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -208,8 +208,6 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev) priv->chip.dev = &pdev->dev; priv->chip.ops = &stm32_pwm_lp_ops; priv->chip.npwm = 1; - priv->chip.of_xlate = of_pwm_xlate_with_flags; - priv->chip.of_pwm_n_cells = 3; ret = pwmchip_add(&priv->chip); if (ret < 0) diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index c46fb90036ab..794ca5b02968 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -621,8 +621,6 @@ static int stm32_pwm_probe(struct platform_device *pdev) priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; - priv->chip.of_xlate = of_pwm_xlate_with_flags; - priv->chip.of_pwm_n_cells = 3; if (!priv->regmap || !priv->clk) return -EINVAL; diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index e01becd102c0..c952604e91f3 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -460,8 +460,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev) pwm->chip.dev = &pdev->dev; pwm->chip.ops = &sun4i_pwm_ops; pwm->chip.npwm = pwm->data->npwm; - pwm->chip.of_xlate = of_pwm_xlate_with_flags; - pwm->chip.of_pwm_n_cells = 3; spin_lock_init(&pwm->ctrl_lock); diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index c529a170bcdd..11a10b575ace 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -300,32 +300,12 @@ static int tegra_pwm_probe(struct platform_device *pdev) static int tegra_pwm_remove(struct platform_device *pdev) { struct tegra_pwm_chip *pc = platform_get_drvdata(pdev); - unsigned int i; - int err; - if (WARN_ON(!pc)) - return -ENODEV; - - err = clk_prepare_enable(pc->clk); - if (err < 0) - return err; - - for (i = 0; i < pc->chip.npwm; i++) { - struct pwm_device *pwm = &pc->chip.pwms[i]; - - if (!pwm_is_enabled(pwm)) - if (clk_prepare_enable(pc->clk) < 0) - continue; - - pwm_writel(pc, i, 0); - - clk_disable_unprepare(pc->clk); - } + pwmchip_remove(&pc->chip); reset_control_assert(pc->rst); - clk_disable_unprepare(pc->clk); - return pwmchip_remove(&pc->chip); + return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index b9a17ab0c202..dec3f1fb150c 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -48,16 +48,13 @@ static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip) * duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE */ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + int duty_ns, int period_ns, int enabled) { struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); u32 period_cycles, duty_cycles; unsigned long long c; u16 value; - if (period_ns > NSEC_PER_SEC) - return -ERANGE; - c = pc->clk_rate; c = c * period_ns; do_div(c, NSEC_PER_SEC); @@ -82,7 +79,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writew(value, pc->mmio_base + ECCTL2); - if (!pwm_is_enabled(pwm)) { + if (!enabled) { /* Update active registers if not running */ writel(duty_cycles, pc->mmio_base + CAP2); writel(period_cycles, pc->mmio_base + CAP1); @@ -96,7 +93,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writel(period_cycles, pc->mmio_base + CAP3); } - if (!pwm_is_enabled(pwm)) { + if (!enabled) { value = readw(pc->mmio_base + ECCTL2); /* Disable APWM mode to put APWM output Low */ value &= ~ECCTL2_APWM_MODE; @@ -168,20 +165,49 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) pm_runtime_put_sync(pc->chip.dev); } -static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { - if (pwm_is_enabled(pwm)) { - dev_warn(chip->dev, "Removing PWM device without disabling\n"); - pm_runtime_put_sync(chip->dev); + int err; + int enabled = pwm->state.enabled; + + if (state->polarity != pwm->state.polarity) { + + if (enabled) { + ecap_pwm_disable(chip, pwm); + enabled = false; + } + + err = ecap_pwm_set_polarity(chip, pwm, state->polarity); + if (err) + return err; } + + if (!state->enabled) { + if (enabled) + ecap_pwm_disable(chip, pwm); + return 0; + } + + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) { + if (state->period > NSEC_PER_SEC) + return -ERANGE; + + err = ecap_pwm_config(chip, pwm, state->duty_cycle, + state->period, enabled); + if (err) + return err; + } + + if (!enabled) + return ecap_pwm_enable(chip, pwm); + + return 0; } static const struct pwm_ops ecap_pwm_ops = { - .free = ecap_pwm_free, - .config = ecap_pwm_config, - .set_polarity = ecap_pwm_set_polarity, - .enable = ecap_pwm_enable, - .disable = ecap_pwm_disable, + .apply = ecap_pwm_apply, .owner = THIS_MODULE, }; @@ -224,8 +250,6 @@ static int ecap_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &ecap_pwm_ops; - pc->chip.of_xlate = of_pwm_xlate_with_flags; - pc->chip.of_pwm_n_cells = 3; pc->chip.npwm = 1; pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 90095a19bf2d..17909fa53211 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -447,8 +447,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &ehrpwm_pwm_ops; - pc->chip.of_xlate = of_pwm_xlate_with_flags; - pc->chip.of_pwm_n_cells = 3; pc->chip.npwm = NUM_PWM_CHANNEL; pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c index 46d903786366..af4e37d3e3a6 100644 --- a/drivers/pwm/pwm-visconti.c +++ b/drivers/pwm/pwm-visconti.c @@ -82,17 +82,14 @@ static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return -ERANGE; /* - * PWMC controls a divider that divides the input clk by a - * power of two between 1 and 8. As a smaller divider yields - * higher precision, pick the smallest possible one. + * PWMC controls a divider that divides the input clk by a power of two + * between 1 and 8. As a smaller divider yields higher precision, pick + * the smallest possible one. As period is at most 0xffff << 3, pwmc0 is + * in the intended range [0..3]. */ - if (period > 0xffff) { - pwmc0 = ilog2(period >> 16); - if (WARN_ON(pwmc0 > 3)) - return -EINVAL; - } else { - pwmc0 = 0; - } + pwmc0 = fls(period >> 16); + if (WARN_ON(pwmc0 > 3)) + return -EINVAL; period >>= pwmc0; duty_cycle >>= pwmc0; diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 52fe5d19473a..ea2aa151080a 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -207,8 +207,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev) chip->chip.dev = &pdev->dev; chip->chip.ops = &vt8500_pwm_ops; - chip->chip.of_xlate = of_pwm_xlate_with_flags; - chip->chip.of_pwm_n_cells = 3; chip->chip.npwm = VT8500_NR_PWMS; chip->clk = devm_clk_get(&pdev->dev, NULL); @@ -240,15 +238,13 @@ static int vt8500_pwm_probe(struct platform_device *pdev) static int vt8500_pwm_remove(struct platform_device *pdev) { - struct vt8500_chip *chip; + struct vt8500_chip *chip = platform_get_drvdata(pdev); - chip = platform_get_drvdata(pdev); - if (chip == NULL) - return -ENODEV; + pwmchip_remove(&chip->chip); clk_unprepare(chip->clk); - return pwmchip_remove(&chip->chip); + return 0; } static struct platform_driver vt8500_pwm_driver = { diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index e68fcedc999c..9a6eedc3994a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -26,6 +26,7 @@ config REMOTEPROC_CDEV config IMX_REMOTEPROC tristate "i.MX remoteproc support" depends on ARCH_MXC + depends on HAVE_ARM_SMCCC select MAILBOX help Say y here to support iMX's remote processors via the remote diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index d6338872c6db..d88f76f5305e 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -3,6 +3,7 @@ * Copyright (c) 2017 Pengutronix, Oleksij Rempel */ +#include #include #include #include @@ -50,6 +51,11 @@ #define IMX_RPROC_MEM_MAX 32 +#define IMX_SIP_RPROC 0xC2000005 +#define IMX_SIP_RPROC_START 0x00 +#define IMX_SIP_RPROC_STARTED 0x01 +#define IMX_SIP_RPROC_STOP 0x02 + /** * struct imx_rproc_mem - slim internal memory structure * @cpu_addr: MPU virtual address of the memory region @@ -74,6 +80,15 @@ struct imx_rproc_att { int flags; }; +/* Remote core start/stop method */ +enum imx_rproc_method { + IMX_RPROC_NONE, + /* Through syscon regmap */ + IMX_RPROC_MMIO, + /* Through ARM SMCCC */ + IMX_RPROC_SMC, +}; + struct imx_rproc_dcfg { u32 src_reg; u32 src_mask; @@ -81,6 +96,7 @@ struct imx_rproc_dcfg { u32 src_stop; const struct imx_rproc_att *att; size_t att_size; + enum imx_rproc_method method; }; struct imx_rproc { @@ -98,6 +114,36 @@ struct imx_rproc { void __iomem *rsc_table; }; +static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { + /* dev addr , sys addr , size , flags */ + /* ITCM */ + { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN }, + /* OCRAM_S */ + { 0x00180000, 0x00180000, 0x00009000, 0 }, + /* OCRAM */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00940000, 0x00940000, 0x00050000, 0 }, + /* QSPI Code - alias */ + { 0x08000000, 0x08000000, 0x08000000, 0 }, + /* DDR (Code) - alias */ + { 0x10000000, 0x40000000, 0x0FFE0000, 0 }, + /* DTCM */ + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN }, + /* OCRAM_S - alias */ + { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM */ + { 0x20200000, 0x00900000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20220000, 0x00920000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20240000, 0x00940000, 0x00040000, ATT_OWN }, + /* DDR (Data) */ + { 0x40000000, 0x40000000, 0x80000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { /* dev addr , sys addr , size , flags */ /* TCML - alias */ @@ -126,6 +172,20 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { { 0x40000000, 0x40000000, 0x80000000, 0 }, }; +static const struct imx_rproc_att imx_rproc_att_imx8ulp[] = { + {0x1FFC0000, 0x1FFC0000, 0xC0000, ATT_OWN}, + {0x21000000, 0x21000000, 0x10000, ATT_OWN}, + {0x80000000, 0x80000000, 0x60000000, 0} +}; + +static const struct imx_rproc_att imx_rproc_att_imx7ulp[] = { + {0x1FFD0000, 0x1FFD0000, 0x30000, ATT_OWN}, + {0x20000000, 0x20000000, 0x10000, ATT_OWN}, + {0x2F000000, 0x2F000000, 0x20000, ATT_OWN}, + {0x2F020000, 0x2F020000, 0x20000, ATT_OWN}, + {0x60000000, 0x60000000, 0x40000000, 0} +}; + static const struct imx_rproc_att imx_rproc_att_imx7d[] = { /* dev addr , sys addr , size , flags */ /* OCRAM_S (M4 Boot code) - alias */ @@ -176,6 +236,12 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_SMC, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -183,6 +249,19 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { .src_stop = IMX7D_M4_STOP, .att = imx_rproc_att_imx8mq, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { + .att = imx_rproc_att_imx8ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), + .method = IMX_RPROC_NONE, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { + .att = imx_rproc_att_imx7ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), + .method = IMX_RPROC_NONE, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { @@ -192,6 +271,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { .src_stop = IMX7D_M4_STOP, .att = imx_rproc_att_imx7d, .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), + .method = IMX_RPROC_MMIO, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { @@ -201,6 +281,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { .src_stop = IMX6SX_M4_STOP, .att = imx_rproc_att_imx6sx, .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), + .method = IMX_RPROC_MMIO, }; static int imx_rproc_start(struct rproc *rproc) @@ -208,12 +289,24 @@ static int imx_rproc_start(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct arm_smccc_res res; int ret; - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, dcfg->src_start); + switch (dcfg->method) { + case IMX_RPROC_MMIO: + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, + dcfg->src_start); + break; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); + ret = res.a0; + break; + default: + return -EOPNOTSUPP; + } + if (ret) - dev_err(dev, "Failed to enable M4!\n"); + dev_err(dev, "Failed to enable remote core!\n"); return ret; } @@ -223,12 +316,26 @@ static int imx_rproc_stop(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct arm_smccc_res res; int ret; - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, dcfg->src_stop); + switch (dcfg->method) { + case IMX_RPROC_MMIO: + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, + dcfg->src_stop); + break; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + ret = res.a0; + if (res.a1) + dev_info(dev, "Not in wfi, force stopped\n"); + break; + default: + return -EOPNOTSUPP; + } + if (ret) - dev_err(dev, "Failed to stop M4!\n"); + dev_err(dev, "Failed to stop remote core\n"); return ret; } @@ -560,12 +667,37 @@ static void imx_rproc_free_mbox(struct rproc *rproc) static int imx_rproc_detect_mode(struct imx_rproc *priv) { + struct regmap_config config = { .name = "imx-rproc" }; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + struct regmap *regmap; + struct arm_smccc_res res; int ret; u32 val; - ret = regmap_read(priv->regmap, dcfg->src_reg, &val); + switch (dcfg->method) { + case IMX_RPROC_NONE: + priv->rproc->state = RPROC_DETACHED; + return 0; + case IMX_RPROC_SMC: + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + priv->rproc->state = RPROC_DETACHED; + return 0; + default: + break; + } + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to find syscon\n"); + return PTR_ERR(regmap); + } + + priv->regmap = regmap; + regmap_attach_dev(dev, regmap, &config); + + ret = regmap_read(regmap, dcfg->src_reg, &val); if (ret) { dev_err(dev, "Failed to read src\n"); return ret; @@ -577,24 +709,44 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) return 0; } +static int imx_rproc_clk_enable(struct imx_rproc *priv) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; + int ret; + + /* Remote core is not under control of Linux */ + if (dcfg->method == IMX_RPROC_NONE) + return 0; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "Failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + /* + * clk for M4 block including memory. Should be + * enabled before .start for FW transfer. + */ + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + + return 0; +} + static int imx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct imx_rproc *priv; struct rproc *rproc; - struct regmap_config config = { .name = "imx-rproc" }; const struct imx_rproc_dcfg *dcfg; - struct regmap *regmap; int ret; - regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to find syscon\n"); - return PTR_ERR(regmap); - } - regmap_attach_dev(dev, regmap, &config); - /* set some other name then imx */ rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, NULL, sizeof(*priv)); @@ -609,7 +761,6 @@ static int imx_rproc_probe(struct platform_device *pdev) priv = rproc->priv; priv->rproc = rproc; - priv->regmap = regmap; priv->dcfg = dcfg; priv->dev = dev; @@ -635,25 +786,15 @@ static int imx_rproc_probe(struct platform_device *pdev) if (ret) goto err_put_mbox; - priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "Failed to get clock\n"); - ret = PTR_ERR(priv->clk); + ret = imx_rproc_clk_enable(priv); + if (ret) goto err_put_mbox; - } - - /* - * clk for M4 block including memory. Should be - * enabled before .start for FW transfer. - */ - ret = clk_prepare_enable(priv->clk); - if (ret) { - dev_err(&rproc->dev, "Failed to enable clock\n"); - goto err_put_mbox; - } INIT_WORK(&priv->rproc_work, imx_rproc_vq_work); + if (rproc->state != RPROC_DETACHED) + rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot"); + ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed\n"); @@ -688,10 +829,14 @@ static int imx_rproc_remove(struct platform_device *pdev) } static const struct of_device_id imx_rproc_of_match[] = { + { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp }, { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx }, { .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq }, { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq }, + { .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn }, + { .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn }, + { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, {}, }; MODULE_DEVICE_TABLE(of, imx_rproc_of_match); diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index e5778e476245..1777a01fa84e 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -887,6 +887,9 @@ static const struct of_device_id pru_rproc_match[] = { { .compatible = "ti,am3356-pru", .data = &pru_data }, { .compatible = "ti,am4376-pru", .data = &pru_data }, { .compatible = "ti,am5728-pru", .data = &pru_data }, + { .compatible = "ti,am642-pru", .data = &k3_pru_data }, + { .compatible = "ti,am642-rtu", .data = &k3_rtu_data }, + { .compatible = "ti,am642-tx-pru", .data = &k3_tx_pru_data }, { .compatible = "ti,k2g-pru", .data = &pru_data }, { .compatible = "ti,am654-pru", .data = &k3_pru_data }, { .compatible = "ti,am654-rtu", .data = &k3_rtu_data }, diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 9627a950928e..7e9244c748da 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -280,7 +280,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, return ret; } - q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit); + q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit); if (IS_ERR(q6v5->state)) { dev_err(&pdev->dev, "failed to acquire stop state\n"); return PTR_ERR(q6v5->state); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index b921fc26cd04..a79bee901e9b 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -689,6 +689,25 @@ static const struct adsp_data mpss_resource_init = { .ssctl_id = 0x12, }; +static const struct adsp_data sc8180x_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "modem.mdt", + .pas_id = 4, + .has_aggre2_clk = false, + .auto_boot = false, + .active_pd_names = (char*[]){ + "load_state", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x12, +}; + static const struct adsp_data slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", @@ -811,6 +830,9 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, + { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource}, + { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource}, + { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource}, { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init}, { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource}, diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 5f3455aa7e0e..f1cbc6b2edbb 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -624,8 +624,8 @@ static int wcnss_probe(struct platform_device *pdev) wcnss->stop_ack_irq = ret; if (wcnss->stop_ack_irq) { - wcnss->state = qcom_smem_state_get(&pdev->dev, "stop", - &wcnss->stop_bit); + wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop", + &wcnss->stop_bit); if (IS_ERR(wcnss->state)) { ret = PTR_ERR(wcnss->state); goto detach_pds; @@ -659,7 +659,6 @@ static int wcnss_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); - qcom_smem_state_put(wcnss->state); rproc_del(wcnss->rproc); qcom_remove_sysmon_subdev(wcnss->sysmon); diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index 0b8a84c04f76..4ad98b0b8caa 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -124,7 +124,7 @@ int rproc_char_device_add(struct rproc *rproc) void rproc_char_device_remove(struct rproc *rproc) { - __unregister_chrdev(MAJOR(rproc->dev.devt), rproc->index, 1, "remoteproc"); + cdev_del(&rproc->cdev); } void __init rproc_init_cdev(void) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 39cf44cb0803..7de5905d276a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -166,6 +166,7 @@ EXPORT_SYMBOL(rproc_va_to_pa); * @rproc: handle of a remote processor * @da: remoteproc device address to translate * @len: length of the memory region @da is pointing to + * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory * * Some remote processors will ask us to allocate them physically contiguous * memory regions (which we call "carveouts"), and map them to specific @@ -183,12 +184,12 @@ EXPORT_SYMBOL(rproc_va_to_pa); * translations on the internal remoteproc memory regions through a platform * implementation specific da_to_va ops, if present. * - * The function returns a valid kernel address on success or NULL on failure. - * * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, * but only on kernel direct mapped RAM memory. Instead, we're just using * here the output of the DMA API for the carveouts, which should be more * correct. + * + * Return: a valid kernel address on success or NULL on failure */ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) { @@ -509,7 +510,7 @@ static int copy_dma_range_map(struct device *to, struct device *from) * use RSC_DEVMEM resource entries to map their required @da to the physical * address of their base CMA region (ouch, hacky!). * - * Returns 0 on success, or an appropriate error code otherwise + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_vdev(struct rproc *rproc, void *ptr, int offset, int avail) @@ -644,7 +645,7 @@ void rproc_vdev_release(struct kref *ref) * support dynamically allocating this address using the generic * DMA API (but currently there isn't a use case for that). * - * Returns 0 on success, or an appropriate error code otherwise + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_trace(struct rproc *rproc, void *ptr, int offset, int avail) @@ -721,6 +722,8 @@ static int rproc_handle_trace(struct rproc *rproc, void *ptr, * tell us ranges of physical addresses the firmware is allowed to request, * and not allow firmwares to request access to physical addresses that * are outside those ranges. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_devmem(struct rproc *rproc, void *ptr, int offset, int avail) @@ -783,6 +786,8 @@ out: * * This function allocate specified memory entry @mem using * dma_alloc_coherent() as default allocator + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_alloc_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) @@ -889,6 +894,8 @@ dma_free: * * This function releases specified memory entry @mem allocated via * rproc_alloc_carveout() function by @rproc. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_release_carveout(struct rproc *rproc, struct rproc_mem_entry *mem) @@ -918,6 +925,8 @@ static int rproc_release_carveout(struct rproc *rproc, * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB * pressure is important; it may have a substantial impact on performance. + * + * Return: 0 on success, or an appropriate error code otherwise */ static int rproc_handle_carveout(struct rproc *rproc, void *ptr, int offset, int avail) @@ -1006,6 +1015,8 @@ EXPORT_SYMBOL(rproc_add_carveout); * * This function allocates a rproc_mem_entry struct and fill it with parameters * provided by client. + * + * Return: a valid pointer on success, or NULL on failure */ __printf(8, 9) struct rproc_mem_entry * @@ -1050,6 +1061,8 @@ EXPORT_SYMBOL(rproc_mem_entry_init); * * This function allocates a rproc_mem_entry struct and fill it with parameters * provided by client. + * + * Return: a valid pointer on success, or NULL on failure */ __printf(5, 6) struct rproc_mem_entry * @@ -1881,6 +1894,8 @@ static int __rproc_detach(struct rproc *rproc) * remoteproc functional again. * * This function can sleep, so it cannot be called from atomic context. + * + * Return: 0 on success or a negative value upon failure */ int rproc_trigger_recovery(struct rproc *rproc) { @@ -1965,7 +1980,7 @@ static void rproc_crash_handler_work(struct work_struct *work) * If the remote processor is already powered on, this function immediately * returns (successfully). * - * Returns 0 on success, and an appropriate error value otherwise. + * Return: 0 on success, and an appropriate error value otherwise */ int rproc_boot(struct rproc *rproc) { @@ -2100,6 +2115,8 @@ EXPORT_SYMBOL(rproc_shutdown); * no longer available. From there it should be possible to remove the * platform driver and even power cycle the application processor (if the HW * supports it) without needing to switch off the remote processor. + * + * Return: 0 on success, and an appropriate error value otherwise */ int rproc_detach(struct rproc *rproc) { @@ -2152,7 +2169,7 @@ EXPORT_SYMBOL(rproc_detach); * This function increments the remote processor's refcount, so always * use rproc_put() to decrement it back once rproc isn't needed anymore. * - * Returns the rproc handle on success, and NULL on failure. + * Return: rproc handle on success, and NULL on failure */ #ifdef CONFIG_OF struct rproc *rproc_get_by_phandle(phandle phandle) @@ -2302,8 +2319,6 @@ static int rproc_validate(struct rproc *rproc) * This is called by the platform-specific rproc implementation, whenever * a new remote processor device is probed. * - * Returns 0 on success and an appropriate error code otherwise. - * * Note: this function initiates an asynchronous firmware loading * context, which will look for virtio devices supported by the rproc's * firmware. @@ -2311,35 +2326,39 @@ static int rproc_validate(struct rproc *rproc) * If found, those virtio devices will be created and added, so as a result * of registering this remote processor, additional virtio drivers might be * probed. + * + * Return: 0 on success and an appropriate error code otherwise */ int rproc_add(struct rproc *rproc) { struct device *dev = &rproc->dev; int ret; - ret = device_add(dev); - if (ret < 0) - return ret; - ret = rproc_validate(rproc); if (ret < 0) return ret; - dev_info(dev, "%s is available\n", rproc->name); - - /* create debugfs entries */ - rproc_create_debug_dir(rproc); - /* add char device for this remoteproc */ ret = rproc_char_device_add(rproc); if (ret < 0) return ret; + ret = device_add(dev); + if (ret < 0) { + put_device(dev); + goto rproc_remove_cdev; + } + + dev_info(dev, "%s is available\n", rproc->name); + + /* create debugfs entries */ + rproc_create_debug_dir(rproc); + /* if rproc is marked always-on, request it to boot */ if (rproc->auto_boot) { ret = rproc_trigger_auto_boot(rproc); if (ret < 0) - return ret; + goto rproc_remove_dev; } /* expose to rproc_get_by_phandle users */ @@ -2348,6 +2367,13 @@ int rproc_add(struct rproc *rproc) mutex_unlock(&rproc_list_mutex); return 0; + +rproc_remove_dev: + rproc_delete_debug_dir(rproc); + device_del(dev); +rproc_remove_cdev: + rproc_char_device_remove(rproc); + return ret; } EXPORT_SYMBOL(rproc_add); @@ -2364,7 +2390,7 @@ static void devm_rproc_remove(void *rproc) * This function performs like rproc_add() but the registered rproc device will * automatically be removed on driver detach. * - * Returns: 0 on success, negative errno on failure + * Return: 0 on success, negative errno on failure */ int devm_rproc_add(struct device *dev, struct rproc *rproc) { @@ -2472,10 +2498,10 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops) * implementations should then call rproc_add() to complete * the registration of the remote processor. * - * On success the new rproc is returned, and on failure, NULL. - * * Note: _never_ directly deallocate @rproc, even if it was not registered * yet. Instead, when you need to unroll rproc_alloc(), use rproc_free(). + * + * Return: new rproc pointer on success, and NULL on failure */ struct rproc *rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, @@ -2588,7 +2614,7 @@ EXPORT_SYMBOL(rproc_put); * of the outstanding reference created by rproc_alloc. To decrement that * one last refcount, one still needs to call rproc_free(). * - * Returns 0 on success and -EINVAL if @rproc isn't valid. + * Return: 0 on success and -EINVAL if @rproc isn't valid */ int rproc_del(struct rproc *rproc) { @@ -2603,7 +2629,6 @@ int rproc_del(struct rproc *rproc) mutex_unlock(&rproc->lock); rproc_delete_debug_dir(rproc); - rproc_char_device_remove(rproc); /* the rproc is downref'ed as soon as it's removed from the klist */ mutex_lock(&rproc_list_mutex); @@ -2614,6 +2639,7 @@ int rproc_del(struct rproc *rproc) synchronize_rcu(); device_del(&rproc->dev); + rproc_char_device_remove(rproc); return 0; } @@ -2635,7 +2661,7 @@ static void devm_rproc_free(struct device *dev, void *res) * This function performs like rproc_alloc() but the acquired rproc device will * automatically be released on driver detach. * - * Returns: new rproc instance, or NULL on failure + * Return: new rproc instance, or NULL on failure */ struct rproc *devm_rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, @@ -2687,7 +2713,7 @@ EXPORT_SYMBOL(rproc_remove_subdev); * rproc_get_by_child() - acquire rproc handle of @dev's ancestor * @dev: child device to find ancestor of * - * Returns the ancestor rproc instance, or NULL if not found. + * Return: the ancestor rproc instance, or NULL if not found */ struct rproc *rproc_get_by_child(struct device *dev) { diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 11423588965a..469c52e62faf 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -31,6 +31,8 @@ * @fw: the ELF firmware image * * Make sure this fw image is sane (ie a correct ELF32/ELF64 file). + * + * Return: 0 on success and -EINVAL upon any failure */ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) { @@ -117,11 +119,11 @@ EXPORT_SYMBOL(rproc_elf_sanity_check); * @rproc: the remote processor handle * @fw: the ELF firmware image * - * This function returns the entry point address of the ELF - * image. - * * Note that the boot address is not a configurable property of all remote * processors. Some will always boot at a specific hard-coded address. + * + * Return: entry point address of the ELF image + * */ u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw) { @@ -152,6 +154,8 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr); * might be different: they might not have iommus, and would prefer to * directly allocate memory for every segment/resource. This is not yet * supported, though. + * + * Return: 0 on success and an appropriate error code otherwise */ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) { @@ -362,7 +366,7 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table); * This function finds the location of the loaded resource table. Don't * call this function if the table wasn't loaded yet - it's a bug if you do. * - * Returns the pointer to the resource table if it is found or NULL otherwise. + * Return: pointer to the resource table if it is found or NULL otherwise. * If the table wasn't loaded yet the result is unspecified. */ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 0cc617f76068..cf4d54e98e6a 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -45,7 +45,7 @@ static bool rproc_virtio_notify(struct virtqueue *vq) * when the remote processor signals that a specific virtqueue has pending * messages available. * - * Returns IRQ_NONE if no message was found in the @notifyid virtqueue, + * Return: IRQ_NONE if no message was found in the @notifyid virtqueue, * and otherwise returns IRQ_HANDLED. */ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) @@ -325,7 +325,7 @@ static void rproc_virtio_dev_release(struct device *dev) * This function registers a virtio device. This vdev's partent is * the rproc device. * - * Returns 0 on success or an appropriate error value otherwise. + * Return: 0 on success or an appropriate error value otherwise */ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) { @@ -432,6 +432,8 @@ out: * @data: must be null * * This function unregisters an existing virtio device. + * + * Return: 0 */ int rproc_remove_virtio_dev(struct device *dev, void *data) { diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 7353f9e7e7af..b643efcf995a 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -474,14 +474,12 @@ static int stm32_rproc_attach(struct rproc *rproc) static int stm32_rproc_detach(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; - int err, dummy_data, idx; + int err, idx; /* Inform the remote processor of the detach */ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH); if (idx >= 0 && ddata->mb[idx].chan) { - /* A dummy data is sent to allow to block on transmit */ - err = mbox_send_message(ddata->mb[idx].chan, - &dummy_data); + err = mbox_send_message(ddata->mb[idx].chan, "stop"); if (err < 0) dev_warn(&rproc->dev, "warning: remote FW detach without ack\n"); } @@ -493,15 +491,13 @@ static int stm32_rproc_detach(struct rproc *rproc) static int stm32_rproc_stop(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; - int err, dummy_data, idx; + int err, idx; /* request shutdown of the remote processor */ if (rproc->state != RPROC_OFFLINE) { idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); if (idx >= 0 && ddata->mb[idx].chan) { - /* a dummy data is sent to allow to block on transmit */ - err = mbox_send_message(ddata->mb[idx].chan, - &dummy_data); + err = mbox_send_message(ddata->mb[idx].chan, "detach"); if (err < 0) dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); } @@ -556,7 +552,7 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid) continue; if (!ddata->mb[i].chan) return; - err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid); + err = mbox_send_message(ddata->mb[i].chan, "kick"); if (err < 0) dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n", __func__, ddata->mb[i].name, err); @@ -580,7 +576,7 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc, continue; *pa = da - p_mem->dev_addr + p_mem->bus_addr; - dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); + dev_dbg(dev, "da %llx to pa %pap\n", da, pa); return 0; } diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 5cf8d030a1f0..71615210df3e 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -40,6 +40,8 @@ #define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000 /* Available from J7200 SoCs onwards */ #define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000 +/* Applicable to only AM64x SoCs */ +#define PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE 0x00008000 /* R5 TI-SCI Processor Control Flags */ #define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001 @@ -49,6 +51,8 @@ #define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002 #define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004 #define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100 +/* Applicable to only AM64x SoCs */ +#define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200 /** * struct k3_r5_mem - internal memory structure @@ -64,19 +68,29 @@ struct k3_r5_mem { size_t size; }; +/* + * All cluster mode values are not applicable on all SoCs. The following + * are the modes supported on various SoCs: + * Split mode : AM65x, J721E, J7200 and AM64x SoCs + * LockStep mode : AM65x, J721E and J7200 SoCs + * Single-CPU mode : AM64x SoCs only + */ enum cluster_mode { CLUSTER_MODE_SPLIT = 0, CLUSTER_MODE_LOCKSTEP, + CLUSTER_MODE_SINGLECPU, }; /** * struct k3_r5_soc_data - match data to handle SoC variations * @tcm_is_double: flag to denote the larger unified TCMs in certain modes * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC + * @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode */ struct k3_r5_soc_data { bool tcm_is_double; bool tcm_ecc_autoinit; + bool single_cpu_mode; }; /** @@ -369,6 +383,13 @@ static inline int k3_r5_core_run(struct k3_r5_core *core) * applicable cores to allow loading into the TCMs. The .prepare() ops is * invoked by remoteproc core before any firmware loading, and is followed * by the .start() ops after loading to actually let the R5 cores run. + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to + * execute code, but combines the TCMs from both cores. The resets for both + * cores need to be released to make this possible, as the TCMs are in general + * private to each core. Only Core0 needs to be unhalted for running the + * cluster in this mode. The function uses the same reset logic as LockStep + * mode for this (though the behavior is agnostic of the reset release order). */ static int k3_r5_rproc_prepare(struct rproc *rproc) { @@ -386,7 +407,9 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) return ret; mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS); - ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + /* Re-use LockStep-mode reset logic for Single-CPU mode */ + ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? k3_r5_lockstep_release(cluster) : k3_r5_split_release(core); if (ret) { dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n", @@ -427,6 +450,12 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) * cores. The cores themselves are only halted in the .stop() ops, and the * .unprepare() ops is invoked by the remoteproc core after the remoteproc is * stopped. + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) combines the TCMs from + * both cores. The access is made possible only with releasing the resets for + * both cores, but with only Core0 unhalted. This function re-uses the same + * reset assert logic as LockStep mode for this mode (though the behavior is + * agnostic of the reset assert order). */ static int k3_r5_rproc_unprepare(struct rproc *rproc) { @@ -436,7 +465,9 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) struct device *dev = kproc->dev; int ret; - ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + /* Re-use LockStep-mode reset logic for Single-CPU mode */ + ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core); if (ret) dev_err(dev, "unable to disable cores, ret = %d\n", ret); @@ -455,6 +486,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) * first followed by Core0. The Split-mode requires that Core0 to be maintained * always in a higher power state that Core1 (implying Core1 needs to be started * always only after Core0 is started). + * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute + * code, so only Core0 needs to be unhalted. The function uses the same logic + * flow as Split-mode for this. */ static int k3_r5_rproc_start(struct rproc *rproc) { @@ -539,6 +574,10 @@ put_mbox: * Core0 to be maintained always in a higher power state that Core1 (implying * Core1 needs to be stopped first before Core0). * + * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute + * code, so only Core0 needs to be halted. The function uses the same logic + * flow as Split-mode for this. + * * Note that the R5F halt operation in general is not effective when the R5F * core is running, but is needed to make sure the core won't run after * deasserting the reset the subsequent time. The asserting of reset can @@ -665,7 +704,9 @@ static const struct rproc_ops k3_r5_rproc_ops = { * * Each R5FSS has a cluster-level setting for configuring the processor * subsystem either in a safety/fault-tolerant LockStep mode or a performance - * oriented Split mode. Each R5F core has a number of settings to either + * oriented Split mode on most SoCs. A fewer SoCs support a non-safety mode + * as an alternate for LockStep mode that exercises only a single R5F core + * called Single-CPU mode. Each R5F core has a number of settings to either * enable/disable each of the TCMs, control which TCM appears at the R5F core's * address 0x0. These settings need to be configured before the resets for the * corresponding core are released. These settings are all protected and managed @@ -677,11 +718,13 @@ static const struct rproc_ops k3_r5_rproc_ops = { * the cores are halted before the .prepare() step. * * The function is called from k3_r5_cluster_rproc_init() and is invoked either - * once (in LockStep mode) or twice (in Split mode). Support for LockStep-mode - * is dictated by an eFUSE register bit, and the config settings retrieved from - * DT are adjusted accordingly as per the permitted cluster mode. All cluster - * level settings like Cluster mode and TEINIT (exception handling state - * dictating ARM or Thumb mode) can only be set and retrieved using Core0. + * once (in LockStep mode or Single-CPU modes) or twice (in Split mode). Support + * for LockStep-mode is dictated by an eFUSE register bit, and the config + * settings retrieved from DT are adjusted accordingly as per the permitted + * cluster mode. Another eFUSE register bit dictates if the R5F cluster only + * supports a Single-CPU mode. All cluster level settings like Cluster mode and + * TEINIT (exception handling state dictating ARM or Thumb mode) can only be set + * and retrieved using Core0. * * The function behavior is different based on the cluster mode. The R5F cores * are configured independently as per their individual settings in Split mode. @@ -700,10 +743,16 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) u32 set_cfg = 0, clr_cfg = 0; u64 boot_vec = 0; bool lockstep_en; + bool single_cpu; int ret; core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); - core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? core0 : kproc->core; + if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) { + core = core0; + } else { + core = kproc->core; + } ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); @@ -713,23 +762,48 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) dev_dbg(dev, "boot_vector = 0x%llx, cfg = 0x%x ctrl = 0x%x stat = 0x%x\n", boot_vec, cfg, ctrl, stat); + /* check if only Single-CPU mode is supported on applicable SoCs */ + if (cluster->soc_data->single_cpu_mode) { + single_cpu = + !!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY); + if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) { + dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n"); + cluster->mode = CLUSTER_MODE_SINGLECPU; + } + goto config; + } + + /* check conventional LockStep vs Split mode configuration */ lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED); if (!lockstep_en && cluster->mode == CLUSTER_MODE_LOCKSTEP) { dev_err(cluster->dev, "lockstep mode not permitted, force configuring for split-mode\n"); cluster->mode = CLUSTER_MODE_SPLIT; } +config: /* always enable ARM mode and set boot vector to 0 */ boot_vec = 0x0; if (core == core0) { clr_cfg = PROC_BOOT_CFG_FLAG_R5_TEINIT; - /* - * LockStep configuration bit is Read-only on Split-mode _only_ - * devices and system firmware will NACK any requests with the - * bit configured, so program it only on permitted devices - */ - if (lockstep_en) - clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; + if (cluster->soc_data->single_cpu_mode) { + /* + * Single-CPU configuration bit can only be configured + * on Core0 and system firmware will NACK any requests + * with the bit configured, so program it only on + * permitted cores + */ + if (cluster->mode == CLUSTER_MODE_SINGLECPU) + set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE; + } else { + /* + * LockStep configuration bit is Read-only on Split-mode + * _only_ devices and system firmware will NACK any + * requests with the bit configured, so program it only + * on permitted devices + */ + if (lockstep_en) + clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; + } } if (core->atcm_enable) @@ -894,12 +968,12 @@ static void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc) * cores are usable in Split-mode, but only the Core0 TCMs can be used in * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by * leveraging the Core1 TCMs as well in certain modes where they would have - * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by - * making a Core1 TCM visible immediately after the corresponding Core0 TCM. - * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the - * dts representation reflects this increased size on supported SoCs. The Core0 - * TCM sizes therefore have to be adjusted to only half the original size in - * Split mode. + * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs, Single-CPU mode on + * AM64x SoCs). This is done by making a Core1 TCM visible immediately after the + * corresponding Core0 TCM. The SoC memory map uses the larger 64 KB sizes for + * the Core0 TCMs, and the dts representation reflects this increased size on + * supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only + * half the original size in Split mode. */ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) { @@ -909,6 +983,7 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) struct k3_r5_core *core0; if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU || !cluster->soc_data->tcm_is_double) return; @@ -987,8 +1062,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) goto err_add; } - /* create only one rproc in lockstep mode */ - if (cluster->mode == CLUSTER_MODE_LOCKSTEP) + /* create only one rproc in lockstep mode or single-cpu mode */ + if (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) break; } @@ -1020,11 +1096,12 @@ static void k3_r5_cluster_rproc_exit(void *data) struct rproc *rproc; /* - * lockstep mode has only one rproc associated with first core, whereas - * split-mode has two rprocs associated with each core, and requires - * that core1 be powered down first + * lockstep mode and single-cpu modes have only one rproc associated + * with first core, whereas split-mode has two rprocs associated with + * each core, and requires that core1 be powered down first */ - core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? + core = (cluster->mode == CLUSTER_MODE_LOCKSTEP || + cluster->mode == CLUSTER_MODE_SINGLECPU) ? list_first_entry(&cluster->cores, struct k3_r5_core, elem) : list_last_entry(&cluster->cores, struct k3_r5_core, elem); @@ -1272,9 +1349,9 @@ static int k3_r5_core_of_init(struct platform_device *pdev) core->tsp = k3_r5_core_of_get_tsp(dev, core->ti_sci); if (IS_ERR(core->tsp)) { + ret = PTR_ERR(core->tsp); dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", ret); - ret = PTR_ERR(core->tsp); goto err; } @@ -1396,7 +1473,12 @@ static int k3_r5_probe(struct platform_device *pdev) return -ENOMEM; cluster->dev = dev; - cluster->mode = CLUSTER_MODE_LOCKSTEP; + /* + * default to most common efuse configurations - Split-mode on AM64x + * and LockStep-mode on all others + */ + cluster->mode = data->single_cpu_mode ? + CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP; cluster->soc_data = data; INIT_LIST_HEAD(&cluster->cores); @@ -1450,17 +1532,26 @@ static int k3_r5_probe(struct platform_device *pdev) static const struct k3_r5_soc_data am65_j721e_soc_data = { .tcm_is_double = false, .tcm_ecc_autoinit = false, + .single_cpu_mode = false, }; static const struct k3_r5_soc_data j7200_soc_data = { .tcm_is_double = true, .tcm_ecc_autoinit = true, + .single_cpu_mode = false, +}; + +static const struct k3_r5_soc_data am64_soc_data = { + .tcm_is_double = true, + .tcm_ecc_autoinit = true, + .single_cpu_mode = true, }; static const struct of_device_id k3_r5_of_match[] = { { .compatible = "ti,am654-r5fss", .data = &am65_j721e_soc_data, }, { .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, }, { .compatible = "ti,j7200-r5fss", .data = &j7200_soc_data, }, + { .compatible = "ti,am64-r5fss", .data = &am64_soc_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, k3_r5_of_match); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 29fb33c0e26d..328f70f633eb 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -43,8 +43,9 @@ config RESET_BCM6345 This enables the reset controller driver for BCM6345 SoCs. config RESET_BERLIN - bool "Berlin Reset Driver" if COMPILE_TEST - default ARCH_BERLIN + tristate "Berlin Reset Driver" + depends on ARCH_BERLIN || COMPILE_TEST + default m if ARCH_BERLIN help This enables the reset controller driver for Marvell Berlin SoCs. @@ -59,7 +60,8 @@ config RESET_BRCMSTB config RESET_BRCMSTB_RESCAL bool "Broadcom STB RESCAL reset controller" depends on HAS_IOMEM - default ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BRCMSTB || COMPILE_TEST + default ARCH_BRCMSTB help This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on BCM7216. @@ -82,6 +84,7 @@ config RESET_IMX7 config RESET_INTEL_GW bool "Intel Reset Controller Driver" + depends on X86 || COMPILE_TEST depends on OF && HAS_IOMEM select REGMAP_MMIO help @@ -111,6 +114,14 @@ config RESET_LPC18XX help This enables the reset controller driver for NXP LPC18xx/43xx SoCs. +config RESET_MCHP_SPARX5 + bool "Microchip Sparx5 reset driver" + depends on HAS_IOMEM || COMPILE_TEST + default y if SPARX5_SWITCH + select MFD_SYSCON + help + This driver supports switch core reset for the Microchip Sparx5 SoC. + config RESET_MESON tristate "Meson Reset Driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index ac3e612ad953..ea8b8d9ca565 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o obj-$(CONFIG_RESET_K210) += reset-k210.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o +obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o obj-$(CONFIG_RESET_NPCM) += reset-npcm.o diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 71c1c8264b2d..61e688882643 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -84,7 +84,7 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev) * without gaps. */ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev, - const struct of_phandle_args *reset_spec) + const struct of_phandle_args *reset_spec) { if (reset_spec->args[0] >= rcdev->nr_resets) return -EINVAL; @@ -744,9 +744,9 @@ void reset_control_bulk_release(int num_rstcs, } EXPORT_SYMBOL_GPL(reset_control_bulk_release); -static struct reset_control *__reset_control_get_internal( - struct reset_controller_dev *rcdev, - unsigned int index, bool shared, bool acquired) +static struct reset_control * +__reset_control_get_internal(struct reset_controller_dev *rcdev, + unsigned int index, bool shared, bool acquired) { struct reset_control *rstc; @@ -774,7 +774,10 @@ static struct reset_control *__reset_control_get_internal( if (!rstc) return ERR_PTR(-ENOMEM); - try_module_get(rcdev->owner); + if (!try_module_get(rcdev->owner)) { + kfree(rstc); + return ERR_PTR(-ENODEV); + } rstc->rcdev = rcdev; list_add(&rstc->list, &rcdev->reset_control_head); @@ -806,9 +809,9 @@ static void __reset_control_put_internal(struct reset_control *rstc) kref_put(&rstc->refcnt, __reset_control_release); } -struct reset_control *__of_reset_control_get(struct device_node *node, - const char *id, int index, bool shared, - bool optional, bool acquired) +struct reset_control * +__of_reset_control_get(struct device_node *node, const char *id, int index, + bool shared, bool optional, bool acquired) { struct reset_control *rstc; struct reset_controller_dev *r, *rcdev; @@ -1027,9 +1030,9 @@ static void devm_reset_control_release(struct device *dev, void *res) reset_control_put(*(struct reset_control **)res); } -struct reset_control *__devm_reset_control_get(struct device *dev, - const char *id, int index, bool shared, - bool optional, bool acquired) +struct reset_control * +__devm_reset_control_get(struct device *dev, const char *id, int index, + bool shared, bool optional, bool acquired) { struct reset_control **ptr, *rstc; diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c index 19926506d033..5ca145b64e63 100644 --- a/drivers/reset/hisilicon/hi6220_reset.c +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -3,7 +3,7 @@ * Hisilicon Hi6220 reset controller driver * * Copyright (c) 2016 Linaro Limited. - * Copyright (c) 2015-2016 Hisilicon Limited. + * Copyright (c) 2015-2016 HiSilicon Limited. * * Author: Feng Chen */ diff --git a/drivers/reset/reset-a10sr.c b/drivers/reset/reset-a10sr.c index 7eacc89382f8..99b3bc8382f3 100644 --- a/drivers/reset/reset-a10sr.c +++ b/drivers/reset/reset-a10sr.c @@ -118,6 +118,7 @@ static struct platform_driver a10sr_reset_driver = { .probe = a10sr_reset_probe, .driver = { .name = "altr_a10sr_reset", + .of_match_table = a10sr_reset_of_match, }, }; module_platform_driver(a10sr_reset_driver); diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c index 737e4e81f6b7..ac6c7ad1deda 100644 --- a/drivers/reset/reset-bcm6345.c +++ b/drivers/reset/reset-bcm6345.c @@ -86,7 +86,7 @@ static int bcm6345_reset_status(struct reset_controller_dev *rcdev, return !(__raw_readl(bcm6345_reset->base) & BIT(id)); } -static struct reset_control_ops bcm6345_reset_ops = { +static const struct reset_control_ops bcm6345_reset_ops = { .assert = bcm6345_reset_assert, .deassert = bcm6345_reset_deassert, .reset = bcm6345_reset_reset, diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c index 371197bbd055..2537ec05ecee 100644 --- a/drivers/reset/reset-berlin.c +++ b/drivers/reset/reset-berlin.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,7 +55,7 @@ static const struct reset_control_ops berlin_reset_ops = { static int berlin_reset_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec) { - unsigned offset, bit; + unsigned int offset, bit; offset = reset_spec->args[0]; bit = reset_spec->args[1]; @@ -93,6 +93,7 @@ static const struct of_device_id berlin_reset_dt_match[] = { { .compatible = "marvell,berlin2-reset" }, { }, }; +MODULE_DEVICE_TABLE(of, berlin_reset_dt_match); static struct platform_driver berlin_reset_driver = { .probe = berlin2_reset_probe, @@ -101,4 +102,9 @@ static struct platform_driver berlin_reset_driver = { .of_match_table = berlin_reset_dt_match, }, }; -builtin_platform_driver(berlin_reset_driver); +module_platform_driver(berlin_reset_driver); + +MODULE_AUTHOR("Antoine Tenart "); +MODULE_AUTHOR("Sebastian Hesselbarth "); +MODULE_DESCRIPTION("Synaptics Berlin reset controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-brcmstb.c b/drivers/reset/reset-brcmstb.c index f213264c8567..42c9d5241c53 100644 --- a/drivers/reset/reset-brcmstb.c +++ b/drivers/reset/reset-brcmstb.c @@ -111,6 +111,7 @@ static const struct of_device_id brcmstb_reset_of_match[] = { { .compatible = "brcm,brcmstb-reset" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, brcmstb_reset_of_match); static struct platform_driver brcmstb_reset_driver = { .probe = brcmstb_reset_probe, diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c index ac41d093de13..b936cfe85641 100644 --- a/drivers/reset/reset-lantiq.c +++ b/drivers/reset/reset-lantiq.c @@ -186,7 +186,7 @@ static int lantiq_rcu_reset_probe(struct platform_device *pdev) priv->rcdev.of_xlate = lantiq_rcu_reset_xlate; priv->rcdev.of_reset_n_cells = 2; - return reset_controller_register(&priv->rcdev); + return devm_reset_controller_register(&pdev->dev, &priv->rcdev); } static const struct of_device_id lantiq_rcu_reset_dt_ids[] = { diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c new file mode 100644 index 000000000000..f01e7db8e83b --- /dev/null +++ b/drivers/reset/reset-microchip-sparx5.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip Sparx5 Switch Reset driver + * + * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries. + * + * The Sparx5 Chip Register Model can be browsed at this location: + * https://github.com/microchip-ung/sparx-5_reginfo + */ +#include +#include +#include +#include +#include +#include + +#define PROTECT_REG 0x84 +#define PROTECT_BIT BIT(10) +#define SOFT_RESET_REG 0x00 +#define SOFT_RESET_BIT BIT(1) + +struct mchp_reset_context { + struct regmap *cpu_ctrl; + struct regmap *gcb_ctrl; + struct reset_controller_dev rcdev; +}; + +static struct regmap_config sparx5_reset_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int sparx5_switch_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mchp_reset_context *ctx = + container_of(rcdev, struct mchp_reset_context, rcdev); + u32 val; + + /* Make sure the core is PROTECTED from reset */ + regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, PROTECT_BIT); + + /* Start soft reset */ + regmap_write(ctx->gcb_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT); + + /* Wait for soft reset done */ + return regmap_read_poll_timeout(ctx->gcb_ctrl, SOFT_RESET_REG, val, + (val & SOFT_RESET_BIT) == 0, + 1, 100); +} + +static const struct reset_control_ops sparx5_reset_ops = { + .reset = sparx5_switch_reset, +}; + +static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name, + struct regmap **target) +{ + struct device_node *syscon_np; + struct regmap *regmap; + int err; + + syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0); + if (!syscon_np) + return -ENODEV; + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + if (IS_ERR(regmap)) { + err = PTR_ERR(regmap); + dev_err(&pdev->dev, "No '%s' map: %d\n", name, err); + return err; + } + *target = regmap; + return 0; +} + +static int mchp_sparx5_map_io(struct platform_device *pdev, int index, + struct regmap **target) +{ + struct resource *res; + struct regmap *map; + void __iomem *mem; + + mem = devm_platform_get_and_ioremap_resource(pdev, index, &res); + if (IS_ERR(mem)) { + dev_err(&pdev->dev, "Could not map resource %d\n", index); + return PTR_ERR(mem); + } + sparx5_reset_regmap_config.name = res->name; + map = devm_regmap_init_mmio(&pdev->dev, mem, &sparx5_reset_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + *target = map; + return 0; +} + +static int mchp_sparx5_reset_probe(struct platform_device *pdev) +{ + struct device_node *dn = pdev->dev.of_node; + struct mchp_reset_context *ctx; + int err; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + err = mchp_sparx5_map_syscon(pdev, "cpu-syscon", &ctx->cpu_ctrl); + if (err) + return err; + err = mchp_sparx5_map_io(pdev, 0, &ctx->gcb_ctrl); + if (err) + return err; + + ctx->rcdev.owner = THIS_MODULE; + ctx->rcdev.nr_resets = 1; + ctx->rcdev.ops = &sparx5_reset_ops; + ctx->rcdev.of_node = dn; + + return devm_reset_controller_register(&pdev->dev, &ctx->rcdev); +} + +static const struct of_device_id mchp_sparx5_reset_of_match[] = { + { + .compatible = "microchip,sparx5-switch-reset", + }, + { } +}; + +static struct platform_driver mchp_sparx5_reset_driver = { + .probe = mchp_sparx5_reset_probe, + .driver = { + .name = "sparx5-switch-reset", + .of_match_table = mchp_sparx5_reset_of_match, + }, +}; + +static int __init mchp_sparx5_reset_init(void) +{ + return platform_driver_register(&mchp_sparx5_reset_driver); +} + +postcore_initcall(mchp_sparx5_reset_init); + +MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver"); +MODULE_AUTHOR("Steen Hegelund "); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c index c4013165bdda..8209f922dc16 100644 --- a/drivers/reset/reset-oxnas.c +++ b/drivers/reset/reset-oxnas.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * drivers/reset/reset-oxnas.c + * Oxford Semiconductor Reset Controller driver * * Copyright (C) 2016 Neil Armstrong * Copyright (C) 2014 Ma Haijun diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index 218370faf37b..2b92775d58f0 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -58,8 +58,8 @@ struct ti_syscon_reset_data { unsigned int nr_controls; }; -#define to_ti_syscon_reset_data(rcdev) \ - container_of(rcdev, struct ti_syscon_reset_data, rcdev) +#define to_ti_syscon_reset_data(_rcdev) \ + container_of(_rcdev, struct ti_syscon_reset_data, rcdev) /** * ti_syscon_reset_assert() - assert device reset diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 279e535bf5d8..5f75783f9397 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -20,7 +20,7 @@ struct uniphier_reset_data { #define UNIPHIER_RESET_ACTIVE_LOW BIT(0) }; -#define UNIPHIER_RESET_ID_END (unsigned int)(-1) +#define UNIPHIER_RESET_ID_END ((unsigned int)(-1)) #define UNIPHIER_RESET_END \ { .id = UNIPHIER_RESET_ID_END } diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index ebd433fa09dd..daa425e74c96 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -83,8 +83,8 @@ static const struct zynqmp_reset_soc_data zynqmp_reset_data = { }; static const struct zynqmp_reset_soc_data versal_reset_data = { - .reset_id = 0, - .num_resets = VERSAL_NR_RESETS, + .reset_id = 0, + .num_resets = VERSAL_NR_RESETS, }; static const struct reset_control_ops zynqmp_reset_ops = { diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c index 99b63035fe72..b4b46e0f207e 100644 --- a/drivers/reset/sti/reset-syscfg.c +++ b/drivers/reset/sti/reset-syscfg.c @@ -153,7 +153,7 @@ static int syscfg_reset_controller_register(struct device *dev, if (!rc->channels) return -ENOMEM; - rc->rst.ops = &syscfg_reset_ops, + rc->rst.ops = &syscfg_reset_ops; rc->rst.of_node = dev->of_node; rc->rst.nr_resets = data->nr_channels; rc->active_low = data->active_low; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d8c13fded164..12153d5801ce 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT watchdog timer in the ST M41T60 and M41T80 RTC chips series. config RTC_DRV_BD70528 - tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC" - depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) + tristate "ROHM BD71815 and BD71828 PMIC RTC" + depends on MFD_ROHM_BD71828 help If you say Y here you will get support for the RTC - block on ROHM BD70528, BD71815 and BD71828 Power Management IC. + block on ROHM BD71815 and BD71828 Power Management IC. This driver can also be built as a module. If so, the module will be called rtc-bd70528. diff --git a/drivers/rtc/proc.c b/drivers/rtc/proc.c index 73344598fc1b..cbcdbb19d848 100644 --- a/drivers/rtc/proc.c +++ b/drivers/rtc/proc.c @@ -23,8 +23,8 @@ static bool is_rtc_hctosys(struct rtc_device *rtc) int size; char name[NAME_SIZE]; - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) + size = snprintf(name, NAME_SIZE, "rtc%d", rtc->id); + if (size >= NAME_SIZE) return false; return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 2216be429ab7..b7b5ea1a4e67 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -184,7 +184,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) return -EILSEQ; memset(alrm, 0, sizeof(*alrm)); - if (alarm != ALARM_DISABLED && offset != 0) { + if (alarm != ALARM_DISABLED) { rtc_time64_to_tm(offset + alarm, tm); dev_dbg(dev, "%s: %ptR\n", __func__, tm); diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index e6428b27b5d4..630ea5de6871 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Au1xxx counter0 (aka Time-Of-Year counter) RTC interface driver. * * Copyright (C) 2008 Manuel Lauss - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. */ /* All current Au1xxx SoCs have 2 counters fed by an external 32.768 kHz diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index 6454afca02a6..59b627fc1ecf 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -2,10 +2,9 @@ // // Copyright (C) 2018 ROHM Semiconductors // -// RTC driver for ROHM BD70528 PMIC +// RTC driver for ROHM BD71828 and BD71815 PMIC #include -#include #include #include #include @@ -39,11 +38,6 @@ struct bd70528_rtc_data { u8 year; } __packed; -struct bd70528_rtc_wake { - struct bd70528_rtc_day time; - u8 ctrl; -} __packed; - struct bd71828_rtc_alm { struct bd70528_rtc_data alm0; struct bd70528_rtc_data alm1; @@ -51,141 +45,14 @@ struct bd71828_rtc_alm { u8 alm1_mask; } __packed; -struct bd70528_rtc_alm { - struct bd70528_rtc_data data; - u8 alm_mask; - u8 alm_repeat; -} __packed; - struct bd70528_rtc { struct rohm_regmap_dev *parent; struct regmap *regmap; struct device *dev; u8 reg_time_start; u8 bd718xx_alm_block_start; - bool has_rtc_timers; }; -static int bd70528_set_wake(struct rohm_regmap_dev *bd70528, - int enable, int *old_state) -{ - int ret; - unsigned int ctrl_reg; - - ret = regmap_read(bd70528->regmap, BD70528_REG_WAKE_EN, &ctrl_reg); - if (ret) - return ret; - - if (old_state) { - if (ctrl_reg & BD70528_MASK_WAKE_EN) - *old_state |= BD70528_WAKE_STATE_BIT; - else - *old_state &= ~BD70528_WAKE_STATE_BIT; - - if (!enable == !(*old_state & BD70528_WAKE_STATE_BIT)) - return 0; - } - - if (enable) - ctrl_reg |= BD70528_MASK_WAKE_EN; - else - ctrl_reg &= ~BD70528_MASK_WAKE_EN; - - return regmap_write(bd70528->regmap, BD70528_REG_WAKE_EN, - ctrl_reg); -} - -static int bd70528_set_elapsed_tmr(struct rohm_regmap_dev *bd70528, - int enable, int *old_state) -{ - int ret; - unsigned int ctrl_reg; - - /* - * TBD - * What is the purpose of elapsed timer ? - * Is the timeout registers counting down, or is the disable - re-enable - * going to restart the elapsed-time counting? If counting is restarted - * the timeout should be decreased by the amount of time that has - * elapsed since starting the timer. Maybe we should store the monotonic - * clock value when timer is started so that if RTC is set while timer - * is armed we could do the compensation. This is a hack if RTC/system - * clk are drifting. OTOH, RTC controlled via I2C is in any case - * inaccurate... - */ - ret = regmap_read(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN, - &ctrl_reg); - if (ret) - return ret; - - if (old_state) { - if (ctrl_reg & BD70528_MASK_ELAPSED_TIMER_EN) - *old_state |= BD70528_ELAPSED_STATE_BIT; - else - *old_state &= ~BD70528_ELAPSED_STATE_BIT; - - if ((!enable) == (!(*old_state & BD70528_ELAPSED_STATE_BIT))) - return 0; - } - - if (enable) - ctrl_reg |= BD70528_MASK_ELAPSED_TIMER_EN; - else - ctrl_reg &= ~BD70528_MASK_ELAPSED_TIMER_EN; - - return regmap_write(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN, - ctrl_reg); -} - -static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, - int *old_state) -{ - int ret; - - ret = bd70528_wdt_set(r->parent, new_state & BD70528_WDT_STATE_BIT, - old_state); - if (ret) { - dev_err(r->dev, - "Failed to disable WDG for RTC setting (%d)\n", ret); - return ret; - } - ret = bd70528_set_elapsed_tmr(r->parent, - new_state & BD70528_ELAPSED_STATE_BIT, - old_state); - if (ret) { - dev_err(r->dev, - "Failed to disable 'elapsed timer' for RTC setting\n"); - return ret; - } - ret = bd70528_set_wake(r->parent, new_state & BD70528_WAKE_STATE_BIT, - old_state); - if (ret) { - dev_err(r->dev, - "Failed to disable 'wake timer' for RTC setting\n"); - return ret; - } - - return ret; -} - -static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r, - int old_state) -{ - if (!r->has_rtc_timers) - return 0; - - return bd70528_set_rtc_based_timers(r, old_state, NULL); -} - -static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r, - int *old_state) -{ - if (!r->has_rtc_timers) - return 0; - - return bd70528_set_rtc_based_timers(r, 0, old_state); -} - static inline void tmday2rtc(struct rtc_time *t, struct bd70528_rtc_day *d) { d->sec &= ~BD70528_MASK_RTC_SEC; @@ -267,52 +134,6 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a) } -static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) -{ - struct bd70528_rtc_wake wake; - struct bd70528_rtc_alm alm; - int ret; - struct bd70528_rtc *r = dev_get_drvdata(dev); - - ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, &wake, - sizeof(wake)); - if (ret) { - dev_err(dev, "Failed to read wake regs\n"); - return ret; - } - - ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm, - sizeof(alm)); - if (ret) { - dev_err(dev, "Failed to read alarm regs\n"); - return ret; - } - - tm2rtc(&a->time, &alm.data); - tmday2rtc(&a->time, &wake.time); - - if (a->enabled) { - alm.alm_mask &= ~BD70528_MASK_ALM_EN; - wake.ctrl |= BD70528_MASK_WAKE_EN; - } else { - alm.alm_mask |= BD70528_MASK_ALM_EN; - wake.ctrl &= ~BD70528_MASK_WAKE_EN; - } - - ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, &wake, - sizeof(wake)); - if (ret) { - dev_err(dev, "Failed to set wake time\n"); - return ret; - } - ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, &alm, - sizeof(alm)); - if (ret) - dev_err(dev, "Failed to set alarm time\n"); - - return ret; -} - static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a) { int ret; @@ -336,75 +157,25 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a) return 0; } -static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a) +static int bd71828_set_time(struct device *dev, struct rtc_time *t) { - struct bd70528_rtc_alm alm; int ret; - struct bd70528_rtc *r = dev_get_drvdata(dev); - - ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm, - sizeof(alm)); - if (ret) { - dev_err(dev, "Failed to read alarm regs\n"); - return ret; - } - - rtc2tm(&alm.data, &a->time); - a->time.tm_mday = -1; - a->time.tm_mon = -1; - a->time.tm_year = -1; - a->enabled = !(alm.alm_mask & BD70528_MASK_ALM_EN); - a->pending = 0; - - return 0; -} - -static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) -{ - int ret, tmpret, old_states; struct bd70528_rtc_data rtc_data; struct bd70528_rtc *r = dev_get_drvdata(dev); - ret = bd70528_disable_rtc_based_timers(r, &old_states); - if (ret) - return ret; - - tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data, - sizeof(rtc_data)); - if (tmpret) { + ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data, + sizeof(rtc_data)); + if (ret) { dev_err(dev, "Failed to read RTC time registers\n"); - goto renable_out; + return ret; } tm2rtc(t, &rtc_data); - tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data, - sizeof(rtc_data)); - if (tmpret) { + ret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data, + sizeof(rtc_data)); + if (ret) dev_err(dev, "Failed to set RTC time\n"); - goto renable_out; - } -renable_out: - ret = bd70528_re_enable_rtc_based_timers(r, old_states); - if (tmpret) - ret = tmpret; - - return ret; -} - -static int bd71828_set_time(struct device *dev, struct rtc_time *t) -{ - return bd70528_set_time_locked(dev, t); -} - -static int bd70528_set_time(struct device *dev, struct rtc_time *t) -{ - int ret; - struct bd70528_rtc *r = dev_get_drvdata(dev); - - bd70528_wdt_lock(r->parent); - ret = bd70528_set_time_locked(dev, t); - bd70528_wdt_unlock(r->parent); return ret; } @@ -427,31 +198,6 @@ static int bd70528_get_time(struct device *dev, struct rtc_time *t) return 0; } -static int bd70528_alm_enable(struct device *dev, unsigned int enabled) -{ - int ret; - unsigned int enableval = BD70528_MASK_ALM_EN; - struct bd70528_rtc *r = dev_get_drvdata(dev); - - if (enabled) - enableval = 0; - - bd70528_wdt_lock(r->parent); - ret = bd70528_set_wake(r->parent, enabled, NULL); - if (ret) { - dev_err(dev, "Failed to change wake state\n"); - goto out_unlock; - } - ret = regmap_update_bits(r->regmap, BD70528_REG_RTC_ALM_MASK, - BD70528_MASK_ALM_EN, enableval); - if (ret) - dev_err(dev, "Failed to change alarm state\n"); - -out_unlock: - bd70528_wdt_unlock(r->parent); - return ret; -} - static int bd71828_alm_enable(struct device *dev, unsigned int enabled) { int ret; @@ -470,14 +216,6 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled) return ret; } -static const struct rtc_class_ops bd70528_rtc_ops = { - .read_time = bd70528_get_time, - .set_time = bd70528_set_time, - .read_alarm = bd70528_read_alarm, - .set_alarm = bd70528_set_alarm, - .alarm_irq_enable = bd70528_alm_enable, -}; - static const struct rtc_class_ops bd71828_rtc_ops = { .read_time = bd70528_get_time, .set_time = bd71828_set_time, @@ -503,7 +241,6 @@ static int bd70528_probe(struct platform_device *pdev) struct rtc_device *rtc; int irq; unsigned int hr; - bool enable_main_irq = false; u8 hour_reg; enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; @@ -518,21 +255,9 @@ static int bd70528_probe(struct platform_device *pdev) } bd_rtc->dev = &pdev->dev; + rtc_ops = &bd71828_rtc_ops; switch (chip) { - case ROHM_CHIP_TYPE_BD70528: - bd_rtc->parent = dev_get_drvdata(pdev->dev.parent); - if (!bd_rtc->parent) { - dev_err(&pdev->dev, "No MFD data\n"); - return -EINVAL; - } - irq_name = "bd70528-rtc-alm"; - bd_rtc->has_rtc_timers = true; - bd_rtc->reg_time_start = BD70528_REG_RTC_START; - hour_reg = BD70528_REG_RTC_HOUR; - enable_main_irq = true; - rtc_ops = &bd70528_rtc_ops; - break; case ROHM_CHIP_TYPE_BD71815: irq_name = "bd71815-rtc-alm-0"; bd_rtc->reg_time_start = BD71815_REG_RTC_START; @@ -549,14 +274,12 @@ static int bd70528_probe(struct platform_device *pdev) */ bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START; hour_reg = BD71815_REG_HOUR; - rtc_ops = &bd71828_rtc_ops; break; case ROHM_CHIP_TYPE_BD71828: irq_name = "bd71828-rtc-alm-0"; bd_rtc->reg_time_start = BD71828_REG_RTC_START; bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START; hour_reg = BD71828_REG_RTC_HOUR; - rtc_ops = &bd71828_rtc_ops; break; default: dev_err(&pdev->dev, "Unknown chip\n"); @@ -611,27 +334,10 @@ static int bd70528_probe(struct platform_device *pdev) if (ret) return ret; - /* - * BD70528 irq controller is not touching the main mask register. - * So enable the RTC block interrupts at main level. We can just - * leave them enabled as irq-controller should disable irqs - * from sub-registers when IRQ is disabled or freed. - */ - if (enable_main_irq) { - ret = regmap_update_bits(bd_rtc->regmap, - BD70528_REG_INT_MAIN_MASK, - BD70528_INT_RTC_MASK, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to enable RTC interrupts\n"); - return ret; - } - } - return devm_rtc_register_device(rtc); } static const struct platform_device_id bd718x7_rtc_id[] = { - { "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 }, { "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 }, { "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 }, { }, @@ -649,6 +355,6 @@ static struct platform_driver bd70528_rtc = { module_platform_driver(bd70528_rtc); MODULE_AUTHOR("Matti Vaittinen "); -MODULE_DESCRIPTION("ROHM BD70528 and BD71828 PMIC RTC driver"); +MODULE_DESCRIPTION("ROHM BD71828 and BD71815 PMIC RTC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:bd70528-rtc"); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index fab79921a712..8db5a631bca8 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C * @@ -6,11 +7,7 @@ * * Copyright (C) 2014 Rose Technology * Copyright (C) 2006-2007 Freescale Semiconductor - * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * Copyright (c) 2005 MontaVista Software, Inc. */ /* * It would be more efficient to use i2c msgs/i2c_transfer directly but, as diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index edb64debd173..138c5e0046c8 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -280,7 +280,6 @@ static struct platform_driver efi_rtc_driver = { module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); -MODULE_ALIAS("platform:rtc-efi"); MODULE_AUTHOR("dann frazier "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("EFI RTC driver"); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index c1806f4d68e7..4b712e5ab08a 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -811,6 +812,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxdi); + device_init_wakeup(&pdev->dev, true); + dev_pm_set_wake_irq(&pdev->dev, norm_irq); + imxdi->rtc->ops = &dryice_rtc_ops; imxdi->rtc->range_max = U32_MAX; diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 89128fc29ccc..f736f8c22e96 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -544,10 +544,22 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) { struct i2c_client *client = m41t80->client; struct device_node *node = client->dev.of_node; + struct device_node *fixed_clock; struct clk *clk; struct clk_init_data init; int ret; + fixed_clock = of_get_child_by_name(node, "clock"); + if (fixed_clock) { + /* + * skip registering square wave clock when a fixed + * clock has been registered. The fixed clock is + * registered automatically when being referenced. + */ + of_node_put(fixed_clock); + return 0; + } + /* First disable the clock */ ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (ret < 0) @@ -599,10 +611,8 @@ static unsigned long wdt_is_open; static int boot_flag; /** - * wdt_ping: - * - * Reload counter one with the watchdog timeout. We don't bother reloading - * the cascade counter. + * wdt_ping - Reload counter one with the watchdog timeout. + * We don't bother reloading the cascade counter. */ static void wdt_ping(void) { @@ -638,9 +648,7 @@ static void wdt_ping(void) } /** - * wdt_disable: - * - * disables watchdog. + * wdt_disable - disables watchdog. */ static void wdt_disable(void) { @@ -677,7 +685,7 @@ static void wdt_disable(void) } /** - * wdt_write: + * wdt_write - write to watchdog. * @file: file handle to the watchdog * @buf: buffer to write (unused as data does not matter here * @count: count of bytes @@ -703,7 +711,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf, } /** - * wdt_ioctl: + * wdt_ioctl - ioctl handler to set watchdog. * @file: file handle to the device * @cmd: watchdog command * @arg: argument pointer @@ -778,7 +786,7 @@ static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd, } /** - * wdt_open: + * wdt_open - open a watchdog. * @inode: inode of device * @file: file handle to device * @@ -802,7 +810,7 @@ static int wdt_open(struct inode *inode, struct file *file) } /** - * wdt_close: + * wdt_release - release a watchdog. * @inode: inode to board * @file: file handle to board * @@ -815,7 +823,7 @@ static int wdt_release(struct inode *inode, struct file *file) } /** - * notify_sys: + * wdt_notify_sys - notify to watchdog. * @this: our notifier block * @code: the event being reported * @unused: unused diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index ab60f13fa3ef..4beadfa41644 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -1,14 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc class driver for the Maxim MAX6900 chip * + * Copyright (c) 2007 MontaVista, Software, Inc. + * * Author: Dale Farnsworth * * based on previously existing rtc class drivers - * - * 2007 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. */ #include diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index d51cc12114cb..eae7cb9faf1e 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -717,8 +717,8 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) add_rtc_irq: ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT | - IRQF_SHARED, 0, info->drv_data->rtc_irq_chip, + IRQF_ONESHOT | IRQF_SHARED, + 0, info->drv_data->rtc_irq_chip, &info->rtc_irq_data); if (ret < 0) { dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret); diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index a577a74aaf75..5e0383401629 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -372,6 +372,7 @@ static const struct of_device_id mxc_ids[] = { { .compatible = "fsl,imx53-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, mxc_ids); static struct platform_driver mxc_rtc_driver = { .driver = { diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 4bcfb88674d3..67571f7f0bbc 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-palmas.c -- Palmas Real Time Clock driver. @@ -7,20 +8,6 @@ * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * 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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index d13c20a2adf7..56c58b055dff 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -10,7 +10,7 @@ * * based on the other drivers in this same directory. * - * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf + * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf */ #include @@ -94,10 +94,20 @@ #define PCF2127_WD_VAL_MAX 255 #define PCF2127_WD_VAL_DEFAULT 60 +/* Mask for currently enabled interrupts */ +#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1) +#define PCF2127_CTRL2_IRQ_MASK ( \ + PCF2127_BIT_CTRL2_AF | \ + PCF2127_BIT_CTRL2_WDTF | \ + PCF2127_BIT_CTRL2_TSF2) + struct pcf2127 { struct rtc_device *rtc; struct watchdog_device wdd; struct regmap *regmap; + time64_t ts; + bool ts_valid; + bool irq_enabled; }; /* @@ -434,23 +444,96 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return pcf2127_rtc_alarm_irq_enable(dev, alrm->enabled); } +/* + * This function reads ctrl2 register, caller is responsible for calling + * pcf2127_wdt_active_ping() + */ +static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + struct rtc_time tm; + int ret; + unsigned char data[25]; + + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, + sizeof(data)); + if (ret) { + dev_err(dev, "%s: read error ret=%d\n", __func__, ret); + return ret; + } + + dev_dbg(dev, + "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", + __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], + data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], + data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], + data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], + data[PCF2127_REG_TS_YR]); + + tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); + tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); + tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); + tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); + /* TS_MO register (month) value range: 1-12 */ + tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; + tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); + if (tm.tm_year < 70) + tm.tm_year += 100; /* assume we are in 1970...2069 */ + + ret = rtc_valid_tm(&tm); + if (ret) { + dev_err(dev, "Invalid timestamp. ret=%d\n", ret); + return ret; + } + + *ts = rtc_tm_to_time64(&tm); + return 0; +}; + +static void pcf2127_rtc_ts_snapshot(struct device *dev) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + /* Let userspace read the first timestamp */ + if (pcf2127->ts_valid) + return; + + ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts); + if (!ret) + pcf2127->ts_valid = true; +} + static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned int ctrl2 = 0; + unsigned int ctrl1, ctrl2; int ret = 0; + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); + if (ret) + return IRQ_NONE; + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); if (ret) return IRQ_NONE; - if (!(ctrl2 & PCF2127_BIT_CTRL2_AF)) + if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) return IRQ_NONE; - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, - ctrl2 & ~(PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_WDTF)); + if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) + pcf2127_rtc_ts_snapshot(dev); - rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); + if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, + ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); + + if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + + if (ctrl2 & PCF2127_BIT_CTRL2_AF) + rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); pcf2127_wdt_active_ping(&pcf2127->wdd); @@ -475,23 +558,27 @@ static ssize_t timestamp0_store(struct device *dev, struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); int ret; - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, - PCF2127_BIT_CTRL1_TSF1, 0); - if (ret) { - dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); - return ret; - } + if (pcf2127->irq_enabled) { + pcf2127->ts_valid = false; + } else { + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_TSF1, 0); + if (ret) { + dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); + return ret; + } - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSF2, 0); - if (ret) { - dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); - return ret; - } + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, + PCF2127_BIT_CTRL2_TSF2, 0); + if (ret) { + dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); + return ret; + } - ret = pcf2127_wdt_active_ping(&pcf2127->wdd); - if (ret) - return ret; + ret = pcf2127_wdt_active_ping(&pcf2127->wdd); + if (ret) + return ret; + } return count; }; @@ -500,50 +587,36 @@ static ssize_t timestamp0_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); - struct rtc_time tm; + unsigned int ctrl1, ctrl2; int ret; - unsigned char data[25]; + time64_t ts; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, - sizeof(data)); - if (ret) { - dev_err(dev, "%s: read error ret=%d\n", __func__, ret); - return ret; + if (pcf2127->irq_enabled) { + if (!pcf2127->ts_valid) + return 0; + ts = pcf2127->ts; + } else { + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); + if (ret) + return 0; + + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); + if (ret) + return 0; + + if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) && + !(ctrl2 & PCF2127_BIT_CTRL2_TSF2)) + return 0; + + ret = pcf2127_rtc_ts_read(dev->parent, &ts); + if (ret) + return 0; + + ret = pcf2127_wdt_active_ping(&pcf2127->wdd); + if (ret) + return ret; } - - dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, " - "ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", - __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], - data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], - data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], - data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], - data[PCF2127_REG_TS_YR]); - - ret = pcf2127_wdt_active_ping(&pcf2127->wdd); - if (ret) - return ret; - - if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) && - !(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2)) - return 0; - - tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); - tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); - tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); - tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); - /* TS_MO register (month) value range: 1-12 */ - tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; - tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); - if (tm.tm_year < 70) - tm.tm_year += 100; /* assume we are in 1970...2069 */ - - ret = rtc_valid_tm(&tm); - if (ret) - return ret; - - return sprintf(buf, "%llu\n", - (unsigned long long)rtc_tm_to_time64(&tm)); + return sprintf(buf, "%llu\n", (unsigned long long)ts); }; static DEVICE_ATTR_RW(timestamp0); @@ -594,6 +667,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, dev_err(dev, "failed to request alarm irq\n"); return ret; } + pcf2127->irq_enabled = true; } if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) { diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 82becae14229..14da4ab30104 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -21,10 +21,10 @@ /* * Information for this driver was pulled from the following datasheets. * - * https://www.nxp.com/documents/data_sheet/PCF85063A.pdf - * https://www.nxp.com/documents/data_sheet/PCF85063TP.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF85063A.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF85063TP.pdf * - * PCF85063A -- Rev. 6 — 18 November 2015 + * PCF85063A -- Rev. 7 — 30 March 2018 * PCF85063TP -- Rev. 4 — 6 May 2015 * * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 740e2136ca98..8b6fb20774bf 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -10,41 +10,41 @@ #include #include -#define REG_CONTROL1 0x00 -#define REG_CONTROL1_CAP_SEL BIT(7) -#define REG_CONTROL1_STOP BIT(5) -#define REG_CONTROL1_AIE BIT(1) +#define PCF8523_REG_CONTROL1 0x00 +#define PCF8523_CONTROL1_CAP_SEL BIT(7) +#define PCF8523_CONTROL1_STOP BIT(5) +#define PCF8523_CONTROL1_AIE BIT(1) -#define REG_CONTROL2 0x01 -#define REG_CONTROL2_AF BIT(3) +#define PCF8523_REG_CONTROL2 0x01 +#define PCF8523_CONTROL2_AF BIT(3) -#define REG_CONTROL3 0x02 -#define REG_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */ -#define REG_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */ -#define REG_CONTROL3_PM_DSM BIT(5) /* direct switching mode */ -#define REG_CONTROL3_PM_MASK 0xe0 -#define REG_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ +#define PCF8523_REG_CONTROL3 0x02 +#define PCF8523_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */ +#define PCF8523_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */ +#define PCF8523_CONTROL3_PM_DSM BIT(5) /* direct switching mode */ +#define PCF8523_CONTROL3_PM_MASK 0xe0 +#define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ -#define REG_SECONDS 0x03 -#define REG_SECONDS_OS BIT(7) +#define PCF8523_REG_SECONDS 0x03 +#define PCF8523_SECONDS_OS BIT(7) -#define REG_MINUTES 0x04 -#define REG_HOURS 0x05 -#define REG_DAYS 0x06 -#define REG_WEEKDAYS 0x07 -#define REG_MONTHS 0x08 -#define REG_YEARS 0x09 +#define PCF8523_REG_MINUTES 0x04 +#define PCF8523_REG_HOURS 0x05 +#define PCF8523_REG_DAYS 0x06 +#define PCF8523_REG_WEEKDAYS 0x07 +#define PCF8523_REG_MONTHS 0x08 +#define PCF8523_REG_YEARS 0x09 -#define REG_MINUTE_ALARM 0x0a -#define REG_HOUR_ALARM 0x0b -#define REG_DAY_ALARM 0x0c -#define REG_WEEKDAY_ALARM 0x0d +#define PCF8523_REG_MINUTE_ALARM 0x0a +#define PCF8523_REG_HOUR_ALARM 0x0b +#define PCF8523_REG_DAY_ALARM 0x0c +#define PCF8523_REG_WEEKDAY_ALARM 0x0d #define ALARM_DIS BIT(7) -#define REG_OFFSET 0x0e -#define REG_OFFSET_MODE BIT(7) +#define PCF8523_REG_OFFSET 0x0e +#define PCF8523_OFFSET_MODE BIT(7) -#define REG_TMR_CLKOUT_CTRL 0x0f +#define PCF8523_TMR_CLKOUT_CTRL 0x0f struct pcf8523 { struct rtc_device *rtc; @@ -99,11 +99,11 @@ static int pcf8523_voltage_low(struct i2c_client *client) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL3, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value); if (err < 0) return err; - return !!(value & REG_CONTROL3_BLF); + return !!(value & PCF8523_CONTROL3_BLF); } static int pcf8523_load_capacitance(struct i2c_client *client) @@ -112,7 +112,7 @@ static int pcf8523_load_capacitance(struct i2c_client *client) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL1, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; @@ -126,14 +126,14 @@ static int pcf8523_load_capacitance(struct i2c_client *client) load); fallthrough; case 12500: - value |= REG_CONTROL1_CAP_SEL; + value |= PCF8523_CONTROL1_CAP_SEL; break; case 7000: - value &= ~REG_CONTROL1_CAP_SEL; + value &= ~PCF8523_CONTROL1_CAP_SEL; break; } - err = pcf8523_write(client, REG_CONTROL1, value); + err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); return err; } @@ -143,13 +143,13 @@ static int pcf8523_set_pm(struct i2c_client *client, u8 pm) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL3, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value); if (err < 0) return err; - value = (value & ~REG_CONTROL3_PM_MASK) | pm; + value = (value & ~PCF8523_CONTROL3_PM_MASK) | pm; - err = pcf8523_write(client, REG_CONTROL3, value); + err = pcf8523_write(client, PCF8523_REG_CONTROL3, value); if (err < 0) return err; @@ -162,13 +162,13 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id) u8 value; int err; - err = pcf8523_read(pcf8523->client, REG_CONTROL2, &value); + err = pcf8523_read(pcf8523->client, PCF8523_REG_CONTROL2, &value); if (err < 0) return IRQ_HANDLED; - if (value & REG_CONTROL2_AF) { - value &= ~REG_CONTROL2_AF; - pcf8523_write(pcf8523->client, REG_CONTROL2, value); + if (value & PCF8523_CONTROL2_AF) { + value &= ~PCF8523_CONTROL2_AF; + pcf8523_write(pcf8523->client, PCF8523_REG_CONTROL2, value); rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF); return IRQ_HANDLED; @@ -182,13 +182,13 @@ static int pcf8523_stop_rtc(struct i2c_client *client) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL1, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; - value |= REG_CONTROL1_STOP; + value |= PCF8523_CONTROL1_STOP; - err = pcf8523_write(client, REG_CONTROL1, value); + err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); if (err < 0) return err; @@ -200,13 +200,13 @@ static int pcf8523_start_rtc(struct i2c_client *client) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL1, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; - value &= ~REG_CONTROL1_STOP; + value &= ~PCF8523_CONTROL1_STOP; - err = pcf8523_write(client, REG_CONTROL1, value); + err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); if (err < 0) return err; @@ -216,7 +216,7 @@ static int pcf8523_start_rtc(struct i2c_client *client) static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); - u8 start = REG_SECONDS, regs[7]; + u8 start = PCF8523_REG_SECONDS, regs[7]; struct i2c_msg msgs[2]; int err; @@ -242,7 +242,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) if (err < 0) return err; - if (regs[0] & REG_SECONDS_OS) + if (regs[0] & PCF8523_SECONDS_OS) return -EINVAL; tm->tm_sec = bcd2bin(regs[0] & 0x7f); @@ -267,8 +267,8 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) if (err < 0) return err; - regs[0] = REG_SECONDS; - /* This will purposely overwrite REG_SECONDS_OS */ + regs[0] = PCF8523_REG_SECONDS; + /* This will purposely overwrite PCF8523_SECONDS_OS */ regs[1] = bin2bcd(tm->tm_sec); regs[2] = bin2bcd(tm->tm_min); regs[3] = bin2bcd(tm->tm_hour); @@ -299,7 +299,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) { struct i2c_client *client = to_i2c_client(dev); - u8 start = REG_MINUTE_ALARM, regs[4]; + u8 start = PCF8523_REG_MINUTE_ALARM, regs[4]; struct i2c_msg msgs[2]; u8 value; int err; @@ -324,15 +324,15 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) tm->time.tm_mday = bcd2bin(regs[2] & 0x3F); tm->time.tm_wday = bcd2bin(regs[3] & 0x7); - err = pcf8523_read(client, REG_CONTROL1, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; - tm->enabled = !!(value & REG_CONTROL1_AIE); + tm->enabled = !!(value & PCF8523_CONTROL1_AIE); - err = pcf8523_read(client, REG_CONTROL2, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL2, &value); if (err < 0) return err; - tm->pending = !!(value & REG_CONTROL2_AF); + tm->pending = !!(value & PCF8523_CONTROL2_AF); return 0; } @@ -343,16 +343,16 @@ static int pcf8523_irq_enable(struct device *dev, unsigned int enabled) u8 value; int err; - err = pcf8523_read(client, REG_CONTROL1, &value); + err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; - value &= REG_CONTROL1_AIE; + value &= PCF8523_CONTROL1_AIE; if (enabled) - value |= REG_CONTROL1_AIE; + value |= PCF8523_CONTROL1_AIE; - err = pcf8523_write(client, REG_CONTROL1, value); + err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); if (err < 0) return err; @@ -370,7 +370,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) if (err) return err; - err = pcf8523_write(client, REG_CONTROL2, 0); + err = pcf8523_write(client, PCF8523_REG_CONTROL2, 0); if (err < 0) return err; @@ -382,7 +382,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) rtc_time64_to_tm(alarm_time, &tm->time); } - regs[0] = REG_MINUTE_ALARM; + regs[0] = PCF8523_REG_MINUTE_ALARM; regs[1] = bin2bcd(tm->time.tm_min); regs[2] = bin2bcd(tm->time.tm_hour); regs[3] = bin2bcd(tm->time.tm_mday); @@ -418,11 +418,11 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, if (ret) flags |= RTC_VL_BACKUP_LOW; - ret = pcf8523_read(client, REG_SECONDS, &value); + ret = pcf8523_read(client, PCF8523_REG_SECONDS, &value); if (ret < 0) return ret; - if (value & REG_SECONDS_OS) + if (value & PCF8523_SECONDS_OS) flags |= RTC_VL_DATA_INVALID; return put_user(flags, (unsigned int __user *)arg); @@ -442,13 +442,13 @@ static int pcf8523_rtc_read_offset(struct device *dev, long *offset) u8 value; s8 val; - err = pcf8523_read(client, REG_OFFSET, &value); + err = pcf8523_read(client, PCF8523_REG_OFFSET, &value); if (err < 0) return err; /* sign extend the 7-bit offset value */ val = value << 1; - *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1); + *offset = (value & PCF8523_OFFSET_MODE ? 4069 : 4340) * (val >> 1); return 0; } @@ -465,9 +465,9 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset) if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset)) value = reg_m0 & 0x7f; else - value = (reg_m1 & 0x7f) | REG_OFFSET_MODE; + value = (reg_m1 & 0x7f) | PCF8523_OFFSET_MODE; - return pcf8523_write(client, REG_OFFSET, value); + return pcf8523_write(client, PCF8523_REG_OFFSET, value); } static const struct rtc_class_ops pcf8523_rtc_ops = { @@ -519,7 +519,7 @@ static int pcf8523_probe(struct i2c_client *client, rtc->uie_unsupported = 1; if (client->irq > 0) { - err = pcf8523_write(client, REG_TMR_CLKOUT_CTRL, 0x38); + err = pcf8523_write(client, PCF8523_TMR_CLKOUT_CTRL, 0x38); if (err < 0) return err; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 18f12f36eb2b..c8bddfb94129 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -8,7 +8,7 @@ * * based on the other drivers in this same directory. * - * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf */ #include diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c index bb98f2d574a5..8f9abd65846c 100644 --- a/drivers/rtc/rtc-rtd119x.c +++ b/drivers/rtc/rtc-rtd119x.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Realtek RTD129x RTC * * Copyright (c) 2017 Andreas Färber - * - * SPDX-License-Identifier: GPL-2.0+ */ #include diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 038269a6b08c..6b56f8eacba6 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -488,9 +488,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); - ret = s5m_check_peding_alarm_interrupt(info, alrm); - - return 0; + return s5m_check_peding_alarm_interrupt(info, alrm); } static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c index 187aa955b79c..ce7a2ddbbc16 100644 --- a/drivers/rtc/rtc-sc27xx.c +++ b/drivers/rtc/rtc-sc27xx.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 Spreadtrum Communications Inc. * - * SPDX-License-Identifier: GPL-2.0 */ #include diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index ee721e53c155..b4a520056b1a 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/rtc/rtc-spear.c * * Copyright (C) 2010 ST Microelectronics * Rajeev Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 75a8924ba12b..ac9e228b56d0 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -754,7 +754,7 @@ static int stm32_rtc_probe(struct platform_device *pdev) ret = clk_prepare_enable(rtc->rtc_ck); if (ret) - goto err; + goto err_no_rtc_ck; if (rtc->data->need_dbp) regmap_update_bits(rtc->dbp, rtc->dbp_reg, @@ -830,10 +830,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) } return 0; + err: + clk_disable_unprepare(rtc->rtc_ck); +err_no_rtc_ck: if (rtc->data->has_pclk) clk_disable_unprepare(rtc->pclk); - clk_disable_unprepare(rtc->rtc_ck); if (rtc->data->need_dbp) regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0); diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index a980337c3065..52093e7ba22d 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-tps6586x.c: RTC driver for TI PMIC TPS6586X * * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * 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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 737f26eb284a..c77b8eab94a0 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver * @@ -7,20 +8,6 @@ * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * 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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index d2da92187d56..4e8341c49f51 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -282,7 +282,7 @@ static int rtc_probe(struct platform_device *pdev) { struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev); struct v3020 *chip; - int retval = -EBUSY; + int retval; int i; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c index 74026f67fdfb..00f1945bcb7e 100644 --- a/drivers/rtc/sysfs.c +++ b/drivers/rtc/sysfs.c @@ -102,7 +102,7 @@ max_user_freq_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(max_user_freq); /** - * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time + * hctosys_show - indicate if the given RTC set the system time * @dev: The device that the attribute belongs to. * @attr: The attribute being read. * @buf: The result buffer. diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index c8df75e99f4c..e34c6cc61983 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -621,7 +621,6 @@ void dasd_set_target_state(struct dasd_device *device, int target) mutex_unlock(&device->state_mutex); dasd_put_device(device); } -EXPORT_SYMBOL(dasd_set_target_state); /* * Enable devices with device numbers in [from..to]. diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a6ac505cbdd7..0de1a463c509 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -746,7 +746,7 @@ static void create_uid(struct dasd_eckd_private *private) memcpy(uid->vendor, private->ned->HDA_manufacturer, sizeof(uid->vendor) - 1); EBCASC(uid->vendor, sizeof(uid->vendor) - 1); - memcpy(uid->serial, private->ned->HDA_location, + memcpy(uid->serial, &private->ned->serial, sizeof(uid->serial) - 1); EBCASC(uid->serial, sizeof(uid->serial) - 1); uid->ssid = private->gneq->subsystemID; diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 73651211789f..65e4630ad2ae 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -332,8 +332,10 @@ struct dasd_ned { __u8 dev_type[6]; __u8 dev_model[3]; __u8 HDA_manufacturer[3]; - __u8 HDA_location[2]; - __u8 HDA_seqno[12]; + struct { + __u8 HDA_location[2]; + __u8 HDA_seqno[12]; + } serial; __u8 ID; __u8 unit_addr; } __attribute__ ((packed)); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index d2560186d771..8d3a1d84a757 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -61,6 +61,9 @@ static char *aqm_str; module_param_named(aqmask, aqm_str, charp, 0440); MODULE_PARM_DESC(aqmask, "AP bus domain mask."); +atomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE); +EXPORT_SYMBOL(ap_max_msg_size); + static struct device *ap_root_device; /* Hashtable of all queue devices on the AP bus */ @@ -316,11 +319,24 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); * Returns true if TAPQ succeeded and the info is filled or * false otherwise. */ -static bool ap_queue_info(ap_qid_t qid, int *q_type, - unsigned int *q_fac, int *q_depth, bool *q_decfg) +static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, + int *q_depth, int *q_ml, bool *q_decfg) { struct ap_queue_status status; - unsigned long info = 0; + union { + unsigned long value; + struct { + unsigned int fac : 32; /* facility bits */ + unsigned int at : 8; /* ap type */ + unsigned int _res1 : 8; + unsigned int _res2 : 4; + unsigned int ml : 4; /* apxl ml */ + unsigned int _res3 : 4; + unsigned int qd : 4; /* queue depth */ + } tapq_gr2; + } tapq_info; + + tapq_info.value = 0; /* make sure we don't run into a specifiation exception */ if (AP_QID_CARD(qid) > ap_max_adapter_id || @@ -328,7 +344,7 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, return false; /* call TAPQ on this APQN */ - status = ap_test_queue(qid, ap_apft_available(), &info); + status = ap_test_queue(qid, ap_apft_available(), &tapq_info.value); switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: @@ -340,11 +356,12 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, * info should be filled. All bits 0 is not possible as * there is at least one of the mode bits set. */ - if (WARN_ON_ONCE(!info)) + if (WARN_ON_ONCE(!tapq_info.value)) return false; - *q_type = (int)((info >> 24) & 0xff); - *q_fac = (unsigned int)(info >> 32); - *q_depth = (int)(info & 0xff); + *q_type = tapq_info.tapq_gr2.at; + *q_fac = tapq_info.tapq_gr2.fac; + *q_depth = tapq_info.tapq_gr2.qd; + *q_ml = tapq_info.tapq_gr2.ml; *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; switch (*q_type) { /* For CEX2 and CEX3 the available functions @@ -1516,7 +1533,7 @@ static inline void ap_scan_domains(struct ap_card *ac) unsigned int func; struct device *dev; struct ap_queue *aq; - int rc, dom, depth, type; + int rc, dom, depth, type, ml; /* * Go through the configuration for the domains and compare them @@ -1540,7 +1557,7 @@ static inline void ap_scan_domains(struct ap_card *ac) continue; } /* domain is valid, get info from this APQN */ - if (!ap_queue_info(qid, &type, &func, &depth, &decfg)) { + if (!ap_queue_info(qid, &type, &func, &depth, &ml, &decfg)) { if (aq) { AP_DBF_INFO( "%s(%d,%d) ap_queue_info() not successful, rm queue device\n", @@ -1639,7 +1656,7 @@ static inline void ap_scan_adapter(int ap) unsigned int func; struct device *dev; struct ap_card *ac; - int rc, dom, depth, type, comp_type; + int rc, dom, depth, type, comp_type, ml; /* Is there currently a card device for this adapter ? */ dev = bus_find_device(&ap_bus_type, NULL, @@ -1668,7 +1685,8 @@ 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, &decfg)) + if (ap_queue_info(qid, &type, &func, + &depth, &ml, &decfg)) break; } if (dom > ap_max_domain_id) { @@ -1737,7 +1755,7 @@ static inline void ap_scan_adapter(int ap) __func__, ap, type); return; } - ac = ap_card_create(ap, depth, type, comp_type, func); + ac = ap_card_create(ap, depth, type, comp_type, func, ml); if (!ac) { AP_DBF_WARN("%s(%d) ap_card_create() failed\n", __func__, ap); @@ -1748,6 +1766,12 @@ static inline void ap_scan_adapter(int ap) dev->bus = &ap_bus_type; dev->parent = ap_root_device; dev_set_name(dev, "card%02x", ap); + /* maybe enlarge ap_max_msg_size to support this card */ + if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) { + atomic_set(&ap_max_msg_size, ac->maxmsgsize); + AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n", + __func__, ap, atomic_read(&ap_max_msg_size)); + } /* Register the new card device with AP bus */ rc = device_register(dev); if (rc) { diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 230fec6510e2..8f18abdbbc2b 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -25,8 +25,11 @@ #define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */ #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ +#define AP_DEFAULT_MAX_MSG_SIZE (12 * 1024) +#define AP_TAPQ_ML_FIELD_CHUNK_SIZE (4096) extern int ap_domain_index; +extern atomic_t ap_max_msg_size; extern DECLARE_HASHTABLE(ap_queues, 8); extern spinlock_t ap_queues_lock; @@ -167,6 +170,7 @@ struct ap_card { unsigned int functions; /* AP device function bitfield. */ int queue_depth; /* AP queue depth.*/ int id; /* AP card number. */ + unsigned int maxmsgsize; /* AP msg limit for this card */ bool config; /* configured state */ atomic64_t total_request_count; /* # requests ever for this AP device.*/ }; @@ -228,7 +232,8 @@ struct ap_message { struct list_head list; /* Request queueing. */ unsigned long long psmid; /* Message id. */ void *msg; /* Pointer to message buffer. */ - unsigned int len; /* Message length. */ + unsigned int len; /* actual msg len in msg buffer */ + unsigned int bufsize; /* allocated msg buffer size */ u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ struct ap_fi fi; /* Failure Injection cmd */ int rc; /* Return code for this message */ @@ -290,8 +295,8 @@ void ap_queue_prepare_remove(struct ap_queue *aq); void ap_queue_remove(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_device_type, - int comp_device_type, unsigned int functions); +struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, + int comp_type, unsigned int functions, int ml); struct ap_perms { unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)]; diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index ca9afc5fcaf7..196325a66662 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -174,6 +174,16 @@ static ssize_t config_store(struct device *dev, static DEVICE_ATTR_RW(config); +static ssize_t max_msg_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", ac->maxmsgsize); +} + +static DEVICE_ATTR_RO(max_msg_size); + static struct attribute *ap_card_dev_attrs[] = { &dev_attr_hwtype.attr, &dev_attr_raw_hwtype.attr, @@ -184,6 +194,7 @@ static struct attribute *ap_card_dev_attrs[] = { &dev_attr_pendingq_count.attr, &dev_attr_modalias.attr, &dev_attr_config.attr, + &dev_attr_max_msg_size.attr, NULL }; @@ -209,7 +220,7 @@ static void ap_card_device_release(struct device *dev) } struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, - int comp_type, unsigned int functions) + int comp_type, unsigned int functions, int ml) { struct ap_card *ac; @@ -223,5 +234,8 @@ struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, ac->queue_depth = queue_depth; ac->functions = functions; ac->id = id; + ac->maxmsgsize = ml > 0 ? + 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 337353c9655e..669f96fddad6 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -101,7 +101,7 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) if (msg == NULL) return -EINVAL; - status = ap_dqap(qid, psmid, msg, length); + status = ap_dqap(qid, psmid, msg, length, NULL, NULL); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -136,9 +136,24 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) struct ap_queue_status status; struct ap_message *ap_msg; bool found = false; + size_t reslen; + unsigned long resgr0 = 0; + int parts = 0; + + /* + * DQAP loop until response code and resgr0 indicate that + * the msg is totally received. As we use the very same buffer + * the msg is overwritten with each invocation. That's intended + * and the receiver of the msg is informed with a msg rc code + * of EMSGSIZE in such a case. + */ + do { + status = ap_dqap(aq->qid, &aq->reply->psmid, + aq->reply->msg, aq->reply->bufsize, + &reslen, &resgr0); + parts++; + } while (status.response_code == 0xFF && resgr0 != 0); - status = ap_dqap(aq->qid, &aq->reply->psmid, - aq->reply->msg, aq->reply->len); switch (status.response_code) { case AP_RESPONSE_NORMAL: aq->queue_count = max_t(int, 0, aq->queue_count - 1); @@ -150,7 +165,12 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) continue; list_del_init(&ap_msg->list); aq->pendingq_count--; - ap_msg->receive(aq, ap_msg, aq->reply); + if (parts > 1) { + ap_msg->rc = -EMSGSIZE; + ap_msg->receive(aq, ap_msg, NULL); + } else { + ap_msg->receive(aq, ap_msg, aq->reply); + } found = true; break; } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 5d726cd67314..529ffe26ea9d 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -900,6 +900,9 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, if (xcRB->user_defined != AUTOSELECT && xcRB->user_defined != zc->card->id) continue; + /* check if request size exceeds card max msg size */ + if (ap_msg.len > zc->card->maxmsgsize) + continue; /* check if device node has admission for this card */ if (!zcrypt_check_card(perms, zc->card->id)) continue; @@ -1068,6 +1071,9 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, if (targets && !is_desired_ep11_card(zc->card->id, target_num, targets)) continue; + /* check if request size exceeds card max msg size */ + if (ap_msg.len > zc->card->maxmsgsize) + continue; /* check if device node has admission for this card */ if (!zcrypt_check_card(perms, zc->card->id)) continue; diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index f4a6d3744241..f518b5fc7e5d 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -28,9 +28,6 @@ #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ #define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */ -#define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE -#define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE - /* Waiting time for requests to be processed. * Currently there are some types of request which are not deterministic. * But the maximum time limit managed by the stomper code is set to 60sec. @@ -605,19 +602,19 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) int rc; if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) { - zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE); + 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)) { - zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + 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)) { - zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + zq = zcrypt_queue_alloc(aq->card->maxmsgsize); if (!zq) return -ENOMEM; zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 6d1800cb21df..99405472824d 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -442,11 +442,13 @@ static void zcrypt_cex2a_receive(struct ap_queue *aq, goto out; /* ap_msg->rc indicates the error */ t80h = reply->msg; if (t80h->type == TYPE80_RSP_CODE) { - if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) - len = min_t(int, CEX2A_MAX_RESPONSE_SIZE, t80h->len); - else - len = min_t(int, CEX3A_MAX_RESPONSE_SIZE, t80h->len); - memcpy(msg->msg, reply->msg, len); + len = t80h->len; + if (len > reply->bufsize || len > msg->bufsize) { + msg->rc = -EMSGSIZE; + } else { + memcpy(msg->msg, reply->msg, len); + msg->len = len; + } } else memcpy(msg->msg, reply->msg, sizeof(error_reply)); out: @@ -469,10 +471,9 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, struct completion work; int rc; - if (zq->zcard->user_space_type == ZCRYPT_CEX2A) - ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); - else - ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ? + MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE; + ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_cex2a_receive; @@ -515,10 +516,9 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, struct completion work; int rc; - if (zq->zcard->user_space_type == ZCRYPT_CEX2A) - ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); - else - ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ? + MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE; + ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_cex2a_receive; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index da6b2bf779a8..752c6398fcd6 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -403,7 +403,7 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg, } __packed * msg = ap_msg->msg; int rcblen = CEIL4(xcRB->request_control_blk_length); - int replylen, req_sumlen, resp_sumlen; + int req_sumlen, resp_sumlen; char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen; char *function_code; @@ -415,7 +415,7 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg, ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcRB->request_control_blk_length) + xcRB->request_data_length; - if (ap_msg->len > MSGTYPE06_MAX_MSG_SIZE) + if (ap_msg->len > ap_msg->bufsize) return -EINVAL; /* @@ -435,12 +435,6 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg, xcRB->reply_control_blk_length) return -EINVAL; /* overflow after alignment*/ - replylen = sizeof(struct type86_fmt2_msg) + - CEIL4(xcRB->reply_control_blk_length) + - xcRB->reply_data_length; - if (replylen > MSGTYPE06_MAX_MSG_SIZE) - return -EINVAL; - /* * Overflow check * sum must be greater (or equal) than the largest operand @@ -530,18 +524,13 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap return -EINVAL; /* overflow after alignment*/ /* length checks */ - ap_msg->len = sizeof(struct type6_hdr) + xcRB->req_len; - if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE - - (sizeof(struct type6_hdr))) + ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcRB->req_len); + if (ap_msg->len > ap_msg->bufsize) return -EINVAL; if (CEIL4(xcRB->resp_len) < xcRB->resp_len) return -EINVAL; /* overflow after alignment*/ - if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE - - (sizeof(struct type86_fmt2_msg))) - return -EINVAL; - /* prepare type6 header */ msg->hdr = static_type6_ep11_hdr; msg->hdr.ToCardLen1 = xcRB->req_len; @@ -952,13 +941,21 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_ICA: len = sizeof(struct type86x_reply) + t86r->length - 2; - len = min_t(int, CEXXC_MAX_ICA_RESPONSE_SIZE, len); - memcpy(msg->msg, reply->msg, len); + if (len > reply->bufsize || len > msg->bufsize) { + msg->rc = -EMSGSIZE; + } else { + memcpy(msg->msg, reply->msg, len); + msg->len = len; + } break; case CEXXC_RESPONSE_TYPE_XCRB: len = t86r->fmt2.offset2 + t86r->fmt2.count2; - len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len); - memcpy(msg->msg, reply->msg, len); + if (len > reply->bufsize || len > msg->bufsize) { + msg->rc = -EMSGSIZE; + } else { + memcpy(msg->msg, reply->msg, len); + msg->len = len; + } break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); @@ -999,8 +996,12 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_EP11: len = t86r->fmt2.offset1 + t86r->fmt2.count1; - len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len); - memcpy(msg->msg, reply->msg, len); + if (len > reply->bufsize || len > msg->bufsize) { + msg->rc = -EMSGSIZE; + } else { + memcpy(msg->msg, reply->msg, len); + msg->len = len; + } break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); @@ -1033,6 +1034,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; + ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); @@ -1080,6 +1082,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; + ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); @@ -1124,7 +1127,8 @@ unsigned int get_cprb_fc(bool userspace, struct ica_xcRB *xcRB, .type = CEXXC_RESPONSE_TYPE_XCRB, }; - ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->bufsize = atomic_read(&ap_max_msg_size); + ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive; @@ -1181,7 +1185,8 @@ unsigned int get_ep11cprb_fc(bool userspace, struct ep11_urb *xcrb, .type = CEXXC_RESPONSE_TYPE_EP11, }; - ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->bufsize = atomic_read(&ap_max_msg_size); + ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive_ep11; @@ -1277,7 +1282,8 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, .type = CEXXC_RESPONSE_TYPE_XCRB, }; - ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE; + ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL); if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index 0a0bf074206b..155c73514bac 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -19,8 +19,6 @@ #define MSGTYPE06_VARIANT_NORNG 1 #define MSGTYPE06_VARIANT_EP11 2 -#define MSGTYPE06_MAX_MSG_SIZE (12*1024) - /** * The type 6 message family is associated with CEXxC/CEXxP cards. * diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 605904b86287..20f12288a8c1 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -111,17 +111,17 @@ bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online) return false; } -struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) +struct zcrypt_queue *zcrypt_queue_alloc(size_t reply_buf_size) { struct zcrypt_queue *zq; zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL); if (!zq) return NULL; - zq->reply.msg = kmalloc(max_response_size, GFP_KERNEL); + zq->reply.msg = kmalloc(reply_buf_size, GFP_KERNEL); if (!zq->reply.msg) goto out_free; - zq->reply.len = max_response_size; + zq->reply.bufsize = reply_buf_size; INIT_LIST_HEAD(&zq->list); kref_init(&zq->refcount); return zq; diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 4b04ab8908f8..a396f048a031 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -493,7 +493,7 @@ ahc_inq(struct ahc_softc *ahc, u_int port) return ((ahc_inb(ahc, port)) | (ahc_inb(ahc, port+1) << 8) | (ahc_inb(ahc, port+2) << 16) - | (ahc_inb(ahc, port+3) << 24) + | (((uint64_t)ahc_inb(ahc, port+3)) << 24) | (((uint64_t)ahc_inb(ahc, port+4)) << 32) | (((uint64_t)ahc_inb(ahc, port+5)) << 40) | (((uint64_t)ahc_inb(ahc, port+6)) << 48) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index a195bfe9eccc..7a78606598c4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -53,6 +53,7 @@ static struct scsi_host_template aic94xx_sht = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index 297a66770260..46815e65f7a4 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -718,10 +718,12 @@ static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1) do { switch (id1) { default: - if (el->id1 == id1) + if (el->id1 == id1) { + fallthrough; case 0xFF: if (el->id0 == id0) return el; + } } el = start + le16_to_cpu(el->next); } while (el != start); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 310b801c6c87..e70f69f791db 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -143,8 +143,7 @@ DEVICE_ATTR(beiscsi_##_name, S_IRUGO | S_IWUSR,\ beiscsi_##_name##_disp, beiscsi_##_name##_store) /* - * When new log level added update the - * the MAX allowed value for log_enable + * When new log level added update MAX allowed value for log_enable */ BEISCSI_RW_ATTR(log_enable, 0x00, 0xFF, 0x00, "Enable logging Bit Mask\n" @@ -825,9 +824,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) &phwi_context->be_eq[i]); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_init_irqs-Failed to" - "register msix for i = %d\n", - i); + "BM_%d : %s-Failed to register msix for i = %d\n", + __func__, i); kfree(phba->msi_name[i]); goto free_msix_irqs; } @@ -841,9 +839,9 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) ret = request_irq(pci_irq_vector(pcidev, i), be_isr_mcc, 0, phba->msi_name[i], &phwi_context->be_eq[i]); if (ret) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT , - "BM_%d : beiscsi_init_irqs-" - "Failed to register beiscsi_msix_mcc\n"); + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, + "BM_%d : %s-Failed to register beiscsi_msix_mcc\n", + __func__); kfree(phba->msi_name[i]); goto free_msix_irqs; } @@ -853,8 +851,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) "beiscsi", phba); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_init_irqs-" - "Failed to register irq\\n"); + "BM_%d : %s-Failed to register irq\n", + __func__); return ret; } } @@ -1030,7 +1028,7 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, phba->params.wrbs_per_cxn); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x" + "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x " "wrb_handles_available=%d\n", pwrb_handle, pwrb_context->free_index, pwrb_context->wrb_handles_available); @@ -1374,7 +1372,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, "BM_%d :\t\t No HWH_TYPE_LOGIN Expected in" - " hwi_complete_cmd- Solicited path\n"); + " %s- Solicited path\n", __func__); break; case HWH_TYPE_NOP: @@ -1384,8 +1382,8 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, default: beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, - "BM_%d : In hwi_complete_cmd, unknown type = %d" - "wrb_index 0x%x CID 0x%x\n", type, + "BM_%d : In %s, unknown type = %d " + "wrb_index 0x%x CID 0x%x\n", __func__, type, csol_cqe.wrb_index, csol_cqe.cid); break; @@ -1883,9 +1881,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) cid = AMAP_GET_BITS( struct amap_i_t_dpdu_cqe_v2, cid, sol); - else - cid = AMAP_GET_BITS(struct amap_sol_cqe_v2, - cid, sol); + else + cid = AMAP_GET_BITS(struct amap_sol_cqe_v2, + cid, sol); } cri_index = BE_GET_CRI_FROM_CID(cid); @@ -2010,8 +2008,7 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) default: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Invalid CQE Event Received Code : %d" - "CID 0x%x...\n", + "BM_%d : Invalid CQE Event Received Code : %d CID 0x%x...\n", code, cid); break; } @@ -3001,7 +2998,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, void *eq_vaddress; dma_addr_t paddr; - num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \ + num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * sizeof(struct be_eq_entry)); if (phba->pcidev->msix_enabled) @@ -3034,8 +3031,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, BEISCSI_EQ_DELAY_DEF); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_cmd_eq_create" - "Failed for EQ\n"); + "BM_%d : beiscsi_cmd_eq_create Failed for EQ\n"); goto create_eq_error; } @@ -3068,7 +3064,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, int ret = -ENOMEM; dma_addr_t paddr; - num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ + num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * sizeof(struct sol_cqe)); for (i = 0; i < phba->num_cpus; i++) { @@ -3090,8 +3086,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, sizeof(struct sol_cqe), cq_vaddress); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : be_fill_queue Failed " - "for ISCSI CQ\n"); + "BM_%d : be_fill_queue Failed for ISCSI CQ\n"); goto create_cq_error; } @@ -3100,8 +3095,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, false, 0); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : beiscsi_cmd_eq_create" - "Failed for ISCSI CQ\n"); + "BM_%d : beiscsi_cmd_eq_create Failed for ISCSI CQ\n"); goto create_cq_error; } beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, @@ -3226,8 +3220,8 @@ beiscsi_create_def_data(struct beiscsi_hba *phba, phwi_context->be_def_dataq[ulp_num].id); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : DEFAULT PDU DATA RING CREATED" - "on ULP : %d\n", ulp_num); + "BM_%d : DEFAULT PDU DATA RING CREATED on ULP : %d\n", + ulp_num); return 0; } @@ -3253,13 +3247,13 @@ beiscsi_post_template_hdr(struct beiscsi_hba *phba) if (status != 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Post Template HDR Failed for" + "BM_%d : Post Template HDR Failed for " "ULP_%d\n", ulp_num); return status; } beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : Template HDR Pages Posted for" + "BM_%d : Template HDR Pages Posted for " "ULP_%d\n", ulp_num); } } @@ -3374,18 +3368,17 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, } else { idx++; wrb_vaddr = mem_descr->mem_array[idx].virtual_address; - pa_addr_lo = mem_descr->mem_array[idx].\ + pa_addr_lo = mem_descr->mem_array[idx]. bus_address.u.a64.address; num_wrb_rings = mem_descr->mem_array[idx].size / (phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb)); pwrb_arr[num].virtual_address = wrb_vaddr; - pwrb_arr[num].bus_address.u.a64.address\ - = pa_addr_lo; + pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo; pwrb_arr[num].size = phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb); wrb_vaddr += pwrb_arr[num].size; - pa_addr_lo += pwrb_arr[num].size; + pa_addr_lo += pwrb_arr[num].size; num_wrb_rings--; } } @@ -3937,7 +3930,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) idx++; } beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : phba->io_sgl_hndl_avbl=%d" + "BM_%d : phba->io_sgl_hndl_avbl=%d " "phba->eh_sgl_hndl_avbl=%d\n", phba->io_sgl_hndl_avbl, phba->eh_sgl_hndl_avbl); @@ -3995,13 +3988,8 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) GFP_KERNEL); if (!ptr_cid_info) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to allocate memory" - "for ULP_CID_INFO for ULP : %d\n", - ulp_num); ret = -ENOMEM; goto free_memory; - } /* Allocate memory for CID array */ @@ -4010,10 +3998,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) sizeof(*ptr_cid_info->cid_array), GFP_KERNEL); if (!ptr_cid_info->cid_array) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to allocate memory" - "for CID_ARRAY for ULP : %d\n", - ulp_num); kfree(ptr_cid_info); ptr_cid_info = NULL; ret = -ENOMEM; @@ -4031,9 +4015,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) sizeof(struct iscsi_endpoint *), GFP_KERNEL); if (!phba->ep_array) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to allocate memory in " - "hba_setup_cid_tbls\n"); ret = -ENOMEM; goto free_memory; @@ -4043,10 +4024,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) sizeof(struct beiscsi_conn *), GFP_KERNEL); if (!phba->conn_table) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Failed to allocate memory in" - "hba_setup_cid_tbls\n"); - kfree(phba->ep_array); phba->ep_array = NULL; ret = -ENOMEM; @@ -4399,7 +4376,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) if (!io_task->psgl_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of IO_SGL_ICD Failed" + "BM_%d : Alloc of IO_SGL_ICD Failed " "for the CID : %d\n", beiscsi_conn->beiscsi_conn_cid); goto free_hndls; @@ -4410,7 +4387,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of WRB_HANDLE Failed" + "BM_%d : Alloc of WRB_HANDLE Failed " "for the CID : %d\n", beiscsi_conn->beiscsi_conn_cid); goto free_io_hndls; @@ -4426,10 +4403,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of MGMT_SGL_ICD Failed" + "BM_%d : Alloc of MGMT_SGL_ICD Failed " "for the CID : %d\n", - beiscsi_conn-> - beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid); goto free_hndls; } @@ -4444,10 +4420,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of WRB_HANDLE Failed" + "BM_%d : Alloc of WRB_HANDLE Failed " "for the CID : %d\n", - beiscsi_conn-> - beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid); goto free_mgmt_hndls; } beiscsi_conn->plogin_wrb_handle = @@ -4465,10 +4440,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of MGMT_SGL_ICD Failed" + "BM_%d : Alloc of MGMT_SGL_ICD Failed " "for the CID : %d\n", - beiscsi_conn-> - beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid); goto free_hndls; } io_task->pwrb_handle = @@ -4478,7 +4452,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, - "BM_%d : Alloc of WRB_HANDLE Failed" + "BM_%d : Alloc of WRB_HANDLE Failed " "for the CID : %d\n", beiscsi_conn->beiscsi_conn_cid); goto free_mgmt_hndls; @@ -5743,6 +5717,7 @@ free_hba: pci_disable_msix(phba->pcidev); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); + pci_disable_pcie_error_reporting(pcidev); pci_set_drvdata(pcidev, NULL); disable_pci: pci_release_regions(pcidev); diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index ed300a279a38..f2996a9b2f63 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1213,7 +1213,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) * cleanup the command and return that I/O was successfully * aborted. */ - rc = bnx2fc_abts_cleanup(io_req); + bnx2fc_abts_cleanup(io_req); /* This only occurs when an task abort was requested while ABTS is in progress. Setting the IO_CLEANUP flag will skip the RRQ process in the case when the fw generated SCSI_CMD cmpl diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c index b7d69ff29c09..e0d798d6baee 100644 --- a/drivers/scsi/elx/efct/efct_lio.c +++ b/drivers/scsi/elx/efct/efct_lio.c @@ -832,10 +832,6 @@ efct_lio_npiv_make_nport(struct target_fabric_configfs *tf, } vport_list->lio_vport = lio_vport; - spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags); - INIT_LIST_HEAD(&vport_list->list_entry); - list_add_tail(&vport_list->list_entry, &efct->tgt_efct.vport_list); - spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags); memset(&vport_id, 0, sizeof(vport_id)); vport_id.port_name = npiv_wwpn; @@ -853,6 +849,10 @@ efct_lio_npiv_make_nport(struct target_fabric_configfs *tf, } lio_vport->fc_vport = new_fc_vport; + spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags); + INIT_LIST_HEAD(&vport_list->list_entry); + list_add_tail(&vport_list->list_entry, &efct->tgt_efct.vport_list); + spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags); return &lio_vport->vport_wwn; } diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c index fc24a50c5d6b..6c6c04e1b74d 100644 --- a/drivers/scsi/elx/libefc_sli/sli4.c +++ b/drivers/scsi/elx/libefc_sli/sli4.c @@ -2381,8 +2381,6 @@ sli_xmit_els_rsp64_wqe(struct sli4 *sli, void *buf, struct efc_dma *rsp, els->ox_id = cpu_to_le16(params->ox_id); - els->flags2 |= SLI4_ELS_IOD & SLI4_ELS_REQUEST64_DIR_WRITE; - els->flags2 |= SLI4_ELS_QOSD; els->cmd_type_wqec = SLI4_ELS_REQUEST64_CMD_GEN; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 9e58009369f9..afe639994f3d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1771,6 +1771,7 @@ static struct scsi_host_template sht_v1_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 49d2723ef34c..b0b2361e63fe 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3584,6 +3584,7 @@ static struct scsi_host_template sht_v2_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 5c3b1dfcb37c..a4885d03afe2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3155,6 +3155,7 @@ static struct scsi_host_template sht_v3_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 30c30a1db5b1..5d78f7e939a3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1300,7 +1300,7 @@ static char *__ipr_format_res_path(u8 *res_path, char *buffer, int len) *p = '\0'; p += scnprintf(p, buffer + len - p, "%02X", res_path[0]); - for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) + for (i = 1; res_path[i] != 0xff && i < IPR_RES_PATH_BYTES; i++) p += scnprintf(p, buffer + len - p, "-%02X", res_path[i]); return buffer; @@ -1323,7 +1323,7 @@ static char *ipr_format_res_path(struct ipr_ioa_cfg *ioa_cfg, *p = '\0'; p += scnprintf(p, buffer + len - p, "%d/", ioa_cfg->host->host_no); - __ipr_format_res_path(res_path, p, len - (buffer - p)); + __ipr_format_res_path(res_path, p, len - (p - buffer)); return buffer; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 783ee03ad9ea..69444d21fca1 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -428,6 +428,7 @@ struct ipr_config_table_entry64 { __be64 lun; __be64 lun_wwn[2]; #define IPR_MAX_RES_PATH_LENGTH 48 +#define IPR_RES_PATH_BYTES 8 __be64 res_path; struct ipr_std_inq_data std_inq_data; u8 reserved2[4]; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index c452849e7bb4..ffd33e5decae 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -167,6 +167,7 @@ static struct scsi_host_template isci_sht = { .eh_abort_handler = sas_eh_abort_handler, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index cd0fb8ca2425..33da3c1085f0 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1162,6 +1162,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x spp_type 0x%x\n", pp->spp.spp_flags, pp->spp.spp_type); + rdata->spp_type = pp->spp.spp_type; if (resp_code != FC_SPP_RESP_ACK) { if (resp_code == FC_SPP_RESP_CONF) @@ -1184,11 +1185,13 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, /* * Call prli provider if we should act as a target */ - prov = fc_passive_prov[rdata->spp_type]; - if (prov) { - memset(&temp_spp, 0, sizeof(temp_spp)); - prov->prli(rdata, pp->prli.prli_spp_len, - &pp->spp, &temp_spp); + if (rdata->spp_type < FC_FC4_PROV_SIZE) { + prov = fc_passive_prov[rdata->spp_type]; + if (prov) { + memset(&temp_spp, 0, sizeof(temp_spp)); + prov->prli(rdata, pp->prli.prli_spp_len, + &pp->spp, &temp_spp); + } } /* * Check if the image pair could be established diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 1bf939818c98..ee44a0d7730b 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -911,6 +911,14 @@ void sas_task_abort(struct sas_task *task) blk_abort_request(sc->request); } +int sas_slave_alloc(struct scsi_device *sdev) +{ + if (dev_is_sata(sdev_to_domain_dev(sdev)) && sdev->lun) + return -ENXIO; + + return 0; +} + void sas_target_destroy(struct scsi_target *starget) { struct domain_device *found_dev = starget->hostdata; @@ -957,5 +965,6 @@ EXPORT_SYMBOL_GPL(sas_task_abort); EXPORT_SYMBOL_GPL(sas_phy_reset); EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); +EXPORT_SYMBOL_GPL(sas_slave_alloc); EXPORT_SYMBOL_GPL(sas_target_destroy); EXPORT_SYMBOL_GPL(sas_ioctl); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index d3fac99db786..d20c2e4ee793 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -121,8 +121,8 @@ static irqreturn_t megaraid_isr(int, void *); static void megaraid_mbox_dpc(unsigned long); -static ssize_t megaraid_sysfs_show_app_hndl(struct device *, struct device_attribute *attr, char *); -static ssize_t megaraid_sysfs_show_ldnum(struct device *, struct device_attribute *attr, char *); +static ssize_t megaraid_mbox_app_hndl_show(struct device *, struct device_attribute *attr, char *); +static ssize_t megaraid_mbox_ld_show(struct device *, struct device_attribute *attr, char *); static int megaraid_cmm_register(adapter_t *); static int megaraid_cmm_unregister(adapter_t *); @@ -302,8 +302,7 @@ static struct pci_driver megaraid_pci_driver = { // definitions for the device attributes for exporting logical drive number // for a scsi address (Host, Channel, Id, Lun) -static DEVICE_ATTR(megaraid_mbox_app_hndl, S_IRUSR, megaraid_sysfs_show_app_hndl, - NULL); +static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_app_hndl); // Host template initializer for megaraid mbox sysfs device attributes static struct device_attribute *megaraid_shost_attrs[] = { @@ -312,7 +311,7 @@ static struct device_attribute *megaraid_shost_attrs[] = { }; -static DEVICE_ATTR(megaraid_mbox_ld, S_IRUSR, megaraid_sysfs_show_ldnum, NULL); +static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_ld); // Host template initializer for megaraid mbox sysfs device attributes static struct device_attribute *megaraid_sdev_attrs[] = { @@ -3961,7 +3960,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter) /** - * megaraid_sysfs_show_app_hndl - display application handle for this adapter + * megaraid_mbox_app_hndl_show - display application handle for this adapter * @dev : class device object representation for the host * @attr : device attribute (unused) * @buf : buffer to send data to @@ -3971,8 +3970,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter) * handle, since we do not interface with applications directly. */ static ssize_t -megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr, - char *buf) +megaraid_mbox_app_hndl_show(struct device *dev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(dev); adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(shost); @@ -3985,7 +3983,7 @@ megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr, /** - * megaraid_sysfs_show_ldnum - display the logical drive number for this device + * megaraid_mbox_ld_show - display the logical drive number for this device * @dev : device object representation for the scsi device * @attr : device attribute to show * @buf : buffer to send data to @@ -4000,7 +3998,7 @@ megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr, * */ static ssize_t -megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf) +megaraid_mbox_ld_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 40676155e62d..24ac7ddec749 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -867,8 +867,9 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) tgtdev->is_hidden = 1; - if (mrioc->shost) - prot_mask = scsi_host_get_prot(mrioc->shost); + if (!mrioc->shost) + break; + prot_mask = scsi_host_get_prot(mrioc->shost); if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) { scsi_host_set_prot(mrioc->shost, prot_mask & 0x77); ioc_info(mrioc, diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 6aa2697c4a15..f18dd9703595 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -46,6 +46,7 @@ static struct scsi_host_template mvs_sht = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT @@ -692,22 +693,17 @@ static struct pci_driver mvs_pci_driver = { .remove = mvs_pci_remove, }; -static ssize_t -mvs_show_driver_version(struct device *cdev, - struct device_attribute *attr, char *buffer) +static ssize_t driver_version_show(struct device *cdev, + struct device_attribute *attr, char *buffer) { return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION); } -static DEVICE_ATTR(driver_version, - S_IRUGO, - mvs_show_driver_version, - NULL); +static DEVICE_ATTR_RO(driver_version); -static ssize_t -mvs_store_interrupt_coalescing(struct device *cdev, - struct device_attribute *attr, - const char *buffer, size_t size) +static ssize_t interrupt_coalescing_store(struct device *cdev, + struct device_attribute *attr, + const char *buffer, size_t size) { unsigned int val = 0; struct mvs_info *mvi = NULL; @@ -745,16 +741,13 @@ mvs_store_interrupt_coalescing(struct device *cdev, return strlen(buffer); } -static ssize_t mvs_show_interrupt_coalescing(struct device *cdev, - struct device_attribute *attr, char *buffer) +static ssize_t interrupt_coalescing_show(struct device *cdev, + struct device_attribute *attr, char *buffer) { return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing); } -static DEVICE_ATTR(interrupt_coalescing, - S_IRUGO|S_IWUSR, - mvs_show_interrupt_coalescing, - mvs_store_interrupt_coalescing); +static DEVICE_ATTR_RW(interrupt_coalescing); static int __init mvs_init(void) { diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index af09bd282cb9..313248c7bab9 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -101,6 +101,7 @@ static struct scsi_host_template pm8001_sht = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, + .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index d995f72a6759..461c0c9180c4 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -24,9 +24,8 @@ static struct qedf_ctx *qedf_get_base_qedf(struct qedf_ctx *qedf) return lport_priv(base_lport); } -static ssize_t -qedf_fcoe_mac_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fcoe_mac_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fc_lport *lport = shost_priv(class_to_shost(dev)); u32 port_id; @@ -42,9 +41,8 @@ qedf_fcoe_mac_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%pM\n", fcoe_mac); } -static ssize_t -qedf_fka_period_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fka_period_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fc_lport *lport = shost_priv(class_to_shost(dev)); struct qedf_ctx *qedf = lport_priv(lport); @@ -59,8 +57,8 @@ qedf_fka_period_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", fka_period); } -static DEVICE_ATTR(fcoe_mac, S_IRUGO, qedf_fcoe_mac_show, NULL); -static DEVICE_ATTR(fka_period, S_IRUGO, qedf_fka_period_show, NULL); +static DEVICE_ATTR_RO(fcoe_mac); +static DEVICE_ATTR_RO(fka_period); struct device_attribute *qedf_host_attrs[] = { &dev_attr_fcoe_mac, diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 6184bc485811..6b5b6a75ac88 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1515,9 +1515,19 @@ void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { int rval; + if (io_req == NULL) { + QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n"); + return; + } + + if (io_req->fcport == NULL) { + QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n"); + return; + } + if (!cqe) { QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, - "cqe is NULL for io_req %p\n", io_req); + "cqe is NULL for io_req %p\n", io_req); return; } @@ -1533,6 +1543,16 @@ void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, le32_to_cpu(cqe->cqe_info.err_info.rx_buf_off), le32_to_cpu(cqe->cqe_info.err_info.rx_id)); + /* When flush is active, let the cmds be flushed out from the cleanup context */ + if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &io_req->fcport->flags) || + (test_bit(QEDF_RPORT_IN_LUN_RESET, &io_req->fcport->flags) && + io_req->sc_cmd->device->lun == (u64)io_req->fcport->lun_reset_lun)) { + QEDF_ERR(&qedf->dbg_ctx, + "Dropping EQE for xid=0x%x as fcport is flushing", + io_req->xid); + return; + } + if (qedf->stop_io_on_error) { qedf_stop_all_io(qedf); return; diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c index 04ee68e6499c..be174d30eb7c 100644 --- a/drivers/scsi/qedi/qedi_sysfs.c +++ b/drivers/scsi/qedi/qedi_sysfs.c @@ -16,9 +16,9 @@ static inline struct qedi_ctx *qedi_dev_to_hba(struct device *dev) return iscsi_host_priv(shost); } -static ssize_t qedi_show_port_state(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t port_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct qedi_ctx *qedi = qedi_dev_to_hba(dev); @@ -28,8 +28,8 @@ static ssize_t qedi_show_port_state(struct device *dev, return sprintf(buf, "Linkdown\n"); } -static ssize_t qedi_show_speed(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t speed_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct qedi_ctx *qedi = qedi_dev_to_hba(dev); struct qed_link_output if_link; @@ -39,8 +39,8 @@ static ssize_t qedi_show_speed(struct device *dev, return sprintf(buf, "%d Gbit\n", if_link.speed / 1000); } -static DEVICE_ATTR(port_state, 0444, qedi_show_port_state, NULL); -static DEVICE_ATTR(speed, 0444, qedi_show_speed, NULL); +static DEVICE_ATTR_RO(port_state); +static DEVICE_ATTR_RO(speed); struct device_attribute *qedi_shost_attrs[] = { &dev_attr_port_state, diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index def4d99f80e9..2f67ec1df3e6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3660,6 +3660,8 @@ struct qla_qpair { struct qla_tgt_counters tgt_counters; uint16_t cpuid; struct qla_fw_resources fwres ____cacheline_aligned; + u32 cmd_cnt; + u32 cmd_completion_cnt; }; /* Place holder for FW buffer parameters */ @@ -4616,6 +4618,7 @@ struct qla_hw_data { struct qla_hw_data_stat stat; pci_error_state_t pci_error_state; + u64 prev_cmd_cnt; }; struct active_regions { @@ -4743,6 +4746,7 @@ typedef struct scsi_qla_host { #define SET_ZIO_THRESHOLD_NEEDED 32 #define ISP_ABORT_TO_ROM 33 #define VPORT_DELETE 34 +#define HEARTBEAT_CHK 38 #define PROCESS_PUREX_IOCB 63 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 418be9a2fcf6..2f867da822ae 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -549,6 +549,7 @@ extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t, uint32_t *); extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t, uint32_t); +void qla_no_op_mb(struct scsi_qla_host *vha); /* * Global Function Prototypes in qla_isr.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index eb825318e3f5..f8f471157109 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -6870,10 +6870,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->flags.fw_init_done = 0; ha->chip_reset++; ha->base_qpair->chip_reset = ha->chip_reset; + ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0; for (i = 0; i < ha->max_qpairs; i++) { - if (ha->queue_pair_map[i]) + if (ha->queue_pair_map[i]) { ha->queue_pair_map[i]->chip_reset = ha->base_qpair->chip_reset; + ha->queue_pair_map[i]->cmd_cnt = + ha->queue_pair_map[i]->cmd_completion_cnt = 0; + } } /* purge MBox commands */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 38b5bdde2405..d0ee843f6b04 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1710,6 +1710,7 @@ qla24xx_start_scsi(srb_t *sp) } else req->ring_ptr++; + sp->qpair->cmd_cnt++; sp->flags |= SRB_DMA_VALID; /* Set chip new ring index. */ @@ -1912,6 +1913,7 @@ qla24xx_dif_start_scsi(srb_t *sp) } else req->ring_ptr++; + sp->qpair->cmd_cnt++; /* Set chip new ring index. */ wrt_reg_dword(req->req_q_in, req->ring_index); @@ -2068,6 +2070,7 @@ qla2xxx_start_scsi_mq(srb_t *sp) } else req->ring_ptr++; + sp->qpair->cmd_cnt++; sp->flags |= SRB_DMA_VALID; /* Set chip new ring index. */ @@ -2284,6 +2287,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) } else req->ring_ptr++; + sp->qpair->cmd_cnt++; /* Set chip new ring index. */ wrt_reg_dword(req->req_q_in, req->ring_index); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 19fe2c1659d0..d9fb093a60a1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2322,6 +2322,8 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, if (unlikely(iocb->u.nvme.aen_op)) atomic_dec(&sp->vha->hw->nvme_active_aen_cnt); + else + sp->qpair->cmd_completion_cnt++; if (unlikely(comp_status != CS_COMPLETE)) logit = 1; @@ -2967,6 +2969,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } + sp->qpair->cmd_completion_cnt++; + /* Fast path completion. */ if (comp_status == CS_COMPLETE && scsi_status == 0) { qla2x00_process_completed_request(vha, req, handle); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 0bcd8afdc0ff..9f3ad8aa649c 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -6939,3 +6939,30 @@ ql26xx_led_config(scsi_qla_host_t *vha, uint16_t options, uint16_t *led) return rval; } + +/** + * qla_no_op_mb(): This MB is used to check if FW is still alive and + * able to generate an interrupt. Otherwise, a timeout will trigger + * FW dump + reset + * @vha: host adapter pointer + * Return: None + */ +void qla_no_op_mb(struct scsi_qla_host *vha) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + memset(&mc, 0, sizeof(mc)); + mcp->mb[0] = 0; // noop cmd= 0 + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 5; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval) { + ql_dbg(ql_dbg_async, vha, 0x7071, + "Failed %s %x\n", __func__, rval); + } +} diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index e119f8b24e33..3e5c70a1d969 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -536,6 +536,10 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) req->ring_ptr++; } + /* ignore nvme async cmd due to long timeout */ + if (!nvme->u.nvme.aen_op) + sp->qpair->cmd_cnt++; + /* Set chip new ring index. */ wrt_reg_dword(req->req_q_in, req->ring_index); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 4eab564ea6a0..cedd558f65eb 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6969,6 +6969,17 @@ intr_on_check: qla2x00_lip_reset(base_vha); } + if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) { + /* + * if there is a mb in progress then that's + * enough of a check to see if fw is still ticking. + */ + if (!ha->flags.mbox_busy && base_vha->flags.init_done) + qla_no_op_mb(base_vha); + + clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags); + } + ha->dpc_active = 0; end_loop: set_current_state(TASK_INTERRUPTIBLE); @@ -7025,6 +7036,61 @@ qla2x00_rst_aen(scsi_qla_host_t *vha) } } +static bool qla_do_heartbeat(struct scsi_qla_host *vha) +{ + u64 cmd_cnt, prev_cmd_cnt; + bool do_hb = false; + struct qla_hw_data *ha = vha->hw; + int i; + + /* if cmds are still pending down in fw, then do hb */ + if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) { + do_hb = true; + goto skip; + } + + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i] && + ha->queue_pair_map[i]->cmd_cnt != + ha->queue_pair_map[i]->cmd_completion_cnt) { + do_hb = true; + break; + } + } + +skip: + prev_cmd_cnt = ha->prev_cmd_cnt; + cmd_cnt = ha->base_qpair->cmd_cnt; + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + cmd_cnt += ha->queue_pair_map[i]->cmd_cnt; + } + ha->prev_cmd_cnt = cmd_cnt; + + if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50)) + /* + * IOs are completing before periodic hb check. + * IOs seems to be running, do hb for sanity check. + */ + do_hb = true; + + return do_hb; +} + +static void qla_heart_beat(struct scsi_qla_host *vha) +{ + if (vha->vp_idx) + return; + + if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) + return; + + if (qla_do_heartbeat(vha)) { + set_bit(HEARTBEAT_CHK, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } +} + /************************************************************************** * qla2x00_timer * @@ -7243,6 +7309,8 @@ qla2x00_timer(struct timer_list *t) qla2xxx_wake_dpc(vha); } + qla_heart_beat(vha); + qla2x00_restart_timer(vha, WATCH_INTERVAL); } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index c6cd5a8e5c85..58a252c38992 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1997,7 +1997,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) struct request *req; struct scsi_request *rq; - req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, 0); + req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN, 0); if (IS_ERR(req)) return; rq = scsi_req(req); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6b994baf87c2..8f9727e525aa 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -215,7 +215,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req = blk_get_request(sdev->request_queue, data_direction == DMA_TO_DEVICE ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0); if (IS_ERR(req)) return PTR_ERR(req); @@ -543,7 +543,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error, if (blk_queue_add_random(q)) add_disk_randomness(req->rq_disk); - if (!blk_rq_is_scsi(req)) { + if (!blk_rq_is_passthrough(req)) { WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED)); cmd->flags &= ~SCMD_INITIALIZED; } @@ -726,6 +726,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) case 0x07: /* operation in progress */ case 0x08: /* Long write in progress */ case 0x09: /* self test in progress */ + case 0x11: /* notify (enable spinup) required */ case 0x14: /* space allocation in progress */ case 0x1a: /* start stop unit in progress */ case 0x1b: /* sanitize in progress */ @@ -1113,7 +1114,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) bool in_flight; int budget_token = cmd->budget_token; - if (!blk_rq_is_scsi(rq) && !(flags & SCMD_INITIALIZED)) { + if (!blk_rq_is_passthrough(rq) && !(flags & SCMD_INITIALIZED)) { flags |= SCMD_INITIALIZED; scsi_initialize_rq(rq); } @@ -1554,7 +1555,7 @@ static blk_status_t scsi_prepare_cmd(struct request *req) * Special handling for passthrough commands, which don't go to the ULP * at all: */ - if (blk_rq_is_scsi(req)) + if (blk_rq_is_passthrough(req)) return scsi_setup_scsi_cmnd(sdev, req); if (sdev->handler && sdev->handler->prep_fn) { @@ -1897,18 +1898,6 @@ static const struct blk_mq_ops scsi_mq_ops = { .get_rq_budget_token = scsi_mq_get_rq_budget_token, }; -struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev) -{ - sdev->request_queue = blk_mq_init_queue(&sdev->host->tag_set); - if (IS_ERR(sdev->request_queue)) - return NULL; - - sdev->request_queue->queuedata = sdev; - __scsi_init_queue(sdev->host, sdev->request_queue); - blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, sdev->request_queue); - return sdev->request_queue; -} - int scsi_mq_setup_tags(struct Scsi_Host *shost) { unsigned int cmd_size, sgl_size; diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 75d6f23e4fff..eae2235f79b5 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -91,7 +91,6 @@ extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern void scsi_requeue_run_queue(struct work_struct *work); -extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev); extern void scsi_start_queue(struct scsi_device *sdev); extern int scsi_mq_setup_tags(struct Scsi_Host *shost); extern void scsi_mq_destroy_tags(struct Scsi_Host *shost); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 5ce45ef9808f..b059bf2b61d4 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -217,6 +217,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, { unsigned int depth; struct scsi_device *sdev; + struct request_queue *q; int display_failure_msg = 1, ret; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -266,16 +267,19 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, */ sdev->borken = 1; - sdev->request_queue = scsi_mq_alloc_queue(sdev); - if (!sdev->request_queue) { + q = blk_mq_init_queue(&sdev->host->tag_set); + if (IS_ERR(q)) { /* release fn is set up in scsi_sysfs_device_initialise, so * have to free and put manually here */ put_device(&starget->dev); kfree(sdev); goto out; } - WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); - sdev->request_queue->queuedata = sdev; + sdev->request_queue = q; + q->queuedata = sdev; + __scsi_init_queue(sdev->host, q); + blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q); + WARN_ON_ONCE(!blk_get_queue(q)); depth = sdev->host->cmd_per_lun ?: 1; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4e66994be190..91e2221bbb0d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1759,7 +1759,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) * not expect an EWOULDBLOCK from this condition. */ rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) { kfree(long_cmdp); return PTR_ERR(rq); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 66f48bd6da76..c6f14540ae03 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -549,7 +549,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, req = blk_get_request(SRpnt->stp->device->request_queue, data_direction == DMA_TO_DEVICE ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(req)) return PTR_ERR(req); rq = scsi_req(req); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e67bf76526cf..81ee0cd9b2aa 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8957,6 +8957,7 @@ out: return ret; } +#ifdef CONFIG_PM static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int ret; @@ -9083,6 +9084,7 @@ static int ufshcd_wl_runtime_resume(struct device *dev) return ret; } +#endif #ifdef CONFIG_PM_SLEEP static int ufshcd_wl_suspend(struct device *dev) @@ -9798,6 +9800,7 @@ static inline int ufshcd_clear_rpmb_uac(struct ufs_hba *hba) return ret; } +#ifdef CONFIG_PM static int ufshcd_rpmb_resume(struct device *dev) { struct ufs_hba *hba = wlun_dev_to_hba(dev); @@ -9806,6 +9809,7 @@ static int ufshcd_rpmb_resume(struct device *dev) ufshcd_clear_rpmb_uac(hba); return 0; } +#endif static const struct dev_pm_ops ufs_rpmb_pm_ops = { SET_RUNTIME_PM_OPS(NULL, ufshcd_rpmb_resume, NULL) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index fd69a03d6137..b0deaf4af5a3 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -97,7 +97,7 @@ static inline struct Scsi_Host *virtio_scsi_host(struct virtio_device *vdev) static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid) { if (resid) - scsi_set_resid(sc, resid); + scsi_set_resid(sc, min(resid, scsi_bufflen(sc))); } /* @@ -156,12 +156,11 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf) WARN_ON(virtio32_to_cpu(vscsi->vdev, resp->sense_len) > VIRTIO_SCSI_SENSE_SIZE); - if (sc->sense_buffer) { + if (resp->sense_len) { memcpy(sc->sense_buffer, resp->sense, min_t(u32, virtio32_to_cpu(vscsi->vdev, resp->sense_len), VIRTIO_SCSI_SENSE_SIZE)); - set_status_byte(sc, SAM_STAT_CHECK_CONDITION); } sc->scsi_done(sc); diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c index 50bf5d2b828b..2be3afe6c2e3 100644 --- a/drivers/soc/amlogic/meson-ee-pwrc.c +++ b/drivers/soc/amlogic/meson-ee-pwrc.c @@ -68,7 +68,7 @@ struct meson_ee_pwrc_domain_desc { struct meson_ee_pwrc_top_domain *top_pd; unsigned int mem_pd_count; struct meson_ee_pwrc_mem_domain *mem_pd; - bool (*get_power)(struct meson_ee_pwrc_domain *pwrc_domain); + bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain); }; struct meson_ee_pwrc_domain_data { @@ -217,7 +217,7 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = { { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) }, }; -#define VPU_PD(__name, __top_pd, __mem, __get_power, __resets, __clks) \ +#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \ { \ .name = __name, \ .reset_names_count = __resets, \ @@ -225,46 +225,46 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = { .top_pd = __top_pd, \ .mem_pd_count = ARRAY_SIZE(__mem), \ .mem_pd = __mem, \ - .get_power = __get_power, \ + .is_powered_off = __is_pwr_off, \ } -#define TOP_PD(__name, __top_pd, __mem, __get_power) \ +#define TOP_PD(__name, __top_pd, __mem, __is_pwr_off) \ { \ .name = __name, \ .top_pd = __top_pd, \ .mem_pd_count = ARRAY_SIZE(__mem), \ .mem_pd = __mem, \ - .get_power = __get_power, \ + .is_powered_off = __is_pwr_off, \ } #define MEM_PD(__name, __mem) \ TOP_PD(__name, NULL, __mem, NULL) -static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain); +static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain); static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = { [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu, - pwrc_ee_get_power, 5, 2), + pwrc_ee_is_powered_off, 5, 2), [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio), }; static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = { [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu, - pwrc_ee_get_power, 11, 2), + pwrc_ee_is_powered_off, 11, 2), [PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), }; static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = { [PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu, - pwrc_ee_get_power, 12, 2), + pwrc_ee_is_powered_off, 12, 2), [PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), }; static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = { [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu, - meson8_pwrc_mem_vpu, pwrc_ee_get_power, - 0, 1), + meson8_pwrc_mem_vpu, + pwrc_ee_is_powered_off, 0, 1), [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM", meson_pwrc_mem_eth), [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM", @@ -273,8 +273,8 @@ static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = { static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = { [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu, - meson8_pwrc_mem_vpu, pwrc_ee_get_power, - 11, 1), + meson8_pwrc_mem_vpu, + pwrc_ee_is_powered_off, 11, 1), [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM", meson_pwrc_mem_eth), [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM", @@ -283,15 +283,15 @@ static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = { static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = { [PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu, - pwrc_ee_get_power, 11, 2), + pwrc_ee_is_powered_off, 11, 2), [PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna, - pwrc_ee_get_power), + pwrc_ee_is_powered_off), [PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb, - pwrc_ee_get_power), + pwrc_ee_is_powered_off), [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie, - pwrc_ee_get_power), + pwrc_ee_is_powered_off), [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d, - pwrc_ee_get_power), + pwrc_ee_is_powered_off), [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio), [PWRC_SM1_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), }; @@ -314,7 +314,7 @@ struct meson_ee_pwrc { struct genpd_onecell_data xlate; }; -static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain) +static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain) { u32 reg; @@ -445,7 +445,7 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev, * we need to power the domain off, otherwise the internal clocks * prepare/enable counters won't be in sync. */ - if (dom->num_clks && dom->desc.get_power && !dom->desc.get_power(dom)) { + if (dom->num_clks && dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) { ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks); if (ret) return ret; @@ -456,8 +456,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev, return ret; } else { ret = pm_genpd_init(&dom->base, NULL, - (dom->desc.get_power ? - dom->desc.get_power(dom) : true)); + (dom->desc.is_powered_off ? + dom->desc.is_powered_off(dom) : true)); if (ret) return ret; } @@ -536,7 +536,7 @@ static void meson_ee_pwrc_shutdown(struct platform_device *pdev) for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) { struct meson_ee_pwrc_domain *dom = &pwrc->domains[i]; - if (dom->desc.get_power && !dom->desc.get_power(dom)) + if (dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) meson_ee_pwrc_off(&dom->base); } } diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c index e87dfc6660f3..2a010881f4b6 100644 --- a/drivers/soc/bcm/brcmstb/common.c +++ b/drivers/soc/bcm/brcmstb/common.c @@ -14,11 +14,6 @@ static u32 family_id; static u32 product_id; -static const struct of_device_id brcmstb_machine_match[] = { - { .compatible = "brcm,brcmstb", }, - { } -}; - u32 brcmstb_get_family_id(void) { return family_id; diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index db7e7fc321b1..34a9ac1f2b9b 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -12,11 +12,15 @@ #include #include #include +#include #include #include +#include #include #include #include +#include +#include #define GPC_LPCR_A_CORE_BSC 0x000 @@ -42,6 +46,25 @@ #define IMX8M_PCIE1_A53_DOMAIN BIT(3) #define IMX8M_MIPI_A53_DOMAIN BIT(2) +#define IMX8MM_VPUH1_A53_DOMAIN BIT(15) +#define IMX8MM_VPUG2_A53_DOMAIN BIT(14) +#define IMX8MM_VPUG1_A53_DOMAIN BIT(13) +#define IMX8MM_DISPMIX_A53_DOMAIN BIT(12) +#define IMX8MM_VPUMIX_A53_DOMAIN BIT(10) +#define IMX8MM_GPUMIX_A53_DOMAIN BIT(9) +#define IMX8MM_GPU_A53_DOMAIN (BIT(8) | BIT(11)) +#define IMX8MM_DDR1_A53_DOMAIN BIT(7) +#define IMX8MM_OTG2_A53_DOMAIN BIT(5) +#define IMX8MM_OTG1_A53_DOMAIN BIT(4) +#define IMX8MM_PCIE_A53_DOMAIN BIT(3) +#define IMX8MM_MIPI_A53_DOMAIN BIT(2) + +#define IMX8MN_DISPMIX_A53_DOMAIN BIT(12) +#define IMX8MN_GPUMIX_A53_DOMAIN BIT(9) +#define IMX8MN_DDR1_A53_DOMAIN BIT(7) +#define IMX8MN_OTG1_A53_DOMAIN BIT(4) +#define IMX8MN_MIPI_A53_DOMAIN BIT(2) + #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 #define GPC_PU_PGC_SW_PDN_REQ 0x104 @@ -65,14 +88,55 @@ #define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) #define IMX8M_MIPI_SW_Pxx_REQ BIT(0) +#define IMX8MM_VPUH1_SW_Pxx_REQ BIT(13) +#define IMX8MM_VPUG2_SW_Pxx_REQ BIT(12) +#define IMX8MM_VPUG1_SW_Pxx_REQ BIT(11) +#define IMX8MM_DISPMIX_SW_Pxx_REQ BIT(10) +#define IMX8MM_VPUMIX_SW_Pxx_REQ BIT(8) +#define IMX8MM_GPUMIX_SW_Pxx_REQ BIT(7) +#define IMX8MM_GPU_SW_Pxx_REQ (BIT(6) | BIT(9)) +#define IMX8MM_DDR1_SW_Pxx_REQ BIT(5) +#define IMX8MM_OTG2_SW_Pxx_REQ BIT(3) +#define IMX8MM_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8MM_PCIE_SW_Pxx_REQ BIT(1) +#define IMX8MM_MIPI_SW_Pxx_REQ BIT(0) + +#define IMX8MN_DISPMIX_SW_Pxx_REQ BIT(10) +#define IMX8MN_GPUMIX_SW_Pxx_REQ BIT(7) +#define IMX8MN_DDR1_SW_Pxx_REQ BIT(5) +#define IMX8MN_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0) + #define GPC_M4_PU_PDN_FLG 0x1bc #define GPC_PU_PWRHSK 0x1fc +#define IMX8M_GPU_HSK_PWRDNACKN BIT(26) +#define IMX8M_VPU_HSK_PWRDNACKN BIT(25) +#define IMX8M_DISP_HSK_PWRDNACKN BIT(24) #define IMX8M_GPU_HSK_PWRDNREQN BIT(6) #define IMX8M_VPU_HSK_PWRDNREQN BIT(5) #define IMX8M_DISP_HSK_PWRDNREQN BIT(4) + +#define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29) +#define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28)) +#define IMX8MM_VPUMIX_HSK_PWRDNACKN BIT(26) +#define IMX8MM_DISPMIX_HSK_PWRDNACKN BIT(25) +#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24)) +#define IMX8MM_GPUMIX_HSK_PWRDNREQN BIT(11) +#define IMX8MM_GPU_HSK_PWRDNREQN (BIT(9) | BIT(10)) +#define IMX8MM_VPUMIX_HSK_PWRDNREQN BIT(8) +#define IMX8MM_DISPMIX_HSK_PWRDNREQN BIT(7) +#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6)) + +#define IMX8MN_GPUMIX_HSK_PWRDNACKN (BIT(29) | BIT(27)) +#define IMX8MN_DISPMIX_HSK_PWRDNACKN BIT(25) +#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23) +#define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9)) +#define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7) +#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5) + /* * The PGC offset values in Reference Manual * (Rev. 1, 01/2018 and the older ones) GPC chapter's @@ -95,18 +159,37 @@ #define IMX8M_PGC_MIPI_CSI2 28 #define IMX8M_PGC_PCIE2 29 +#define IMX8MM_PGC_MIPI 16 +#define IMX8MM_PGC_PCIE 17 +#define IMX8MM_PGC_OTG1 18 +#define IMX8MM_PGC_OTG2 19 +#define IMX8MM_PGC_DDR1 21 +#define IMX8MM_PGC_GPU2D 22 +#define IMX8MM_PGC_GPUMIX 23 +#define IMX8MM_PGC_VPUMIX 24 +#define IMX8MM_PGC_GPU3D 25 +#define IMX8MM_PGC_DISPMIX 26 +#define IMX8MM_PGC_VPUG1 27 +#define IMX8MM_PGC_VPUG2 28 +#define IMX8MM_PGC_VPUH1 29 + +#define IMX8MN_PGC_MIPI 16 +#define IMX8MN_PGC_OTG1 18 +#define IMX8MN_PGC_DDR1 21 +#define IMX8MN_PGC_GPUMIX 23 +#define IMX8MN_PGC_DISPMIX 26 + #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) #define GPC_PGC_CTRL_PCR BIT(0) -#define GPC_CLK_MAX 6 - struct imx_pgc_domain { struct generic_pm_domain genpd; struct regmap *regmap; struct regulator *regulator; - struct clk *clk[GPC_CLK_MAX]; + struct reset_control *reset; + struct clk_bulk_data *clks; int num_clks; unsigned int pgc; @@ -114,7 +197,8 @@ struct imx_pgc_domain { const struct { u32 pxx; u32 map; - u32 hsk; + u32 hskreq; + u32 hskack; } bits; const int voltage; @@ -127,96 +211,172 @@ struct imx_pgc_domain_data { const struct regmap_access_table *reg_access_table; }; -static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, - bool on) +static inline struct imx_pgc_domain * +to_imx_pgc_domain(struct generic_pm_domain *genpd) { - struct imx_pgc_domain *domain = container_of(genpd, - struct imx_pgc_domain, - genpd); - unsigned int offset = on ? - GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; - const bool enable_power_control = !on; - const bool has_regulator = !IS_ERR(domain->regulator); - int i, ret = 0; - u32 pxx_req; + return container_of(genpd, struct imx_pgc_domain, genpd); +} - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, - domain->bits.map, domain->bits.map); +static int imx_pgc_power_up(struct generic_pm_domain *genpd) +{ + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); + u32 reg_val; + int ret; - if (has_regulator && on) { + ret = pm_runtime_get_sync(domain->dev); + if (ret < 0) { + pm_runtime_put_noidle(domain->dev); + return ret; + } + + if (!IS_ERR(domain->regulator)) { ret = regulator_enable(domain->regulator); if (ret) { dev_err(domain->dev, "failed to enable regulator\n"); - goto unmap; + goto out_put_pm; } } /* Enable reset clocks for all devices in the domain */ - for (i = 0; i < domain->num_clks; i++) - clk_prepare_enable(domain->clk[i]); - - if (enable_power_control) - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), - GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); - - if (domain->bits.hsk) - regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, - domain->bits.hsk, on ? domain->bits.hsk : 0); - - regmap_update_bits(domain->regmap, offset, - domain->bits.pxx, domain->bits.pxx); - - /* - * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait - * for PUP_REQ/PDN_REQ bit to be cleared - */ - ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req, - !(pxx_req & domain->bits.pxx), - 0, USEC_PER_MSEC); + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); if (ret) { - dev_err(domain->dev, "failed to command PGC\n"); - /* - * If we were in a process of enabling a - * domain and failed we might as well disable - * the regulator we just enabled. And if it - * was the opposite situation and we failed to - * power down -- keep the regulator on - */ - on = !on; + dev_err(domain->dev, "failed to enable reset clocks\n"); + goto out_regulator_disable; } - if (enable_power_control) - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), - GPC_PGC_CTRL_PCR, 0); + if (domain->bits.pxx) { + /* request the domain to power up */ + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ, + domain->bits.pxx, domain->bits.pxx); + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + ret = regmap_read_poll_timeout(domain->regmap, + GPC_PU_PGC_SW_PUP_REQ, reg_val, + !(reg_val & domain->bits.pxx), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to command PGC\n"); + goto out_clk_disable; + } + + /* disable power control */ + regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR); + } + + reset_control_assert(domain->reset); + + /* delay for reset to propagate */ + udelay(5); + + reset_control_deassert(domain->reset); + + /* request the ADB400 to power up */ + if (domain->bits.hskreq) { + regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, + domain->bits.hskreq, domain->bits.hskreq); + + /* + * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val, + * (reg_val & domain->bits.hskack), 0, + * USEC_PER_MSEC); + * Technically we need the commented code to wait handshake. But that needs + * the BLK-CTL module BUS clk-en bit being set. + * + * There is a separate BLK-CTL module and we will have such a driver for it, + * that driver will set the BUS clk-en bit and handshake will be triggered + * automatically there. Just add a delay and suppose the handshake finish + * after that. + */ + } /* Disable reset clocks for all devices in the domain */ - for (i = 0; i < domain->num_clks; i++) - clk_disable_unprepare(domain->clk[i]); + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); - if (has_regulator && !on) { - int err; + return 0; + +out_clk_disable: + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); +out_regulator_disable: + if (!IS_ERR(domain->regulator)) + regulator_disable(domain->regulator); +out_put_pm: + pm_runtime_put(domain->dev); - err = regulator_disable(domain->regulator); - if (err) - dev_err(domain->dev, - "failed to disable regulator: %d\n", err); - /* Preserve earlier error code */ - ret = ret ?: err; - } -unmap: - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, - domain->bits.map, 0); return ret; } -static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd) +static int imx_pgc_power_down(struct generic_pm_domain *genpd) { - return imx_gpc_pu_pgc_sw_pxx_req(genpd, true); -} + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); + u32 reg_val; + int ret; -static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) -{ - return imx_gpc_pu_pgc_sw_pxx_req(genpd, false); + /* Enable reset clocks for all devices in the domain */ + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); + if (ret) { + dev_err(domain->dev, "failed to enable reset clocks\n"); + return ret; + } + + /* request the ADB400 to power down */ + if (domain->bits.hskreq) { + regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK, + domain->bits.hskreq); + + ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, + reg_val, + !(reg_val & domain->bits.hskack), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to power down ADB400\n"); + goto out_clk_disable; + } + } + + if (domain->bits.pxx) { + /* enable power control */ + regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); + + /* request the domain to power down */ + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ, + domain->bits.pxx, domain->bits.pxx); + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + ret = regmap_read_poll_timeout(domain->regmap, + GPC_PU_PGC_SW_PDN_REQ, reg_val, + !(reg_val & domain->bits.pxx), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to command PGC\n"); + goto out_clk_disable; + } + } + + /* Disable reset clocks for all devices in the domain */ + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + if (!IS_ERR(domain->regulator)) { + ret = regulator_disable(domain->regulator); + if (ret) { + dev_err(domain->dev, "failed to disable regulator\n"); + return ret; + } + } + + pm_runtime_put(domain->dev); + + return 0; + +out_clk_disable: + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + return ret; } static const struct imx_pgc_domain imx7_pgc_domains[] = { @@ -342,7 +502,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_GPU_SW_Pxx_REQ, .map = IMX8M_GPU_A53_DOMAIN, - .hsk = IMX8M_GPU_HSK_PWRDNREQN, + .hskreq = IMX8M_GPU_HSK_PWRDNREQN, + .hskack = IMX8M_GPU_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_GPU, }, @@ -354,7 +515,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_VPU_SW_Pxx_REQ, .map = IMX8M_VPU_A53_DOMAIN, - .hsk = IMX8M_VPU_HSK_PWRDNREQN, + .hskreq = IMX8M_VPU_HSK_PWRDNREQN, + .hskack = IMX8M_VPU_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_VPU, }, @@ -366,7 +528,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_DISP_SW_Pxx_REQ, .map = IMX8M_DISP_A53_DOMAIN, - .hsk = IMX8M_DISP_HSK_PWRDNREQN, + .hskreq = IMX8M_DISP_HSK_PWRDNREQN, + .hskack = IMX8M_DISP_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_DISP, }, @@ -443,40 +606,254 @@ static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { .reg_access_table = &imx8m_access_table, }; -static int imx_pgc_get_clocks(struct imx_pgc_domain *domain) -{ - int i, ret; +static const struct imx_pgc_domain imx8mm_pgc_domains[] = { + [IMX8MM_POWER_DOMAIN_HSIOMIX] = { + .genpd = { + .name = "hsiomix", + }, + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MM_HSIO_HSK_PWRDNACKN, + }, + }, - for (i = 0; ; i++) { - struct clk *clk = of_clk_get(domain->dev->of_node, i); - if (IS_ERR(clk)) - break; - if (i >= GPC_CLK_MAX) { - dev_err(domain->dev, "more than %d clocks\n", - GPC_CLK_MAX); - ret = -EINVAL; - goto clk_err; - } - domain->clk[i] = clk; - } - domain->num_clks = i; + [IMX8MM_POWER_DOMAIN_PCIE] = { + .genpd = { + .name = "pcie", + }, + .bits = { + .pxx = IMX8MM_PCIE_SW_Pxx_REQ, + .map = IMX8MM_PCIE_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_PCIE, + }, - return 0; + [IMX8MM_POWER_DOMAIN_OTG1] = { + .genpd = { + .name = "usb-otg1", + }, + .bits = { + .pxx = IMX8MM_OTG1_SW_Pxx_REQ, + .map = IMX8MM_OTG1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_OTG1, + }, -clk_err: - while (i--) - clk_put(domain->clk[i]); + [IMX8MM_POWER_DOMAIN_OTG2] = { + .genpd = { + .name = "usb-otg2", + }, + .bits = { + .pxx = IMX8MM_OTG2_SW_Pxx_REQ, + .map = IMX8MM_OTG2_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_OTG2, + }, - return ret; -} + [IMX8MM_POWER_DOMAIN_GPUMIX] = { + .genpd = { + .name = "gpumix", + }, + .bits = { + .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ, + .map = IMX8MM_GPUMIX_A53_DOMAIN, + .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_GPUMIX, + }, -static void imx_pgc_put_clocks(struct imx_pgc_domain *domain) -{ - int i; + [IMX8MM_POWER_DOMAIN_GPU] = { + .genpd = { + .name = "gpu", + }, + .bits = { + .pxx = IMX8MM_GPU_SW_Pxx_REQ, + .map = IMX8MM_GPU_A53_DOMAIN, + .hskreq = IMX8MM_GPU_HSK_PWRDNREQN, + .hskack = IMX8MM_GPU_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_GPU2D, + }, - for (i = domain->num_clks - 1; i >= 0; i--) - clk_put(domain->clk[i]); -} + [IMX8MM_POWER_DOMAIN_VPUMIX] = { + .genpd = { + .name = "vpumix", + }, + .bits = { + .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ, + .map = IMX8MM_VPUMIX_A53_DOMAIN, + .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_VPUMIX, + }, + + [IMX8MM_POWER_DOMAIN_VPUG1] = { + .genpd = { + .name = "vpu-g1", + }, + .bits = { + .pxx = IMX8MM_VPUG1_SW_Pxx_REQ, + .map = IMX8MM_VPUG1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUG1, + }, + + [IMX8MM_POWER_DOMAIN_VPUG2] = { + .genpd = { + .name = "vpu-g2", + }, + .bits = { + .pxx = IMX8MM_VPUG2_SW_Pxx_REQ, + .map = IMX8MM_VPUG2_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUG2, + }, + + [IMX8MM_POWER_DOMAIN_VPUH1] = { + .genpd = { + .name = "vpu-h1", + }, + .bits = { + .pxx = IMX8MM_VPUH1_SW_Pxx_REQ, + .map = IMX8MM_VPUH1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUH1, + }, + + [IMX8MM_POWER_DOMAIN_DISPMIX] = { + .genpd = { + .name = "dispmix", + }, + .bits = { + .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ, + .map = IMX8MM_DISPMIX_A53_DOMAIN, + .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_DISPMIX, + }, + + [IMX8MM_POWER_DOMAIN_MIPI] = { + .genpd = { + .name = "mipi", + }, + .bits = { + .pxx = IMX8MM_MIPI_SW_Pxx_REQ, + .map = IMX8MM_MIPI_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_MIPI, + }, +}; + +static const struct regmap_range imx8mm_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_PU_PWRHSK), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_MIPI), + GPC_PGC_SR(IMX8MM_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_PCIE), + GPC_PGC_SR(IMX8MM_PGC_PCIE)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG1), + GPC_PGC_SR(IMX8MM_PGC_OTG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG2), + GPC_PGC_SR(IMX8MM_PGC_OTG2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DDR1), + GPC_PGC_SR(IMX8MM_PGC_DDR1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU2D), + GPC_PGC_SR(IMX8MM_PGC_GPU2D)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPUMIX), + GPC_PGC_SR(IMX8MM_PGC_GPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUMIX), + GPC_PGC_SR(IMX8MM_PGC_VPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU3D), + GPC_PGC_SR(IMX8MM_PGC_GPU3D)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DISPMIX), + GPC_PGC_SR(IMX8MM_PGC_DISPMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG1), + GPC_PGC_SR(IMX8MM_PGC_VPUG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG2), + GPC_PGC_SR(IMX8MM_PGC_VPUG2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUH1), + GPC_PGC_SR(IMX8MM_PGC_VPUH1)), +}; + +static const struct regmap_access_table imx8mm_access_table = { + .yes_ranges = imx8mm_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx8mm_yes_ranges), +}; + +static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = { + .domains = imx8mm_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mm_pgc_domains), + .reg_access_table = &imx8mm_access_table, +}; + +static const struct imx_pgc_domain imx8mn_pgc_domains[] = { + [IMX8MN_POWER_DOMAIN_HSIOMIX] = { + .genpd = { + .name = "hsiomix", + }, + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MN_HSIO_HSK_PWRDNACKN, + }, + }, + + [IMX8MN_POWER_DOMAIN_OTG1] = { + .genpd = { + .name = "usb-otg1", + }, + .bits = { + .pxx = IMX8MN_OTG1_SW_Pxx_REQ, + .map = IMX8MN_OTG1_A53_DOMAIN, + }, + .pgc = IMX8MN_PGC_OTG1, + }, + + [IMX8MN_POWER_DOMAIN_GPUMIX] = { + .genpd = { + .name = "gpumix", + }, + .bits = { + .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ, + .map = IMX8MN_GPUMIX_A53_DOMAIN, + .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MN_PGC_GPUMIX, + }, +}; + +static const struct regmap_range imx8mn_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_PU_PWRHSK), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_MIPI), + GPC_PGC_SR(IMX8MN_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_OTG1), + GPC_PGC_SR(IMX8MN_PGC_OTG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DDR1), + GPC_PGC_SR(IMX8MN_PGC_DDR1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_GPUMIX), + GPC_PGC_SR(IMX8MN_PGC_GPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DISPMIX), + GPC_PGC_SR(IMX8MN_PGC_DISPMIX)), +}; + +static const struct regmap_access_table imx8mn_access_table = { + .yes_ranges = imx8mn_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx8mn_yes_ranges), +}; + +static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = { + .domains = imx8mn_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mn_pgc_domains), + .reg_access_table = &imx8mn_access_table, +}; static int imx_pgc_domain_probe(struct platform_device *pdev) { @@ -495,25 +872,45 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) domain->voltage, domain->voltage); } - ret = imx_pgc_get_clocks(domain); - if (ret) - return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n"); + domain->num_clks = devm_clk_bulk_get_all(domain->dev, &domain->clks); + if (domain->num_clks < 0) + return dev_err_probe(domain->dev, domain->num_clks, + "Failed to get domain's clocks\n"); + + domain->reset = devm_reset_control_array_get_optional_exclusive(domain->dev); + if (IS_ERR(domain->reset)) + return dev_err_probe(domain->dev, PTR_ERR(domain->reset), + "Failed to get domain's resets\n"); + + pm_runtime_enable(domain->dev); + + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, domain->bits.map); ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) { dev_err(domain->dev, "Failed to init power domain\n"); - imx_pgc_put_clocks(domain); - return ret; + goto out_domain_unmap; } ret = of_genpd_add_provider_simple(domain->dev->of_node, &domain->genpd); if (ret) { dev_err(domain->dev, "Failed to add genpd provider\n"); - pm_genpd_remove(&domain->genpd); - imx_pgc_put_clocks(domain); + goto out_genpd_remove; } + return 0; + +out_genpd_remove: + pm_genpd_remove(&domain->genpd); +out_domain_unmap: + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, 0); + pm_runtime_disable(domain->dev); + return ret; } @@ -523,7 +920,12 @@ static int imx_pgc_domain_remove(struct platform_device *pdev) of_genpd_del_provider(domain->dev->of_node); pm_genpd_remove(&domain->genpd); - imx_pgc_put_clocks(domain); + + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, 0); + + pm_runtime_disable(domain->dev); return 0; } @@ -617,8 +1019,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev) domain = pd_pdev->dev.platform_data; domain->regmap = regmap; - domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req; - domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req; + domain->genpd.power_on = imx_pgc_power_up; + domain->genpd.power_off = imx_pgc_power_down; pd_pdev->dev.parent = dev; pd_pdev->dev.of_node = np; @@ -636,6 +1038,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev) static const struct of_device_id imx_gpcv2_dt_ids[] = { { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, + { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, }, + { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, }, { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, { } }; diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c index 0738c0f36792..ac6d856ba228 100644 --- a/drivers/soc/imx/soc-imx.c +++ b/drivers/soc/imx/soc-imx.c @@ -70,6 +70,9 @@ static int __init imx_soc_device_init(void) case MXC_CPU_MX35: soc_id = "i.MX35"; break; + case MXC_CPU_MX50: + soc_id = "i.MX50"; + break; case MXC_CPU_MX51: ocotp_compat = "fsl,imx51-iim"; soc_id = "i.MX51"; diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 3c158251a58b..7bd19354982a 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #define DEBUG_MSG 0 #define DEBUG_FW 0 diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index 8c968382cea7..7149510b307e 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include static struct qmgr_regs __iomem *qmgr_regs; static int qmgr_irq_1; diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig index e7011d665b15..e6ba3573a772 100644 --- a/drivers/soc/litex/Kconfig +++ b/drivers/soc/litex/Kconfig @@ -17,16 +17,4 @@ config LITEX_SOC_CONTROLLER All drivers that use functions from litex.h must depend on LITEX. -config LITEX_SUBREG_SIZE - int "Size of a LiteX CSR subregister, in bytes" - depends on LITEX - range 1 4 - default 4 - help - LiteX MMIO registers (referred to as Configuration and Status - registers, or CSRs) are spread across adjacent 8- or 32-bit - subregisters, located at 32-bit aligned MMIO addresses. Use - this to select the appropriate size (1 or 4 bytes) matching - your particular LiteX build. - endmenu diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c index c3e379a990f2..f75790091d38 100644 --- a/drivers/soc/litex/litex_soc_ctrl.c +++ b/drivers/soc/litex/litex_soc_ctrl.c @@ -62,8 +62,7 @@ static int litex_check_csr_access(void __iomem *reg_addr) /* restore original value of the SCRATCH register */ litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE); - pr_info("LiteX SoC Controller driver initialized: subreg:%d, align:%d", - LITEX_SUBREG_SIZE, LITEX_SUBREG_ALIGN); + pr_info("LiteX SoC Controller driver initialized"); return 0; } diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c index f1cea041dc5a..7c65ad3d1f8a 100644 --- a/drivers/soc/mediatek/mtk-devapc.c +++ b/drivers/soc/mediatek/mtk-devapc.c @@ -234,6 +234,7 @@ static const struct of_device_id mtk_devapc_dt_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match); static int mtk_devapc_probe(struct platform_device *pdev) { diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 0af00efa0ef8..b762bc40f56b 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -211,7 +211,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) if (ret) return ret; - ret = clk_bulk_enable(pd->num_clks, pd->clks); + ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks); if (ret) goto err_reg; @@ -229,7 +229,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); - ret = clk_bulk_enable(pd->num_subsys_clks, pd->subsys_clks); + ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks); if (ret) goto err_pwr_ack; @@ -246,9 +246,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) err_disable_sram: scpsys_sram_disable(pd); err_disable_subsys_clks: - clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); err_pwr_ack: - clk_bulk_disable(pd->num_clks, pd->clks); + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); err_reg: scpsys_regulator_disable(pd->supply); return ret; @@ -269,7 +269,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) if (ret < 0) return ret; - clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); + clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks); /* subsys power off */ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); @@ -284,7 +284,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) if (ret < 0) return ret; - clk_bulk_disable(pd->num_clks, pd->clks); + clk_bulk_disable_unprepare(pd->num_clks, pd->clks); scpsys_regulator_disable(pd->supply); @@ -297,6 +297,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no const struct scpsys_domain_data *domain_data; struct scpsys_domain *pd; struct device_node *root_node = scpsys->dev->of_node; + struct device_node *smi_node; struct property *prop; const char *clk_name; int i, ret, num_clks; @@ -352,9 +353,13 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no if (IS_ERR(pd->infracfg)) return ERR_CAST(pd->infracfg); - pd->smi = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,smi"); - if (IS_ERR(pd->smi)) - return ERR_CAST(pd->smi); + smi_node = of_parse_phandle(node, "mediatek,smi", 0); + if (smi_node) { + pd->smi = device_node_to_regmap(smi_node); + of_node_put(smi_node); + if (IS_ERR(pd->smi)) + return ERR_CAST(pd->smi); + } num_clks = of_clk_get_parent_count(node); if (num_clks > 0) { @@ -405,14 +410,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no pd->subsys_clks[i].clk = clk; } - ret = clk_bulk_prepare(pd->num_clks, pd->clks); - if (ret) - goto err_put_subsys_clocks; - - ret = clk_bulk_prepare(pd->num_subsys_clks, pd->subsys_clks); - if (ret) - goto err_unprepare_clocks; - /* * Initially turn on all domains to make the domains usable * with !CONFIG_PM and to get the hardware in sync with the @@ -427,7 +424,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no ret = scpsys_power_on(&pd->genpd); if (ret < 0) { dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); - goto err_unprepare_clocks; + goto err_put_subsys_clocks; } } @@ -435,7 +432,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no ret = -EINVAL; dev_err(scpsys->dev, "power domain with id %d already exists, check your device-tree\n", id); - goto err_unprepare_subsys_clocks; + goto err_put_subsys_clocks; } if (!pd->data->name) @@ -455,10 +452,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no return scpsys->pd_data.domains[id]; -err_unprepare_subsys_clocks: - clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); -err_unprepare_clocks: - clk_bulk_unprepare(pd->num_clks, pd->clks); err_put_subsys_clocks: clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); err_put_clocks: @@ -537,10 +530,7 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) "failed to remove domain '%s' : %d - state may be inconsistent\n", pd->genpd.name, ret); - clk_bulk_unprepare(pd->num_clks, pd->clks); clk_bulk_put(pd->num_clks, pd->clks); - - clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); } diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index e4de75f35c33..952bc554f443 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -961,6 +961,23 @@ static int mt8183_regs[] = { [PWRAP_WACS2_VLDCLR] = 0xC28, }; +static int mt8195_regs[] = { + [PWRAP_INIT_DONE2] = 0x0, + [PWRAP_STAUPD_CTRL] = 0x4C, + [PWRAP_TIMER_EN] = 0x3E4, + [PWRAP_INT_EN] = 0x420, + [PWRAP_INT_FLG] = 0x428, + [PWRAP_INT_CLR] = 0x42C, + [PWRAP_INT1_EN] = 0x450, + [PWRAP_INT1_FLG] = 0x458, + [PWRAP_INT1_CLR] = 0x45C, + [PWRAP_WACS2_CMD] = 0x880, + [PWRAP_SWINF_2_WDATA_31_0] = 0x884, + [PWRAP_SWINF_2_RDATA_31_0] = 0x894, + [PWRAP_WACS2_VLDCLR] = 0x8A4, + [PWRAP_WACS2_RDATA] = 0x8A8, +}; + static int mt8516_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -1066,6 +1083,7 @@ enum pwrap_type { PWRAP_MT8135, PWRAP_MT8173, PWRAP_MT8183, + PWRAP_MT8195, PWRAP_MT8516, }; @@ -1525,6 +1543,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) break; case PWRAP_MT6873: case PWRAP_MT8183: + case PWRAP_MT8195: break; } @@ -2025,6 +2044,19 @@ static const struct pmic_wrapper_type pwrap_mt8183 = { .init_soc_specific = pwrap_mt8183_init_soc_specific, }; +static struct pmic_wrapper_type pwrap_mt8195 = { + .regs = mt8195_regs, + .type = PWRAP_MT8195, + .arb_en_all = 0x777f, /* NEED CONFIRM */ + .int_en_all = 0x180000, /* NEED CONFIRM */ + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + static struct pmic_wrapper_type pwrap_mt8516 = { .regs = mt8516_regs, .type = PWRAP_MT8516, @@ -2065,6 +2097,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { }, { .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183, + }, { + .compatible = "mediatek,mt8195-pwrap", + .data = &pwrap_mt8195, }, { .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516, diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index bb21c4f1c0c4..2daa17ba54a3 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -271,9 +271,30 @@ static const struct rpmhpd_desc sc7280_desc = { .num_pds = ARRAY_SIZE(sc7280_rpmhpds), }; +/* SC8180x RPMH powerdomains */ +static struct rpmhpd *sc8180x_rpmhpds[] = { + [SC8180X_CX] = &sdm845_cx, + [SC8180X_CX_AO] = &sdm845_cx_ao, + [SC8180X_EBI] = &sdm845_ebi, + [SC8180X_GFX] = &sdm845_gfx, + [SC8180X_LCX] = &sdm845_lcx, + [SC8180X_LMX] = &sdm845_lmx, + [SC8180X_MMCX] = &sm8150_mmcx, + [SC8180X_MMCX_AO] = &sm8150_mmcx_ao, + [SC8180X_MSS] = &sdm845_mss, + [SC8180X_MX] = &sdm845_mx, + [SC8180X_MX_AO] = &sdm845_mx_ao, +}; + +static const struct rpmhpd_desc sc8180x_desc = { + .rpmhpds = sc8180x_rpmhpds, + .num_pds = ARRAY_SIZE(sc8180x_rpmhpds), +}; + static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, + { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 27733b0e7fca..0b532a892d60 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -118,6 +118,27 @@ struct rpmpd_desc { static DEFINE_MUTEX(rpmpd_lock); +/* mdm9607 RPM Power Domains */ +DEFINE_RPMPD_PAIR(mdm9607, vddcx, vddcx_ao, SMPA, LEVEL, 3); +DEFINE_RPMPD_VFL(mdm9607, vddcx_vfl, SMPA, 3); + +DEFINE_RPMPD_PAIR(mdm9607, vddmx, vddmx_ao, LDOA, LEVEL, 12); +DEFINE_RPMPD_VFL(mdm9607, vddmx_vfl, LDOA, 12); +static struct rpmpd *mdm9607_rpmpds[] = { + [MDM9607_VDDCX] = &mdm9607_vddcx, + [MDM9607_VDDCX_AO] = &mdm9607_vddcx_ao, + [MDM9607_VDDCX_VFL] = &mdm9607_vddcx_vfl, + [MDM9607_VDDMX] = &mdm9607_vddmx, + [MDM9607_VDDMX_AO] = &mdm9607_vddmx_ao, + [MDM9607_VDDMX_VFL] = &mdm9607_vddmx_vfl, +}; + +static const struct rpmpd_desc mdm9607_desc = { + .rpmpds = mdm9607_rpmpds, + .num_pds = ARRAY_SIZE(mdm9607_rpmpds), + .max_state = RPM_SMD_LEVEL_TURBO, +}; + /* msm8939 RPM Power Domains */ DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1); DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1); @@ -326,6 +347,7 @@ static const struct rpmpd_desc sdm660_desc = { }; static const struct of_device_id rpmpd_match_table[] = { + { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index b93218cb50b5..bc0be1d4be5f 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -233,6 +233,7 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev) static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-apq8084" }, { .compatible = "qcom,rpm-ipq6018" }, + { .compatible = "qcom,rpm-msm8226" }, { .compatible = "qcom,rpm-msm8916" }, { .compatible = "qcom,rpm-msm8936" }, { .compatible = "qcom,rpm-msm8974" }, @@ -241,6 +242,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-msm8996" }, { .compatible = "qcom,rpm-msm8998" }, { .compatible = "qcom,rpm-sdm660" }, + { .compatible = "qcom,rpm-sm6125" }, { .compatible = "qcom,rpm-qcs404" }, {} }; diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c index d2b558438deb..31faf4aa868e 100644 --- a/drivers/soc/qcom/smem_state.c +++ b/drivers/soc/qcom/smem_state.c @@ -151,6 +151,42 @@ void qcom_smem_state_put(struct qcom_smem_state *state) } EXPORT_SYMBOL_GPL(qcom_smem_state_put); +static void devm_qcom_smem_state_release(struct device *dev, void *res) +{ + qcom_smem_state_put(*(struct qcom_smem_state **)res); +} + +/** + * devm_qcom_smem_state_get() - acquire handle to a devres managed state + * @dev: client device pointer + * @con_id: name of the state to lookup + * @bit: flags from the state reference, indicating which bit's affected + * + * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() is called + * automatically when @dev is removed. + */ +struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev, + const char *con_id, + unsigned *bit) +{ + struct qcom_smem_state **ptr, *state; + + ptr = devres_alloc(devm_qcom_smem_state_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + state = qcom_smem_state_get(dev, con_id, bit); + if (!IS_ERR(state)) { + *ptr = state; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return state; +} +EXPORT_SYMBOL_GPL(devm_qcom_smem_state_get); + /** * qcom_smem_state_register() - register a new state * @of_node: of_node used for matching client lookups diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index f6cfb79338f0..b2f049faa3df 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -70,21 +70,33 @@ static const char *const socinfo_image_names[] = { static const char *const pmic_models[] = { [0] = "Unknown PMIC model", + [1] = "PM8941", + [2] = "PM8841", + [3] = "PM8019", + [4] = "PM8226", + [5] = "PM8110", + [6] = "PMA8084", + [7] = "PMI8962", + [8] = "PMD9635", [9] = "PM8994", + [10] = "PMI8994", [11] = "PM8916", - [13] = "PM8058", + [12] = "PM8004", + [13] = "PM8909/PM8058", [14] = "PM8028", [15] = "PM8901", - [16] = "PM8027", - [17] = "ISL9519", + [16] = "PM8950/PM8027", + [17] = "PMI8950/ISL9519", [18] = "PM8921", [19] = "PM8018", - [20] = "PM8015", - [21] = "PM8014", + [20] = "PM8998/PM8015", + [21] = "PMI8998/PM8014", [22] = "PM8821", [23] = "PM8038", - [24] = "PM8922", + [24] = "PM8005/PM8922", [25] = "PM8917", + [26] = "PM660L", + [27] = "PM660", [30] = "PM8150", [31] = "PM8150L", [32] = "PM8150B", @@ -195,11 +207,30 @@ static const struct soc_id soc_id[] = { { 139, "APQ8060AB" }, { 140, "MSM8260AB" }, { 141, "MSM8660AB" }, + { 145, "MSM8626" }, + { 147, "MSM8610" }, + { 153, "APQ8064AB" }, + { 158, "MSM8226" }, + { 159, "MSM8526" }, + { 161, "MSM8110" }, + { 162, "MSM8210" }, + { 163, "MSM8810" }, + { 164, "MSM8212" }, + { 165, "MSM8612" }, + { 166, "MSM8112" }, + { 168, "MSM8225Q" }, + { 169, "MSM8625Q" }, + { 170, "MSM8125Q" }, + { 172, "APQ8064AA" }, { 178, "APQ8084" }, { 184, "APQ8074" }, { 185, "MSM8274" }, { 186, "MSM8674" }, { 194, "MSM8974PRO" }, + { 198, "MSM8126" }, + { 199, "APQ8026" }, + { 200, "MSM8926" }, + { 205, "MSM8326" }, { 206, "MSM8916" }, { 207, "MSM8994" }, { 208, "APQ8074-AA" }, @@ -213,6 +244,14 @@ static const struct soc_id soc_id[] = { { 216, "MSM8674PRO" }, { 217, "MSM8974-AA" }, { 218, "MSM8974-AB" }, + { 219, "APQ8028" }, + { 220, "MSM8128" }, + { 221, "MSM8228" }, + { 222, "MSM8528" }, + { 223, "MSM8628" }, + { 224, "MSM8928" }, + { 225, "MSM8510" }, + { 226, "MSM8512" }, { 233, "MSM8936" }, { 239, "MSM8939" }, { 240, "APQ8036" }, @@ -254,8 +293,13 @@ static const struct soc_id soc_id[] = { { 350, "SDA632" }, { 351, "SDA450" }, { 356, "SM8250" }, + { 394, "SM6125" }, { 402, "IPQ6018" }, + { 403, "IPQ6028" }, + { 421, "IPQ6000" }, + { 422, "IPQ6010" }, { 425, "SC7180" }, + { 453, "IPQ6005" }, { 455, "QRB5165" }, }; diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index b70bbc38efc6..71b44c31b012 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -279,6 +279,11 @@ config ARCH_R8A774B1 help This enables support for the Renesas RZ/G2N SoC. +config ARCH_R9A07G044 + bool "ARM64 Platform support for RZ/G2L" + help + This enables support for the Renesas RZ/G2L SoC variants. + endif # ARM64 config RST_RCAR diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 0f8eff4a641a..8310fce7714e 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -56,6 +56,10 @@ static const struct renesas_family fam_rzg2 __initconst __maybe_unused = { .reg = 0xfff00044, /* PRR (Product Register) */ }; +static const struct renesas_family fam_rzg2l __initconst __maybe_unused = { + .name = "RZ/G2L", +}; + static const struct renesas_family fam_shmobile __initconst __maybe_unused = { .name = "SH-Mobile", .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ @@ -64,7 +68,7 @@ static const struct renesas_family fam_shmobile __initconst __maybe_unused = { struct renesas_soc { const struct renesas_family *family; - u8 id; + u32 id; }; static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { @@ -131,6 +135,11 @@ static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = { .id = 0x4f, }; +static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = { + .family = &fam_rzg2l, + .id = 0x841c447, +}; + static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { .family = &fam_rcar_gen1, }; @@ -299,6 +308,9 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A779A0 { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u }, #endif +#if defined(CONFIG_ARCH_R9A07G044) + { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, +#endif #ifdef CONFIG_ARCH_SH73A0 { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, #endif @@ -348,6 +360,25 @@ static int __init renesas_soc_init(void) goto done; } + np = of_find_compatible_node(NULL, NULL, "renesas,r9a07g044-sysc"); + if (np) { + chipid = of_iomap(np, 0); + of_node_put(np); + + if (chipid) { + product = readl(chipid + 0x0a04); + iounmap(chipid); + + if (soc->id && (product & 0xfffffff) != soc->id) { + pr_warn("SoC mismatch (product = 0x%x)\n", + product); + return -ENODEV; + } + } + + goto done; + } + /* Try PRR first, then hardcoded fallback */ np = of_find_compatible_node(NULL, NULL, "renesas,prr"); if (np) { diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 54eb6cfc5d5b..0868b7d406fb 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -27,8 +27,10 @@ #include #include #include +#include struct rockchip_domain_info { + const char *name; int pwr_mask; int status_mask; int req_mask; @@ -85,8 +87,9 @@ struct rockchip_pmu { #define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd) -#define DOMAIN(pwr, status, req, idle, ack, wakeup) \ +#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup) \ { \ + .name = _name, \ .pwr_mask = (pwr), \ .status_mask = (status), \ .req_mask = (req), \ @@ -95,8 +98,9 @@ struct rockchip_pmu { .active_wakeup = (wakeup), \ } -#define DOMAIN_M(pwr, status, req, idle, ack, wakeup) \ +#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup) \ { \ + .name = _name, \ .pwr_w_mask = (pwr) << 16, \ .pwr_mask = (pwr), \ .status_mask = (status), \ @@ -107,8 +111,9 @@ struct rockchip_pmu { .active_wakeup = wakeup, \ } -#define DOMAIN_RK3036(req, ack, idle, wakeup) \ +#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \ { \ + .name = _name, \ .req_mask = (req), \ .req_w_mask = (req) << 16, \ .ack_mask = (ack), \ @@ -116,20 +121,23 @@ struct rockchip_pmu { .active_wakeup = wakeup, \ } -#define DOMAIN_PX30(pwr, status, req, wakeup) \ - DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup) +#define DOMAIN_PX30(name, pwr, status, req, wakeup) \ + DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup) -#define DOMAIN_RK3288(pwr, status, req, wakeup) \ - DOMAIN(pwr, status, req, req, (req) << 16, wakeup) +#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \ + DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup) -#define DOMAIN_RK3328(pwr, status, req, wakeup) \ - DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup) +#define DOMAIN_RK3328(name, pwr, status, req, wakeup) \ + DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup) -#define DOMAIN_RK3368(pwr, status, req, wakeup) \ - DOMAIN(pwr, status, req, (req) << 16, req, wakeup) +#define DOMAIN_RK3368(name, pwr, status, req, wakeup) \ + DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup) -#define DOMAIN_RK3399(pwr, status, req, wakeup) \ - DOMAIN(pwr, status, req, req, req, wakeup) +#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \ + DOMAIN(name, pwr, status, req, req, req, wakeup) + +#define DOMAIN_RK3568(name, pwr, req, wakeup) \ + DOMAIN_M(name, pwr, pwr, req, req, req, wakeup) static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) { @@ -490,7 +498,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, goto err_unprepare_clocks; } - pd->genpd.name = node->name; + if (pd->info->name) + pd->genpd.name = pd->info->name; + else + pd->genpd.name = kbasename(node->full_name); pd->genpd.power_off = rockchip_pd_power_off; pd->genpd.power_on = rockchip_pd_power_on; pd->genpd.attach_dev = rockchip_pd_attach_dev; @@ -716,129 +727,141 @@ err_out: } static const struct rockchip_domain_info px30_pm_domains[] = { - [PX30_PD_USB] = DOMAIN_PX30(BIT(5), BIT(5), BIT(10), false), - [PX30_PD_SDCARD] = DOMAIN_PX30(BIT(8), BIT(8), BIT(9), false), - [PX30_PD_GMAC] = DOMAIN_PX30(BIT(10), BIT(10), BIT(6), false), - [PX30_PD_MMC_NAND] = DOMAIN_PX30(BIT(11), BIT(11), BIT(5), false), - [PX30_PD_VPU] = DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false), - [PX30_PD_VO] = DOMAIN_PX30(BIT(13), BIT(13), BIT(7), false), - [PX30_PD_VI] = DOMAIN_PX30(BIT(14), BIT(14), BIT(8), false), - [PX30_PD_GPU] = DOMAIN_PX30(BIT(15), BIT(15), BIT(2), false), + [PX30_PD_USB] = DOMAIN_PX30("usb", BIT(5), BIT(5), BIT(10), false), + [PX30_PD_SDCARD] = DOMAIN_PX30("sdcard", BIT(8), BIT(8), BIT(9), false), + [PX30_PD_GMAC] = DOMAIN_PX30("gmac", BIT(10), BIT(10), BIT(6), false), + [PX30_PD_MMC_NAND] = DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5), false), + [PX30_PD_VPU] = DOMAIN_PX30("vpu", BIT(12), BIT(12), BIT(14), false), + [PX30_PD_VO] = DOMAIN_PX30("vo", BIT(13), BIT(13), BIT(7), false), + [PX30_PD_VI] = DOMAIN_PX30("vi", BIT(14), BIT(14), BIT(8), false), + [PX30_PD_GPU] = DOMAIN_PX30("gpu", BIT(15), BIT(15), BIT(2), false), }; static const struct rockchip_domain_info rk3036_pm_domains[] = { - [RK3036_PD_MSCH] = DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true), - [RK3036_PD_CORE] = DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false), - [RK3036_PD_PERI] = DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false), - [RK3036_PD_VIO] = DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false), - [RK3036_PD_VPU] = DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false), - [RK3036_PD_GPU] = DOMAIN_RK3036(BIT(9), BIT(21), BIT(28), false), - [RK3036_PD_SYS] = DOMAIN_RK3036(BIT(8), BIT(22), BIT(29), false), + [RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true), + [RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false), + [RK3036_PD_PERI] = DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false), + [RK3036_PD_VIO] = DOMAIN_RK3036("vio", BIT(11), BIT(19), BIT(26), false), + [RK3036_PD_VPU] = DOMAIN_RK3036("vpu", BIT(10), BIT(20), BIT(27), false), + [RK3036_PD_GPU] = DOMAIN_RK3036("gpu", BIT(9), BIT(21), BIT(28), false), + [RK3036_PD_SYS] = DOMAIN_RK3036("sys", BIT(8), BIT(22), BIT(29), false), }; static const struct rockchip_domain_info rk3066_pm_domains[] = { - [RK3066_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), - [RK3066_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), - [RK3066_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), - [RK3066_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), - [RK3066_PD_CPU] = DOMAIN(0, BIT(5), BIT(1), BIT(26), BIT(31), false), + [RK3066_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), + [RK3066_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), + [RK3066_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), + [RK3066_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), + [RK3066_PD_CPU] = DOMAIN("cpu", 0, BIT(5), BIT(1), BIT(26), BIT(31), false), }; static const struct rockchip_domain_info rk3128_pm_domains[] = { - [RK3128_PD_CORE] = DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false), - [RK3128_PD_MSCH] = DOMAIN_RK3288(0, 0, BIT(6), true), - [RK3128_PD_VIO] = DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false), - [RK3128_PD_VIDEO] = DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false), - [RK3128_PD_GPU] = DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false), + [RK3128_PD_CORE] = DOMAIN_RK3288("core", BIT(0), BIT(0), BIT(4), false), + [RK3128_PD_MSCH] = DOMAIN_RK3288("msch", 0, 0, BIT(6), true), + [RK3128_PD_VIO] = DOMAIN_RK3288("vio", BIT(3), BIT(3), BIT(2), false), + [RK3128_PD_VIDEO] = DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false), + [RK3128_PD_GPU] = DOMAIN_RK3288("gpu", BIT(1), BIT(1), BIT(3), false), }; static const struct rockchip_domain_info rk3188_pm_domains[] = { - [RK3188_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), - [RK3188_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), - [RK3188_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), - [RK3188_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), - [RK3188_PD_CPU] = DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false), + [RK3188_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), + [RK3188_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), + [RK3188_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), + [RK3188_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), + [RK3188_PD_CPU] = DOMAIN("cpu", BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false), }; static const struct rockchip_domain_info rk3228_pm_domains[] = { - [RK3228_PD_CORE] = DOMAIN_RK3036(BIT(0), BIT(0), BIT(16), true), - [RK3228_PD_MSCH] = DOMAIN_RK3036(BIT(1), BIT(1), BIT(17), true), - [RK3228_PD_BUS] = DOMAIN_RK3036(BIT(2), BIT(2), BIT(18), true), - [RK3228_PD_SYS] = DOMAIN_RK3036(BIT(3), BIT(3), BIT(19), true), - [RK3228_PD_VIO] = DOMAIN_RK3036(BIT(4), BIT(4), BIT(20), false), - [RK3228_PD_VOP] = DOMAIN_RK3036(BIT(5), BIT(5), BIT(21), false), - [RK3228_PD_VPU] = DOMAIN_RK3036(BIT(6), BIT(6), BIT(22), false), - [RK3228_PD_RKVDEC] = DOMAIN_RK3036(BIT(7), BIT(7), BIT(23), false), - [RK3228_PD_GPU] = DOMAIN_RK3036(BIT(8), BIT(8), BIT(24), false), - [RK3228_PD_PERI] = DOMAIN_RK3036(BIT(9), BIT(9), BIT(25), true), - [RK3228_PD_GMAC] = DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false), + [RK3228_PD_CORE] = DOMAIN_RK3036("core", BIT(0), BIT(0), BIT(16), true), + [RK3228_PD_MSCH] = DOMAIN_RK3036("msch", BIT(1), BIT(1), BIT(17), true), + [RK3228_PD_BUS] = DOMAIN_RK3036("bus", BIT(2), BIT(2), BIT(18), true), + [RK3228_PD_SYS] = DOMAIN_RK3036("sys", BIT(3), BIT(3), BIT(19), true), + [RK3228_PD_VIO] = DOMAIN_RK3036("vio", BIT(4), BIT(4), BIT(20), false), + [RK3228_PD_VOP] = DOMAIN_RK3036("vop", BIT(5), BIT(5), BIT(21), false), + [RK3228_PD_VPU] = DOMAIN_RK3036("vpu", BIT(6), BIT(6), BIT(22), false), + [RK3228_PD_RKVDEC] = DOMAIN_RK3036("vdec", BIT(7), BIT(7), BIT(23), false), + [RK3228_PD_GPU] = DOMAIN_RK3036("gpu", BIT(8), BIT(8), BIT(24), false), + [RK3228_PD_PERI] = DOMAIN_RK3036("peri", BIT(9), BIT(9), BIT(25), true), + [RK3228_PD_GMAC] = DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false), }; static const struct rockchip_domain_info rk3288_pm_domains[] = { - [RK3288_PD_VIO] = DOMAIN_RK3288(BIT(7), BIT(7), BIT(4), false), - [RK3288_PD_HEVC] = DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false), - [RK3288_PD_VIDEO] = DOMAIN_RK3288(BIT(8), BIT(8), BIT(3), false), - [RK3288_PD_GPU] = DOMAIN_RK3288(BIT(9), BIT(9), BIT(2), false), + [RK3288_PD_VIO] = DOMAIN_RK3288("vio", BIT(7), BIT(7), BIT(4), false), + [RK3288_PD_HEVC] = DOMAIN_RK3288("hevc", BIT(14), BIT(10), BIT(9), false), + [RK3288_PD_VIDEO] = DOMAIN_RK3288("video", BIT(8), BIT(8), BIT(3), false), + [RK3288_PD_GPU] = DOMAIN_RK3288("gpu", BIT(9), BIT(9), BIT(2), false), }; static const struct rockchip_domain_info rk3328_pm_domains[] = { - [RK3328_PD_CORE] = DOMAIN_RK3328(0, BIT(0), BIT(0), false), - [RK3328_PD_GPU] = DOMAIN_RK3328(0, BIT(1), BIT(1), false), - [RK3328_PD_BUS] = DOMAIN_RK3328(0, BIT(2), BIT(2), true), - [RK3328_PD_MSCH] = DOMAIN_RK3328(0, BIT(3), BIT(3), true), - [RK3328_PD_PERI] = DOMAIN_RK3328(0, BIT(4), BIT(4), true), - [RK3328_PD_VIDEO] = DOMAIN_RK3328(0, BIT(5), BIT(5), false), - [RK3328_PD_HEVC] = DOMAIN_RK3328(0, BIT(6), BIT(6), false), - [RK3328_PD_VIO] = DOMAIN_RK3328(0, BIT(8), BIT(8), false), - [RK3328_PD_VPU] = DOMAIN_RK3328(0, BIT(9), BIT(9), false), + [RK3328_PD_CORE] = DOMAIN_RK3328("core", 0, BIT(0), BIT(0), false), + [RK3328_PD_GPU] = DOMAIN_RK3328("gpu", 0, BIT(1), BIT(1), false), + [RK3328_PD_BUS] = DOMAIN_RK3328("bus", 0, BIT(2), BIT(2), true), + [RK3328_PD_MSCH] = DOMAIN_RK3328("msch", 0, BIT(3), BIT(3), true), + [RK3328_PD_PERI] = DOMAIN_RK3328("peri", 0, BIT(4), BIT(4), true), + [RK3328_PD_VIDEO] = DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false), + [RK3328_PD_HEVC] = DOMAIN_RK3328("hevc", 0, BIT(6), BIT(6), false), + [RK3328_PD_VIO] = DOMAIN_RK3328("vio", 0, BIT(8), BIT(8), false), + [RK3328_PD_VPU] = DOMAIN_RK3328("vpu", 0, BIT(9), BIT(9), false), }; static const struct rockchip_domain_info rk3366_pm_domains[] = { - [RK3366_PD_PERI] = DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true), - [RK3366_PD_VIO] = DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false), - [RK3366_PD_VIDEO] = DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false), - [RK3366_PD_RKVDEC] = DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false), - [RK3366_PD_WIFIBT] = DOMAIN_RK3368(BIT(8), BIT(8), BIT(9), false), - [RK3366_PD_VPU] = DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false), - [RK3366_PD_GPU] = DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false), + [RK3366_PD_PERI] = DOMAIN_RK3368("peri", BIT(10), BIT(10), BIT(6), true), + [RK3366_PD_VIO] = DOMAIN_RK3368("vio", BIT(14), BIT(14), BIT(8), false), + [RK3366_PD_VIDEO] = DOMAIN_RK3368("video", BIT(13), BIT(13), BIT(7), false), + [RK3366_PD_RKVDEC] = DOMAIN_RK3368("vdec", BIT(11), BIT(11), BIT(7), false), + [RK3366_PD_WIFIBT] = DOMAIN_RK3368("wifibt", BIT(8), BIT(8), BIT(9), false), + [RK3366_PD_VPU] = DOMAIN_RK3368("vpu", BIT(12), BIT(12), BIT(7), false), + [RK3366_PD_GPU] = DOMAIN_RK3368("gpu", BIT(15), BIT(15), BIT(2), false), }; static const struct rockchip_domain_info rk3368_pm_domains[] = { - [RK3368_PD_PERI] = DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true), - [RK3368_PD_VIO] = DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false), - [RK3368_PD_VIDEO] = DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false), - [RK3368_PD_GPU_0] = DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false), - [RK3368_PD_GPU_1] = DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false), + [RK3368_PD_PERI] = DOMAIN_RK3368("peri", BIT(13), BIT(12), BIT(6), true), + [RK3368_PD_VIO] = DOMAIN_RK3368("vio", BIT(15), BIT(14), BIT(8), false), + [RK3368_PD_VIDEO] = DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false), + [RK3368_PD_GPU_0] = DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false), + [RK3368_PD_GPU_1] = DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false), }; static const struct rockchip_domain_info rk3399_pm_domains[] = { - [RK3399_PD_TCPD0] = DOMAIN_RK3399(BIT(8), BIT(8), 0, false), - [RK3399_PD_TCPD1] = DOMAIN_RK3399(BIT(9), BIT(9), 0, false), - [RK3399_PD_CCI] = DOMAIN_RK3399(BIT(10), BIT(10), 0, true), - [RK3399_PD_CCI0] = DOMAIN_RK3399(0, 0, BIT(15), true), - [RK3399_PD_CCI1] = DOMAIN_RK3399(0, 0, BIT(16), true), - [RK3399_PD_PERILP] = DOMAIN_RK3399(BIT(11), BIT(11), BIT(1), true), - [RK3399_PD_PERIHP] = DOMAIN_RK3399(BIT(12), BIT(12), BIT(2), true), - [RK3399_PD_CENTER] = DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true), - [RK3399_PD_VIO] = DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false), - [RK3399_PD_GPU] = DOMAIN_RK3399(BIT(15), BIT(15), BIT(0), false), - [RK3399_PD_VCODEC] = DOMAIN_RK3399(BIT(16), BIT(16), BIT(3), false), - [RK3399_PD_VDU] = DOMAIN_RK3399(BIT(17), BIT(17), BIT(4), false), - [RK3399_PD_RGA] = DOMAIN_RK3399(BIT(18), BIT(18), BIT(5), false), - [RK3399_PD_IEP] = DOMAIN_RK3399(BIT(19), BIT(19), BIT(6), false), - [RK3399_PD_VO] = DOMAIN_RK3399(BIT(20), BIT(20), 0, false), - [RK3399_PD_VOPB] = DOMAIN_RK3399(0, 0, BIT(7), false), - [RK3399_PD_VOPL] = DOMAIN_RK3399(0, 0, BIT(8), false), - [RK3399_PD_ISP0] = DOMAIN_RK3399(BIT(22), BIT(22), BIT(9), false), - [RK3399_PD_ISP1] = DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false), - [RK3399_PD_HDCP] = DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false), - [RK3399_PD_GMAC] = DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true), - [RK3399_PD_EMMC] = DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true), - [RK3399_PD_USB3] = DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true), - [RK3399_PD_EDP] = DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false), - [RK3399_PD_GIC] = DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true), - [RK3399_PD_SD] = DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true), - [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true), + [RK3399_PD_TCPD0] = DOMAIN_RK3399("tcpd0", BIT(8), BIT(8), 0, false), + [RK3399_PD_TCPD1] = DOMAIN_RK3399("tcpd1", BIT(9), BIT(9), 0, false), + [RK3399_PD_CCI] = DOMAIN_RK3399("cci", BIT(10), BIT(10), 0, true), + [RK3399_PD_CCI0] = DOMAIN_RK3399("cci0", 0, 0, BIT(15), true), + [RK3399_PD_CCI1] = DOMAIN_RK3399("cci1", 0, 0, BIT(16), true), + [RK3399_PD_PERILP] = DOMAIN_RK3399("perilp", BIT(11), BIT(11), BIT(1), true), + [RK3399_PD_PERIHP] = DOMAIN_RK3399("perihp", BIT(12), BIT(12), BIT(2), true), + [RK3399_PD_CENTER] = DOMAIN_RK3399("center", BIT(13), BIT(13), BIT(14), true), + [RK3399_PD_VIO] = DOMAIN_RK3399("vio", BIT(14), BIT(14), BIT(17), false), + [RK3399_PD_GPU] = DOMAIN_RK3399("gpu", BIT(15), BIT(15), BIT(0), false), + [RK3399_PD_VCODEC] = DOMAIN_RK3399("vcodec", BIT(16), BIT(16), BIT(3), false), + [RK3399_PD_VDU] = DOMAIN_RK3399("vdu", BIT(17), BIT(17), BIT(4), false), + [RK3399_PD_RGA] = DOMAIN_RK3399("rga", BIT(18), BIT(18), BIT(5), false), + [RK3399_PD_IEP] = DOMAIN_RK3399("iep", BIT(19), BIT(19), BIT(6), false), + [RK3399_PD_VO] = DOMAIN_RK3399("vo", BIT(20), BIT(20), 0, false), + [RK3399_PD_VOPB] = DOMAIN_RK3399("vopb", 0, 0, BIT(7), false), + [RK3399_PD_VOPL] = DOMAIN_RK3399("vopl", 0, 0, BIT(8), false), + [RK3399_PD_ISP0] = DOMAIN_RK3399("isp0", BIT(22), BIT(22), BIT(9), false), + [RK3399_PD_ISP1] = DOMAIN_RK3399("isp1", BIT(23), BIT(23), BIT(10), false), + [RK3399_PD_HDCP] = DOMAIN_RK3399("hdcp", BIT(24), BIT(24), BIT(11), false), + [RK3399_PD_GMAC] = DOMAIN_RK3399("gmac", BIT(25), BIT(25), BIT(23), true), + [RK3399_PD_EMMC] = DOMAIN_RK3399("emmc", BIT(26), BIT(26), BIT(24), true), + [RK3399_PD_USB3] = DOMAIN_RK3399("usb3", BIT(27), BIT(27), BIT(12), true), + [RK3399_PD_EDP] = DOMAIN_RK3399("edp", BIT(28), BIT(28), BIT(22), false), + [RK3399_PD_GIC] = DOMAIN_RK3399("gic", BIT(29), BIT(29), BIT(27), true), + [RK3399_PD_SD] = DOMAIN_RK3399("sd", BIT(30), BIT(30), BIT(28), true), + [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true), +}; + +static const struct rockchip_domain_info rk3568_pm_domains[] = { + [RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false), + [RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false), + [RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false), + [RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false), + [RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false), + [RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false), + [RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false), + [RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false), + [RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false), }; static const struct rockchip_pmu_info px30_pmu = { @@ -976,6 +999,17 @@ static const struct rockchip_pmu_info rk3399_pmu = { .domain_info = rk3399_pm_domains, }; +static const struct rockchip_pmu_info rk3568_pmu = { + .pwr_offset = 0xa0, + .status_offset = 0x98, + .req_offset = 0x50, + .idle_offset = 0x68, + .ack_offset = 0x60, + + .num_domains = ARRAY_SIZE(rk3568_pm_domains), + .domain_info = rk3568_pm_domains, +}; + static const struct of_device_id rockchip_pm_domain_dt_match[] = { { .compatible = "rockchip,px30-power-controller", @@ -1021,6 +1055,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { .compatible = "rockchip,rk3399-power-controller", .data = (void *)&rk3399_pmu, }, + { + .compatible = "rockchip,rk3568-power-controller", + .data = (void *)&rk3568_pmu, + }, { /* sentinel */ }, }; diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 976dee036470..20ace654553a 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL config SOC_TEGRA_PMC bool select GENERIC_PINCONF + select PM_OPP + select PM_GENERIC_DOMAINS config SOC_TEGRA_POWERGATE_BPMP def_bool y diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 3dc54f59cafe..cd33e99249c3 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -3,9 +3,16 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#define dev_fmt(fmt) "tegra-soc: " fmt + +#include +#include +#include #include +#include #include +#include static const struct of_device_id tegra_machine_match[] = { { .compatible = "nvidia,tegra20", }, @@ -31,3 +38,93 @@ bool soc_is_tegra(void) return match != NULL; } + +static int tegra_core_dev_init_opp_state(struct device *dev) +{ + unsigned long rate; + struct clk *clk; + int err; + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clk: %pe\n", clk); + return PTR_ERR(clk); + } + + rate = clk_get_rate(clk); + if (!rate) { + dev_err(dev, "failed to get clk rate\n"); + return -EINVAL; + } + + /* first dummy rate-setting initializes voltage vote */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + return err; + } + + return 0; +} + +/** + * devm_tegra_core_dev_init_opp_table() - initialize OPP table + * @dev: device for which OPP table is initialized + * @params: pointer to the OPP table configuration + * + * This function will initialize OPP table and sync OPP state of a Tegra SoC + * core device. + * + * Return: 0 on success or errorno. + */ +int devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params) +{ + u32 hw_version; + int err; + + err = devm_pm_opp_set_clkname(dev, NULL); + if (err) { + dev_err(dev, "failed to set OPP clk: %d\n", err); + return err; + } + + /* Tegra114+ doesn't support OPP yet */ + if (!of_machine_is_compatible("nvidia,tegra20") && + !of_machine_is_compatible("nvidia,tegra30")) + return -ENODEV; + + if (of_machine_is_compatible("nvidia,tegra20")) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1); + if (err) { + dev_err(dev, "failed to set OPP supported HW: %d\n", err); + return err; + } + + /* + * Older device-trees have an empty OPP table, we will get + * -ENODEV from devm_pm_opp_of_add_table() in this case. + */ + err = devm_pm_opp_of_add_table(dev); + if (err) { + if (err == -ENODEV) + dev_err_once(dev, "OPP table not found, please update device-tree\n"); + else + dev_err(dev, "failed to add OPP table: %d\n", err); + + return err; + } + + if (params->init_state) { + err = tegra_core_dev_init_opp_state(dev); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(devm_tegra_core_dev_init_opp_table); diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 94b60a692b51..3d9da3d359da 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -489,10 +489,8 @@ static int __init tegra_init_fuse(void) size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups; fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL); - if (!fuse->lookups) - return -ENOMEM; - - nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); + if (fuse->lookups) + nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); } return 0; diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 9ea7f0168457..c1aa7815bd6e 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -37,7 +37,8 @@ defined(CONFIG_ARCH_TEGRA_132_SOC) || \ defined(CONFIG_ARCH_TEGRA_210_SOC) || \ defined(CONFIG_ARCH_TEGRA_186_SOC) || \ - defined(CONFIG_ARCH_TEGRA_194_SOC) + defined(CONFIG_ARCH_TEGRA_194_SOC) || \ + defined(CONFIG_ARCH_TEGRA_234_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { if (WARN_ON(!fuse->base)) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 4a582eae82ef..ea62f84d1c8b 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -428,6 +429,9 @@ struct tegra_pmc { struct irq_chip irq; struct notifier_block clk_nb; + + bool core_domain_state_synced; + bool core_domain_registered; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1297,12 +1301,107 @@ free_mem: return err; } +bool tegra_pmc_core_domain_state_synced(void) +{ + return pmc->core_domain_state_synced; +} + +static int +tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd, + unsigned int level) +{ + struct dev_pm_opp *opp; + int err; + + opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level); + if (IS_ERR(opp)) { + dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n", + level, opp); + return PTR_ERR(opp); + } + + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_set_opp(pmc->dev, opp); + mutex_unlock(&pmc->powergates_lock); + + dev_pm_opp_put(opp); + + if (err) { + dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n", + level, err); + return err; + } + + return 0; +} + +static unsigned int +tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd, + struct dev_pm_opp *opp) +{ + return dev_pm_opp_get_level(opp); +} + +static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) +{ + struct generic_pm_domain *genpd; + const char *rname = "core"; + int err; + + genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL); + if (!genpd) + return -ENOMEM; + + genpd->name = np->name; + genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; + genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; + + err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1); + if (err) + return dev_err_probe(pmc->dev, err, + "failed to set core OPP regulator\n"); + + err = pm_genpd_init(genpd, NULL, false); + if (err) { + dev_err(pmc->dev, "failed to init core genpd: %d\n", err); + return err; + } + + err = of_genpd_add_provider_simple(np, genpd); + if (err) { + dev_err(pmc->dev, "failed to add core genpd: %d\n", err); + goto remove_genpd; + } + + pmc->core_domain_registered = true; + + return 0; + +remove_genpd: + pm_genpd_remove(genpd); + + return err; +} + static int tegra_powergate_init(struct tegra_pmc *pmc, struct device_node *parent) { + struct of_phandle_args child_args, parent_args; struct device_node *np, *child; int err = 0; + /* + * Core power domain is the parent of powergate domains, hence it + * should be registered first. + */ + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + err = tegra_pmc_core_pd_add(pmc, np); + of_node_put(np); + if (err) + return err; + } + np = of_get_child_by_name(parent, "powergates"); if (!np) return 0; @@ -1313,6 +1412,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, of_node_put(child); break; } + + if (of_parse_phandle_with_args(child, "power-domains", + "#power-domain-cells", + 0, &parent_args)) + continue; + + child_args.np = child; + child_args.args_count = 0; + + err = of_genpd_add_subdomain(&parent_args, &child_args); + of_node_put(parent_args.np); + if (err) { + of_node_put(child); + break; + } } of_node_put(np); @@ -1356,6 +1470,12 @@ static void tegra_powergate_remove_all(struct device_node *parent) } of_node_put(np); + + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + of_genpd_del_provider(np); + of_genpd_remove_last(np); + } } static const struct tegra_io_pad_soc * @@ -3667,6 +3787,29 @@ static const struct of_device_id tegra_pmc_match[] = { { } }; +static void tegra_pmc_sync_state(struct device *dev) +{ + int err; + + /* + * Older device-trees don't have core PD, and thus, there are + * no dependencies that will block the state syncing. We shouldn't + * mark the domain as synced in this case. + */ + if (!pmc->core_domain_registered) + return; + + pmc->core_domain_state_synced = true; + + /* this is a no-op if core regulator isn't used */ + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_sync_regulators(dev); + mutex_unlock(&pmc->powergates_lock); + + if (err) + dev_err(dev, "failed to sync regulators: %d\n", err); +} + static struct platform_driver tegra_pmc_driver = { .driver = { .name = "tegra-pmc", @@ -3675,6 +3818,7 @@ static struct platform_driver tegra_pmc_driver = { #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) .pm = &tegra_pmc_pm_ops, #endif + .sync_state = tegra_pmc_sync_state, }, .probe = tegra_pmc_probe, }; diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index 367a71a3cd10..b8ce9fd0650d 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -12,16 +12,22 @@ #include #include #include +#include #include #include #include +#include + struct tegra_regulator_coupler { struct regulator_coupler coupler; struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; - int core_min_uV; + struct notifier_block reboot_notifier; + int core_min_uV, cpu_min_uV; + bool sys_reboot_mode_req; + bool sys_reboot_mode; }; static inline struct tegra_regulator_coupler * @@ -38,6 +44,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra20 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Display controller for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -58,7 +79,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } @@ -242,6 +263,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (cpu_uV < 0) return cpu_uV; + /* store boot voltage level */ + if (!tegra->cpu_min_uV) + tegra->cpu_min_uV = cpu_uV; + /* * CPU's regulator may not have any consumers, hence the voltage * must not be changed in that case because CPU simply won't @@ -250,6 +275,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (!cpu_min_uV_consumers) cpu_min_uV = cpu_uV; + /* restore boot voltage level */ + if (tegra->sys_reboot_mode) + cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -290,6 +319,8 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EINVAL; } + tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, core_rdev, rtc_rdev); @@ -303,6 +334,51 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, + bool sys_reboot_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + WRITE_ONCE(tegra->sys_reboot_mode_req, true); + + /* + * Some devices use CPU soft-reboot method and in this case we + * should ensure that voltages are sane for the reboot by restoring + * the minimum boot levels. + */ + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode); + + return 0; +} + +static int tegra20_regulator_reboot(struct notifier_block *notifier, + unsigned long event, void *cmd) +{ + struct tegra_regulator_coupler *tegra; + int ret; + + if (event != SYS_RESTART) + return NOTIFY_DONE; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + reboot_notifier); + + ret = tegra20_regulator_prepare_reboot(tegra, true); + + return notifier_from_errno(ret); +} + static int tegra20_regulator_attach(struct regulator_coupler *coupler, struct regulator_dev *rdev) { @@ -335,6 +411,14 @@ static int tegra20_regulator_detach(struct regulator_coupler *coupler, { struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); + /* + * We don't expect regulators to be decoupled during reboot, + * this may race with the reboot handler and shouldn't ever + * happen in practice. + */ + if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING)) + return -EPERM; + if (tegra->core_rdev == rdev) { tegra->core_rdev = NULL; return 0; @@ -359,13 +443,19 @@ static struct tegra_regulator_coupler tegra20_coupler = { .detach_regulator = tegra20_regulator_detach, .balance_voltage = tegra20_regulator_balance_voltage, }, + .reboot_notifier.notifier_call = tegra20_regulator_reboot, }; static int __init tegra_regulator_coupler_init(void) { + int err; + if (!of_machine_is_compatible("nvidia,tegra20")) return 0; + err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra20_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index 0e776b20f625..e74bbc9c7859 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -12,17 +12,22 @@ #include #include #include +#include #include #include #include #include +#include struct tegra_regulator_coupler { struct regulator_coupler coupler; struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; - int core_min_uV; + struct notifier_block reboot_notifier; + int core_min_uV, cpu_min_uV; + bool sys_reboot_mode_req; + bool sys_reboot_mode; }; static inline struct tegra_regulator_coupler * @@ -39,6 +44,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra30 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Display controller for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -59,7 +79,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } @@ -172,6 +192,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (cpu_uV < 0) return cpu_uV; + /* store boot voltage level */ + if (!tegra->cpu_min_uV) + tegra->cpu_min_uV = cpu_uV; + /* * CPU's regulator may not have any consumers, hence the voltage * must not be changed in that case because CPU simply won't @@ -195,6 +219,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* restore boot voltage level */ + if (tegra->sys_reboot_mode) + cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + if (core_min_limited_uV > core_uV) { pr_err("core voltage constraint violated: %d %d %d\n", core_uV, core_min_limited_uV, cpu_uV); @@ -263,9 +291,56 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler, return -EINVAL; } + tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + return tegra30_voltage_update(tegra, cpu_rdev, core_rdev); } +static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, + bool sys_reboot_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->cpu_rdev) + return 0; + + WRITE_ONCE(tegra->sys_reboot_mode_req, true); + + /* + * Some devices use CPU soft-reboot method and in this case we + * should ensure that voltages are sane for the reboot by restoring + * the minimum boot levels. + */ + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode); + + return 0; +} + +static int tegra30_regulator_reboot(struct notifier_block *notifier, + unsigned long event, void *cmd) +{ + struct tegra_regulator_coupler *tegra; + int ret; + + if (event != SYS_RESTART) + return NOTIFY_DONE; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + reboot_notifier); + + ret = tegra30_regulator_prepare_reboot(tegra, true); + + return notifier_from_errno(ret); +} + static int tegra30_regulator_attach(struct regulator_coupler *coupler, struct regulator_dev *rdev) { @@ -292,6 +367,14 @@ static int tegra30_regulator_detach(struct regulator_coupler *coupler, { struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); + /* + * We don't expect regulators to be decoupled during reboot, + * this may race with the reboot handler and shouldn't ever + * happen in practice. + */ + if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING)) + return -EPERM; + if (tegra->core_rdev == rdev) { tegra->core_rdev = NULL; return 0; @@ -311,13 +394,19 @@ static struct tegra_regulator_coupler tegra30_coupler = { .detach_regulator = tegra30_regulator_detach, .balance_voltage = tegra30_regulator_balance_voltage, }, + .reboot_notifier.notifier_call = tegra30_regulator_reboot, }; static int __init tegra_regulator_coupler_init(void) { + int err; + if (!of_machine_is_compatible("nvidia,tegra30")) return 0; + err = register_reboot_notifier(&tegra30_coupler.reboot_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra30_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index 5376f3d22f31..06cbee5fd254 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -846,10 +846,8 @@ static int omap_sr_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); sr_info->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(sr_info->base)) { - dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); + if (IS_ERR(sr_info->base)) return PTR_ERR(sr_info->base); - } irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index c3e2161df732..09abd17065ba 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -445,10 +445,8 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res); - if (IS_ERR(m3_ipc->ipc_mem_base)) { - dev_err(dev, "could not ioremap ipc_mem\n"); + if (IS_ERR(m3_ipc->ipc_mem_base)) return PTR_ERR(m3_ipc->ipc_mem_base); - } irq = platform_get_irq(pdev, 0); if (!irq) { diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 1646ba8eda11..2629d2ef3970 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -982,7 +982,7 @@ pscsi_execute_cmd(struct se_cmd *cmd) req = blk_get_request(pdv->pdv_sd->request_queue, cmd->data_direction == DMA_TO_DEVICE ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed\n"); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 3a788ac4f525..5a86cffd78f6 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c @@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) EXPORT_SYMBOL_GPL(devfreq_cooling_register); /** - * devfreq_cooling_em_register_power() - Register devfreq cooling device with + * devfreq_cooling_em_register() - Register devfreq cooling device with * power information and automatically register Energy Model (EM) * @df: Pointer to devfreq device. * @dfc_power: Pointer to devfreq_cooling_power. diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c index b01d28eca7ee..8d76dbfde6a9 100644 --- a/drivers/thermal/imx_sc_thermal.c +++ b/drivers/thermal/imx_sc_thermal.c @@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) for_each_available_child_of_node(np, child) { sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) { + of_node_put(child); of_node_put(sensor_np); return -ENOMEM; } @@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get valid sensor resource id: %d\n", ret); + of_node_put(child); break; } @@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) if (IS_ERR(sensor->tzd)) { dev_err(&pdev->dev, "failed to register thermal zone\n"); ret = PTR_ERR(sensor->tzd); + of_node_put(child); break; } diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index 38a2731e503c..4e852ce4a5d5 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o +obj-$(CONFIG_INT340X_THERMAL) += int3401_thermal.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci_legacy.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c new file mode 100644 index 000000000000..acebc8ba94e2 --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * INT3401 processor thermal device + * Copyright (c) 2020, Intel Corporation. + */ +#include +#include +#include +#include +#include + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" + +static const struct acpi_device_id int3401_device_ids[] = { + {"INT3401", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, int3401_device_ids); + +static int int3401_add(struct platform_device *pdev) +{ + struct proc_thermal_device *proc_priv; + int ret; + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) + return ret; + + platform_set_drvdata(pdev, proc_priv); + + return ret; +} + +static int int3401_remove(struct platform_device *pdev) +{ + proc_thermal_remove(platform_get_drvdata(pdev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int int3401_thermal_resume(struct device *dev) +{ + return proc_thermal_resume(dev); +} +#else +#define int3401_thermal_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume); + +static struct platform_driver int3401_driver = { + .probe = int3401_add, + .remove = int3401_remove, + .driver = { + .name = "int3401 thermal", + .acpi_match_table = int3401_device_ids, + .pm = &int3401_proc_thermal_pm, + }, +}; + +static int __init proc_thermal_init(void) +{ + return platform_driver_register(&int3401_driver); +} + +static void __exit proc_thermal_exit(void) +{ + platform_driver_unregister(&int3401_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 9e6f2a895a23..0f0038af2ad4 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -3,34 +3,17 @@ * processor_thermal_device.c * Copyright (c) 2014, Intel Corporation. */ +#include #include #include -#include #include -#include -#include -#include #include -#include #include "int340x_thermal_zone.h" #include "processor_thermal_device.h" #include "../intel_soc_dts_iosf.h" #define DRV_NAME "proc_thermal" -enum proc_thermal_emum_mode_type { - PROC_THERMAL_NONE, - PROC_THERMAL_PCI, - PROC_THERMAL_PLATFORM_DEV -}; - -/* - * We can have only one type of enumeration, PCI or Platform, - * not both. So we don't need instance specific data. - */ -static enum proc_thermal_emum_mode_type proc_thermal_emum_mode = - PROC_THERMAL_NONE; - #define POWER_LIMIT_SHOW(index, suffix) \ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -38,11 +21,6 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ { \ struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \ \ - if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \ - dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \ - return 0; \ - } \ - \ return sprintf(buf, "%lu\n",\ (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ } @@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev, if (err) return err; - val = (val >> 24) & 0xff; + val = (val >> 24) & 0x3f; return sprintf(buf, "%d\n", (int)val); } -static int tcc_offset_update(int tcc) +static int tcc_offset_update(unsigned int tcc) { u64 val; int err; - if (!tcc) + if (tcc > 63) return -EINVAL; err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); if (err) return err; - val &= ~GENMASK_ULL(31, 24); - val |= (tcc & 0xff) << 24; + if (val & BIT(31)) + return -EPERM; + + val &= ~GENMASK_ULL(29, 24); + val |= (tcc & 0x3f) << 24; err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); if (err) @@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc) return 0; } -static int tcc_offset_save; +static unsigned int tcc_offset_save; static ssize_t tcc_offset_degree_celsius_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned int tcc; u64 val; - int tcc, err; + int err; err = rdmsrl_safe(MSR_PLATFORM_INFO, &val); if (err) @@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, if (!(val & BIT(30))) return -EACCES; - if (kstrtoint(buf, 0, &tcc)) + if (kstrtouint(buf, 0, &tcc)) return -EINVAL; err = tcc_offset_update(tcc); @@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) } } - -static int proc_thermal_add(struct device *dev, - struct proc_thermal_device **priv) +int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv) { - struct proc_thermal_device *proc_priv; struct acpi_device *adev; acpi_status status; unsigned long long tmp; @@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev, if (!adev) return -ENODEV; - proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); - if (!proc_priv) - return -ENOMEM; - proc_priv->dev = dev; proc_priv->adev = adev; - *priv = proc_priv; ret = proc_thermal_read_ppcc(proc_priv); if (ret) @@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev, if (ret) goto remove_zone; + ret = sysfs_create_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); + if (ret) + goto remove_notify; + + ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group); + if (ret) { + sysfs_remove_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); + goto remove_notify; + } + return 0; +remove_notify: + acpi_remove_notify_handler(adev->handle, + ACPI_DEVICE_NOTIFY, proc_thermal_notify); remove_zone: int340x_thermal_zone_remove(proc_priv->int340x_zone); return ret; } +EXPORT_SYMBOL_GPL(proc_thermal_add); -static void proc_thermal_remove(struct proc_thermal_device *proc_priv) +void proc_thermal_remove(struct proc_thermal_device *proc_priv) { acpi_remove_notify_handler(proc_priv->adev->handle, ACPI_DEVICE_NOTIFY, proc_thermal_notify); @@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv) sysfs_remove_group(&proc_priv->dev->kobj, &power_limit_attribute_group); } +EXPORT_SYMBOL_GPL(proc_thermal_remove); -static int int3401_add(struct platform_device *pdev) +int proc_thermal_resume(struct device *dev) { - struct proc_thermal_device *proc_priv; - int ret; + struct proc_thermal_device *proc_dev; - if (proc_thermal_emum_mode == PROC_THERMAL_PCI) { - dev_err(&pdev->dev, "error: enumerated as PCI dev\n"); - return -ENODEV; - } + proc_dev = dev_get_drvdata(dev); + proc_thermal_read_ppcc(proc_dev); - ret = proc_thermal_add(&pdev->dev, &proc_priv); - if (ret) - return ret; - - platform_set_drvdata(pdev, proc_priv); - proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV; - - dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n"); - - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - if (ret) - return ret; - - ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group); - if (ret) - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - - return ret; -} - -static int int3401_remove(struct platform_device *pdev) -{ - proc_thermal_remove(platform_get_drvdata(pdev)); + tcc_offset_update(tcc_offset_save); return 0; } - -static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) -{ - struct proc_thermal_device *proc_priv; - struct pci_dev *pdev = devid; - - proc_priv = pci_get_drvdata(pdev); - - intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts); - - return IRQ_HANDLED; -} +EXPORT_SYMBOL_GPL(proc_thermal_resume); #define MCHBAR 0 -static int proc_thermal_set_mmio_base(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv) +static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { int ret; @@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev, return 0; } -static int proc_thermal_mmio_add(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv, - kernel_ulong_t feature_mask) +int proc_thermal_mmio_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + kernel_ulong_t feature_mask) { int ret; @@ -471,11 +423,10 @@ err_rem_rapl: return ret; } +EXPORT_SYMBOL_GPL(proc_thermal_mmio_add); -static void proc_thermal_mmio_remove(struct pci_dev *pdev) +void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { - struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); - if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) proc_thermal_rapl_remove(); @@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX) proc_thermal_mbox_remove(pdev); } - -static int proc_thermal_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct proc_thermal_device *proc_priv; - int ret; - - if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { - dev_err(&pdev->dev, "error: enumerated as platform dev\n"); - return -ENODEV; - } - - ret = pcim_enable_device(pdev); - if (ret < 0) { - dev_err(&pdev->dev, "error: could not enable device\n"); - return ret; - } - - ret = proc_thermal_add(&pdev->dev, &proc_priv); - if (ret) - return ret; - - pci_set_drvdata(pdev, proc_priv); - proc_thermal_emum_mode = PROC_THERMAL_PCI; - - if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) { - /* - * Enumerate additional DTS sensors available via IOSF. - * But we are not treating as a failure condition, if - * there are no aux DTSs enabled or fails. This driver - * already exposes sensors, which can be accessed via - * ACPI/MSR. So we don't want to fail for auxiliary DTSs. - */ - proc_priv->soc_dts = intel_soc_dts_iosf_init( - INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); - - if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) { - ret = pci_enable_msi(pdev); - if (!ret) { - ret = request_threaded_irq(pdev->irq, NULL, - proc_thermal_pci_msi_irq, - IRQF_ONESHOT, "proc_thermal", - pdev); - if (ret) { - intel_soc_dts_iosf_exit( - proc_priv->soc_dts); - pci_disable_msi(pdev); - proc_priv->soc_dts = NULL; - } - } - } else - dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); - } - - dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n"); - - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - if (ret) - return ret; - - ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group); - if (ret) { - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - return ret; - } - - ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); - if (ret) { - proc_thermal_remove(proc_priv); - return ret; - } - - return 0; -} - -static void proc_thermal_pci_remove(struct pci_dev *pdev) -{ - struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); - - if (proc_priv->soc_dts) { - intel_soc_dts_iosf_exit(proc_priv->soc_dts); - if (pdev->irq) { - free_irq(pdev->irq, pdev); - pci_disable_msi(pdev); - } - } - - proc_thermal_mmio_remove(pdev); - proc_thermal_remove(proc_priv); -} - -#ifdef CONFIG_PM_SLEEP -static int proc_thermal_resume(struct device *dev) -{ - struct proc_thermal_device *proc_dev; - - proc_dev = dev_get_drvdata(dev); - proc_thermal_read_ppcc(proc_dev); - - tcc_offset_update(tcc_offset_save); - - return 0; -} -#else -#define proc_thermal_resume NULL -#endif - -static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); - -static const struct pci_device_id proc_thermal_pci_ids[] = { - { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, - { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); - -static struct pci_driver proc_thermal_pci_driver = { - .name = DRV_NAME, - .probe = proc_thermal_pci_probe, - .remove = proc_thermal_pci_remove, - .id_table = proc_thermal_pci_ids, - .driver.pm = &proc_thermal_pm, -}; - -static const struct acpi_device_id int3401_device_ids[] = { - {"INT3401", 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, int3401_device_ids); - -static struct platform_driver int3401_driver = { - .probe = int3401_add, - .remove = int3401_remove, - .driver = { - .name = "int3401 thermal", - .acpi_match_table = int3401_device_ids, - .pm = &proc_thermal_pm, - }, -}; - -static int __init proc_thermal_init(void) -{ - int ret; - - ret = platform_driver_register(&int3401_driver); - if (ret) - return ret; - - ret = pci_register_driver(&proc_thermal_pci_driver); - - return ret; -} - -static void __exit proc_thermal_exit(void) -{ - platform_driver_unregister(&int3401_driver); - pci_unregister_driver(&proc_thermal_pci_driver); -} - -module_init(proc_thermal_init); -module_exit(proc_thermal_exit); +EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index b9ed64561aaf..5a1cfe4864f1 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -44,6 +44,7 @@ struct proc_thermal_device { struct intel_soc_dts_sensors *soc_dts; u32 mmio_feature_mask; void __iomem *mmio_base; + void *priv_data; }; struct rapl_mmio_regs { @@ -79,4 +80,12 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev); int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); void proc_thermal_mbox_remove(struct pci_dev *pdev); +int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp); +int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv); +void proc_thermal_remove(struct proc_thermal_device *proc_priv); +int proc_thermal_resume(struct device *dev); +int proc_thermal_mmio_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + kernel_ulong_t feature_mask); +void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c new file mode 100644 index 000000000000..11dd2e825f4f --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Processor thermal device for newer processors + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include +#include +#include +#include + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" + +#define DRV_NAME "proc_thermal_pci" + +struct proc_thermal_pci { + struct pci_dev *pdev; + struct proc_thermal_device *proc_priv; + struct thermal_zone_device *tzone; + struct delayed_work work; + int stored_thres; + int no_legacy; +}; + +enum proc_thermal_mmio_type { + PROC_THERMAL_MMIO_TJMAX, + PROC_THERMAL_MMIO_PP0_TEMP, + PROC_THERMAL_MMIO_PP1_TEMP, + PROC_THERMAL_MMIO_PKG_TEMP, + PROC_THERMAL_MMIO_THRES_0, + PROC_THERMAL_MMIO_THRES_1, + PROC_THERMAL_MMIO_INT_ENABLE_0, + PROC_THERMAL_MMIO_INT_ENABLE_1, + PROC_THERMAL_MMIO_INT_STATUS_0, + PROC_THERMAL_MMIO_INT_STATUS_1, + PROC_THERMAL_MMIO_MAX +}; + +struct proc_thermal_mmio_info { + enum proc_thermal_mmio_type mmio_type; + u64 mmio_addr; + u64 shift; + u64 mask; +}; + +static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = { + { PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff }, + { PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff }, + { PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff }, + { PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff }, + { PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F }, + { PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F }, + { PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 }, + { PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 }, + { PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 }, + { PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 }, +}; + +#define B0D4_THERMAL_NOTIFY_DELAY 1000 +static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY; + +static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info, + enum proc_thermal_mmio_type type, + u32 *value) +{ + *value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); + *value >>= proc_thermal_mmio_info[type].shift; + *value &= proc_thermal_mmio_info[type].mask; +} + +static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info, + enum proc_thermal_mmio_type type, + u32 value) +{ + u32 current_val; + u32 mask; + + current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); + mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift; + current_val &= ~mask; + + value &= proc_thermal_mmio_info[type].mask; + value <<= proc_thermal_mmio_info[type].shift; + + current_val |= value; + iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); +} + +/* + * To avoid sending two many messages to user space, we have 1 second delay. + * On interrupt we are disabling interrupt and enabling after 1 second. + * This workload function is delayed by 1 second. + */ +static void proc_thermal_threshold_work_fn(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct proc_thermal_pci *pci_info = container_of(delayed_work, + struct proc_thermal_pci, work); + struct thermal_zone_device *tzone = pci_info->tzone; + + if (tzone) + thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED); + + /* Enable interrupt flag */ + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); +} + +static void pkg_thermal_schedule_work(struct delayed_work *work) +{ + unsigned long ms = msecs_to_jiffies(notify_delay_ms); + + schedule_delayed_work(work, ms); +} + +static irqreturn_t proc_thermal_irq_handler(int irq, void *devid) +{ + struct proc_thermal_pci *pci_info = devid; + u32 status; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status); + + /* Disable enable interrupt flag */ + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + pci_write_config_byte(pci_info->pdev, 0xdc, 0x01); + + pkg_thermal_schedule_work(&pci_info->work); + + return IRQ_HANDLED; +} + +static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + u32 _temp; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp); + *temp = (unsigned long)_temp * 1000; + + return 0; +} + +static int sys_get_trip_temp(struct thermal_zone_device *tzd, + int trip, int *temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + u32 _temp; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp); + if (!_temp) { + *temp = THERMAL_TEMP_INVALID; + } else { + int tjmax; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); + _temp = tjmax - _temp; + *temp = (unsigned long)_temp * 1000; + } + + return 0; +} + +static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip, + enum thermal_trip_type *type) +{ + *type = THERMAL_TRIP_PASSIVE; + + return 0; +} + +static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + int tjmax, _temp; + + if (temp <= 0) { + cancel_delayed_work_sync(&pci_info->work); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0); + thermal_zone_device_disable(tzd); + pci_info->stored_thres = 0; + return 0; + } + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); + _temp = tjmax - (temp / 1000); + if (_temp < 0) + return -EINVAL; + + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); + + thermal_zone_device_enable(tzd); + pci_info->stored_thres = temp; + + return 0; +} + +static struct thermal_zone_device_ops tzone_ops = { + .get_temp = sys_get_curr_temp, + .get_trip_temp = sys_get_trip_temp, + .get_trip_type = sys_get_trip_type, + .set_trip_temp = sys_set_trip_temp, +}; + +static struct thermal_zone_params tzone_params = { + .governor_name = "user_space", + .no_hwmon = true, +}; + +static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct proc_thermal_device *proc_priv; + struct proc_thermal_pci *pci_info; + int irq_flag = 0, irq, ret; + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL); + if (!pci_info) + return -ENOMEM; + + pci_info->pdev = pdev; + ret = pcim_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + pci_set_master(pdev); + + INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn); + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) { + dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n"); + pci_info->no_legacy = 1; + } + + proc_priv->priv_data = pci_info; + pci_info->proc_priv = proc_priv; + pci_set_drvdata(pdev, proc_priv); + + ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); + if (ret) + goto err_ret_thermal; + + pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info, + &tzone_ops, + &tzone_params, 0, 0); + if (IS_ERR(pci_info->tzone)) { + ret = PTR_ERR(pci_info->tzone); + goto err_ret_mmio; + } + + /* request and enable interrupt */ + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to allocate vectors!\n"); + goto err_ret_tzone; + } + if (!pdev->msi_enabled && !pdev->msix_enabled) + irq_flag = IRQF_SHARED; + + irq = pci_irq_vector(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, + proc_thermal_irq_handler, NULL, + irq_flag, KBUILD_MODNAME, pci_info); + if (ret) { + dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq); + goto err_free_vectors; + } + + return 0; + +err_free_vectors: + pci_free_irq_vectors(pdev); +err_ret_tzone: + thermal_zone_device_unregister(pci_info->tzone); +err_ret_mmio: + proc_thermal_mmio_remove(pdev, proc_priv); +err_ret_thermal: + if (!pci_info->no_legacy) + proc_thermal_remove(proc_priv); + pci_disable_device(pdev); + + return ret; +} + +static void proc_thermal_pci_remove(struct pci_dev *pdev) +{ + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + struct proc_thermal_pci *pci_info = proc_priv->priv_data; + + cancel_delayed_work_sync(&pci_info->work); + + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + + devm_free_irq(&pdev->dev, pdev->irq, pci_info); + pci_free_irq_vectors(pdev); + + thermal_zone_device_unregister(pci_info->tzone); + proc_thermal_mmio_remove(pdev, pci_info->proc_priv); + if (!pci_info->no_legacy) + proc_thermal_remove(proc_priv); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct proc_thermal_device *proc_priv; + struct proc_thermal_pci *pci_info; + + proc_priv = pci_get_drvdata(pdev); + pci_info = proc_priv->priv_data; + + if (pci_info->stored_thres) { + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, + pci_info->stored_thres / 1000); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); + } + + if (!pci_info->no_legacy) + return proc_thermal_resume(dev); + + return 0; +} +#else +#define proc_thermal_pci_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); + +static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); + +static struct pci_driver proc_thermal_pci_driver = { + .name = DRV_NAME, + .probe = proc_thermal_pci_probe, + .remove = proc_thermal_pci_remove, + .id_table = proc_thermal_pci_ids, + .driver.pm = &proc_thermal_pci_pm, +}; + +static int __init proc_thermal_init(void) +{ + return pci_register_driver(&proc_thermal_pci_driver); +} + +static void __exit proc_thermal_exit(void) +{ + pci_unregister_driver(&proc_thermal_pci_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c new file mode 100644 index 000000000000..f5fc1791b11e --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * B0D4 processor thermal device + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include +#include +#include +#include + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" +#include "../intel_soc_dts_iosf.h" + +#define DRV_NAME "proc_thermal" + +static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) +{ + struct proc_thermal_device *proc_priv; + struct pci_dev *pdev = devid; + + proc_priv = pci_get_drvdata(pdev); + + intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts); + + return IRQ_HANDLED; +} + +static int proc_thermal_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct proc_thermal_device *proc_priv; + int ret; + + ret = pcim_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) + return ret; + + pci_set_drvdata(pdev, proc_priv); + + if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) { + /* + * Enumerate additional DTS sensors available via IOSF. + * But we are not treating as a failure condition, if + * there are no aux DTSs enabled or fails. This driver + * already exposes sensors, which can be accessed via + * ACPI/MSR. So we don't want to fail for auxiliary DTSs. + */ + proc_priv->soc_dts = intel_soc_dts_iosf_init( + INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); + + if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) { + ret = pci_enable_msi(pdev); + if (!ret) { + ret = request_threaded_irq(pdev->irq, NULL, + proc_thermal_pci_msi_irq, + IRQF_ONESHOT, "proc_thermal", + pdev); + if (ret) { + intel_soc_dts_iosf_exit( + proc_priv->soc_dts); + pci_disable_msi(pdev); + proc_priv->soc_dts = NULL; + } + } + } else + dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); + } else { + + } + + ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); + if (ret) { + proc_thermal_remove(proc_priv); + return ret; + } + + return 0; +} + +static void proc_thermal_pci_remove(struct pci_dev *pdev) +{ + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + + if (proc_priv->soc_dts) { + intel_soc_dts_iosf_exit(proc_priv->soc_dts); + if (pdev->irq) { + free_irq(pdev->irq, pdev); + pci_disable_msi(pdev); + } + } + + proc_thermal_mmio_remove(pdev, proc_priv); + proc_thermal_remove(proc_priv); +} + +#ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_resume(struct device *dev) +{ + return proc_thermal_resume(dev); +} +#else +#define proc_thermal_pci_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); + +static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); + +static struct pci_driver proc_thermal_pci_driver = { + .name = DRV_NAME, + .probe = proc_thermal_pci_probe, + .remove = proc_thermal_pci_remove, + .id_table = proc_thermal_pci_ids, + .driver.pm = &proc_thermal_pci_pm, +}; + +static int __init proc_thermal_init(void) +{ + return pci_register_driver(&proc_thermal_pci_driver); +} + +static void __exit proc_thermal_exit(void) +{ + pci_unregister_driver(&proc_thermal_pci_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c index 990f51f22884..59e93b04f0a9 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c @@ -23,7 +23,7 @@ static DEFINE_MUTEX(mbox_lock); -static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp) +static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp) { struct proc_thermal_device *proc_priv; u32 retries, data; @@ -82,6 +82,12 @@ unlock_mbox: return ret; } +int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp) +{ + return send_mbox_cmd(pdev, cmd_id, cmd_data, cmd_resp); +} +EXPORT_SYMBOL_GPL(processor_thermal_send_mbox_cmd); + /* List of workload types */ static const char * const workload_types[] = { "none", @@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); - u8 cmd_resp; + u32 cmd_resp; int ret; ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp); @@ -181,7 +187,7 @@ static bool workload_req_created; int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { - u8 cmd_resp; + u32 cmd_resp; int ret; /* Check if there is a mailbox support, if fails return success */ diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index aef993a813e2..2b8a3235d518 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -190,6 +190,59 @@ static DEVICE_ATTR_RO(ddr_data_rate_point_2); static DEVICE_ATTR_RO(ddr_data_rate_point_3); static DEVICE_ATTR_RW(rfi_disable); +static ssize_t rfi_restriction_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u16 cmd_id = 0x0008; + u32 cmd_resp; + u32 input; + int ret; + + ret = kstrtou32(buf, 10, &input); + if (ret) + return ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp); + if (ret) + return ret; + + return count; +} + +static ssize_t rfi_restriction_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u16 cmd_id = 0x0007; + u32 cmd_resp; + int ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp); + if (ret) + return ret; + + return sprintf(buf, "%u\n", cmd_resp); +} + +static ssize_t ddr_data_rate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u16 cmd_id = 0x0107; + u32 cmd_resp; + int ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp); + if (ret) + return ret; + + return sprintf(buf, "%u\n", cmd_resp); +} + +static DEVICE_ATTR_RW(rfi_restriction); +static DEVICE_ATTR_RO(ddr_data_rate); + static struct attribute *dvfs_attrs[] = { &dev_attr_rfi_restriction_run_busy.attr, &dev_attr_rfi_restriction_err_code.attr, @@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = { &dev_attr_ddr_data_rate_point_2.attr, &dev_attr_ddr_data_rate_point_3.attr, &dev_attr_rfi_disable.attr, + &dev_attr_ddr_data_rate.attr, + &dev_attr_rfi_restriction.attr, NULL }; diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c index 4f1a2f7c016c..342b0bb5a56d 100644 --- a/drivers/thermal/intel/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel/intel_soc_dts_iosf.c @@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip( int i, j; for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { - for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { - if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { - return update_trip_temp(&sensors->soc_dts[i], j, - sensors->tj_max - critical_offset, - THERMAL_TRIP_CRITICAL); - } - } + struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i]; + int temp = sensors->tj_max - critical_offset; + unsigned long count = entry->trip_count; + unsigned long mask = entry->trip_mask; + + j = find_first_zero_bit(&mask, count); + if (j < count) + return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL); } return -EINVAL; diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 97e8678ccf0e..ede94eadddda 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -23,6 +23,8 @@ #include #include +#include "thermal_hwmon.h" + /* AUXADC Registers */ #define AUXADC_CON1_SET_V 0x008 #define AUXADC_CON1_CLR_V 0x00c @@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev) goto err_disable_clk_peri_therm; } + ret = devm_thermal_add_hwmon_sysfs(tzdev); + if (ret) + dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); + return 0; err_disable_clk_peri_therm: diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index e1e412348076..fdf16aa34eb4 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -143,7 +143,7 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, * Division is not scaled in BSP and if scaled it might overflow * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled */ - tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157) + tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3)) / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3); tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), @@ -307,7 +307,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) { struct rcar_gen3_thermal_priv *priv; struct device *dev = &pdev->dev; - const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev); + const int *ths_tj_1 = of_device_get_match_data(dev); struct resource *res; struct thermal_zone_device *zone; int ret, i; @@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) priv->tscs[i] = tsc; priv->thermal_init(tsc); - rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], - *rcar_gen3_ths_tj_1); + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index aa9e0e31ef98..657d84b9963e 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -211,7 +211,11 @@ struct rockchip_thermal_data { #define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ #define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */ +#define TSADCV5_AUTO_PERIOD_TIME 1622 /* 2.5ms */ +#define TSADCV5_AUTO_PERIOD_HT_TIME 1622 /* 2.5ms */ + #define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ +#define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */ #define GRF_SARADC_TESTBIT 0x0e644 #define GRF_TSADC_TESTBIT_L 0x0e648 @@ -219,6 +223,12 @@ struct rockchip_thermal_data { #define PX30_GRF_SOC_CON2 0x0408 +#define RK3568_GRF_TSADC_CON 0x0600 +#define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0) +#define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1) +#define RK3568_GRF_TSADC_ANA_REG2 (0x10001 << 2) +#define RK3568_GRF_TSADC_TSEN (0x10001 << 8) + #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) #define GRF_TSADC_VCM_EN_L (0x10001 << 7) @@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = { {TSADCV3_DATA_MASK, 125000}, }; +static const struct tsadc_table rk3568_code_table[] = { + {0, -40000}, + {1584, -40000}, + {1620, -35000}, + {1652, -30000}, + {1688, -25000}, + {1720, -20000}, + {1756, -15000}, + {1788, -10000}, + {1824, -5000}, + {1856, 0}, + {1892, 5000}, + {1924, 10000}, + {1956, 15000}, + {1992, 20000}, + {2024, 25000}, + {2060, 30000}, + {2092, 35000}, + {2128, 40000}, + {2160, 45000}, + {2196, 50000}, + {2228, 55000}, + {2264, 60000}, + {2300, 65000}, + {2332, 70000}, + {2368, 75000}, + {2400, 80000}, + {2436, 85000}, + {2468, 90000}, + {2500, 95000}, + {2536, 100000}, + {2572, 105000}, + {2604, 110000}, + {2636, 115000}, + {2672, 120000}, + {2704, 125000}, + {TSADCV2_DATA_MASK, 125000}, +}; + static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table, int temp) { @@ -701,6 +750,49 @@ static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs, regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV); } +static void rk_tsadcv7_initialize(struct regmap *grf, void __iomem *regs, + enum tshut_polarity tshut_polarity) +{ + writel_relaxed(TSADCV5_USER_INTER_PD_SOC, regs + TSADCV2_USER_CON); + writel_relaxed(TSADCV5_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV5_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); + + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, + regs + TSADCV2_AUTO_CON); + else + writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, + regs + TSADCV2_AUTO_CON); + + /* + * The general register file will is optional + * and might not be available. + */ + if (!IS_ERR(grf)) { + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_TSEN); + /* + * RK3568 TRM, section 18.5. requires a delay no less + * than 10us between the rising edge of tsadc_tsen_en + * and the rising edge of tsadc_ana_reg_0/1/2. + */ + udelay(15); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG0); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG1); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG2); + + /* + * RK3568 TRM, section 18.5. requires a delay no less + * than 90us after the rising edge of tsadc_ana_reg_0/1/2. + */ + usleep_range(100, 200); + } +} + static void rk_tsadcv2_irq_ack(void __iomem *regs) { u32 val; @@ -1027,6 +1119,31 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { }, }; +static const struct rockchip_tsadc_chip rk3568_tsadc_data = { + .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ + .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ + .chn_num = 2, /* two channels for tsadc */ + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv7_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = rk3568_code_table, + .length = ARRAY_SIZE(rk3568_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + static const struct of_device_id of_rockchip_thermal_match[] = { { .compatible = "rockchip,px30-tsadc", .data = (void *)&px30_tsadc_data, @@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { .compatible = "rockchip,rk3399-tsadc", .data = (void *)&rk3399_tsadc_data, }, + { + .compatible = "rockchip,rk3568-tsadc", + .data = (void *)&rk3568_tsadc_data, + }, { /* end */ }, }; MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c index 3682edb2f466..fff80fc18002 100644 --- a/drivers/thermal/sprd_thermal.c +++ b/drivers/thermal/sprd_thermal.c @@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev) sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL); if (!sen) { ret = -ENOMEM; - goto disable_clk; + goto of_put; } sen->data = thm; @@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev) ret = of_property_read_u32(sen_child, "reg", &sen->id); if (ret) { dev_err(&pdev->dev, "get sensor reg failed"); - goto disable_clk; + goto of_put; } ret = sprd_thm_sensor_calibration(sen_child, thm, sen); if (ret) { dev_err(&pdev->dev, "efuse cal analysis failed"); - goto disable_clk; + goto of_put; } sprd_thm_sensor_init(thm, sen); @@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev) dev_err(&pdev->dev, "register thermal zone failed %d\n", sen->id); ret = PTR_ERR(sen->tzd); - goto disable_clk; + goto of_put; } thm->sensor[sen->id] = sen; } + /* sen_child set to NULL at this point */ ret = sprd_thm_set_ready(thm); if (ret) - goto disable_clk; + goto of_put; ret = sprd_thm_wait_temp_ready(thm); if (ret) - goto disable_clk; + goto of_put; for (i = 0; i < thm->nr_sensors; i++) sprd_thm_toggle_sensor(thm->sensor[i], true); @@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, thm); return 0; +of_put: + of_node_put(sen_child); disable_clk: clk_disable_unprepare(thm->clk); return ret; @@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = { { .compatible = "sprd,ums512-thermal", .data = &ums512_data }, { }, }; +MODULE_DEVICE_TABLE(of, sprd_thermal_of_match); static const struct dev_pm_ops sprd_thermal_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume) diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c index a0114452d11f..d68596c40be9 100644 --- a/drivers/thermal/st/st_thermal_memmap.c +++ b/drivers/thermal/st/st_thermal_memmap.c @@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor) { struct device *dev = sensor->dev; struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no memory resources defined\n"); - return -ENODEV; - } - - sensor->mmio_base = devm_ioremap_resource(dev, res); - if (IS_ERR(sensor->mmio_base)) { - dev_err(dev, "failed to remap IO\n"); + sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(sensor->mmio_base)) return PTR_ERR(sensor->mmio_base); - } sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base, &st_416mpe_regmap_config); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 10a2d8e1cacf..97ef9b040b84 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1315,7 +1315,7 @@ free_tz: EXPORT_SYMBOL_GPL(thermal_zone_device_register); /** - * thermal_device_unregister - removes the registered thermal zone device + * thermal_zone_device_unregister - removes the registered thermal zone device * @tz: the thermal zone device to remove */ void thermal_zone_device_unregister(struct thermal_zone_device *tz) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 5b76f9a1280d..6379f26a335f 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev, if (!tz) return; + /* stop temperature polling */ + thermal_zone_device_disable(tzd); + mutex_lock(&tzd->lock); tzd->ops->get_temp = NULL; tzd->ops->get_trend = NULL; diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 476c11278235..23cc988c68a4 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -12,9 +12,8 @@ if TTY config VT bool "Virtual terminal" if EXPERT - depends on !UML select INPUT - default y + default y if !UML help If you say Y here, you will get support for terminal devices with display and keyboard devices. These are called "virtual" because you @@ -78,7 +77,7 @@ config VT_CONSOLE_SLEEP config HW_CONSOLE bool - depends on VT && !UML + depends on VT default y config VT_HW_CONSOLE_BINDING diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c index 1a661ab45af5..6e197fe0fcf9 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.c +++ b/drivers/vdpa/ifcvf/ifcvf_base.c @@ -133,6 +133,8 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev) &hw->notify_off_multiplier); hw->notify_bar = cap.bar; hw->notify_base = get_cap_addr(hw, &cap); + hw->notify_base_pa = pci_resource_start(pdev, cap.bar) + + le32_to_cpu(cap.offset); IFCVF_DBG(pdev, "hw->notify_base = %p\n", hw->notify_base); break; @@ -161,6 +163,8 @@ next: notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off); hw->vring[i].notify_addr = hw->notify_base + notify_off * hw->notify_off_multiplier; + hw->vring[i].notify_pa = hw->notify_base_pa + + notify_off * hw->notify_off_multiplier; } hw->lm_cfg = hw->base[IFCVF_LM_BAR]; diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h index 0111bfdeb342..2996db0da490 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.h +++ b/drivers/vdpa/ifcvf/ifcvf_base.h @@ -19,21 +19,9 @@ #include #include -#define N3000_VENDOR_ID 0x1AF4 #define N3000_DEVICE_ID 0x1041 -#define N3000_SUBSYS_VENDOR_ID 0x8086 #define N3000_SUBSYS_DEVICE_ID 0x001A -#define C5000X_PL_VENDOR_ID 0x1AF4 -#define C5000X_PL_DEVICE_ID 0x1000 -#define C5000X_PL_SUBSYS_VENDOR_ID 0x8086 -#define C5000X_PL_SUBSYS_DEVICE_ID 0x0001 - -#define C5000X_PL_BLK_VENDOR_ID 0x1AF4 -#define C5000X_PL_BLK_DEVICE_ID 0x1001 -#define C5000X_PL_BLK_SUBSYS_VENDOR_ID 0x8086 -#define C5000X_PL_BLK_SUBSYS_DEVICE_ID 0x0002 - #define IFCVF_NET_SUPPORTED_FEATURES \ ((1ULL << VIRTIO_NET_F_MAC) | \ (1ULL << VIRTIO_F_ANY_LAYOUT) | \ @@ -73,6 +61,7 @@ struct vring_info { u16 last_avail_idx; bool ready; void __iomem *notify_addr; + phys_addr_t notify_pa; u32 irq; struct vdpa_callback cb; char msix_name[256]; @@ -87,6 +76,7 @@ struct ifcvf_hw { u8 notify_bar; /* Notificaiton bar address */ void __iomem *notify_base; + phys_addr_t notify_base_pa; u32 notify_off_multiplier; u64 req_features; u64 hw_features; diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index ab0ab5cf0f6e..21b78f1cd521 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -264,7 +264,7 @@ static int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid, { struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); - state->avail_index = ifcvf_get_vq_state(vf, qid); + state->split.avail_index = ifcvf_get_vq_state(vf, qid); return 0; } @@ -273,7 +273,7 @@ static int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid, { struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); - return ifcvf_set_vq_state(vf, qid, state->avail_index); + return ifcvf_set_vq_state(vf, qid, state->split.avail_index); } static void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid, @@ -413,6 +413,21 @@ static int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev, return vf->vring[qid].irq; } +static struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev, + u16 idx) +{ + struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); + struct vdpa_notification_area area; + + area.addr = vf->vring[idx].notify_pa; + if (!vf->notify_off_multiplier) + area.size = PAGE_SIZE; + else + area.size = vf->notify_off_multiplier; + + return area; +} + /* * IFCVF currently does't have on-chip IOMMU, so not * implemented set_map()/dma_map()/dma_unmap() @@ -440,6 +455,7 @@ static const struct vdpa_config_ops ifc_vdpa_ops = { .get_config = ifcvf_vdpa_get_config, .set_config = ifcvf_vdpa_set_config, .set_config_cb = ifcvf_vdpa_set_config_cb, + .get_vq_notification = ifcvf_get_vq_notification, }; static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -536,18 +552,21 @@ static void ifcvf_remove(struct pci_dev *pdev) } static struct pci_device_id ifcvf_pci_ids[] = { - { PCI_DEVICE_SUB(N3000_VENDOR_ID, + /* N3000 network device */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, N3000_DEVICE_ID, - N3000_SUBSYS_VENDOR_ID, + PCI_VENDOR_ID_INTEL, N3000_SUBSYS_DEVICE_ID) }, - { PCI_DEVICE_SUB(C5000X_PL_VENDOR_ID, - C5000X_PL_DEVICE_ID, - C5000X_PL_SUBSYS_VENDOR_ID, - C5000X_PL_SUBSYS_DEVICE_ID) }, - { PCI_DEVICE_SUB(C5000X_PL_BLK_VENDOR_ID, - C5000X_PL_BLK_DEVICE_ID, - C5000X_PL_BLK_SUBSYS_VENDOR_ID, - C5000X_PL_BLK_SUBSYS_DEVICE_ID) }, + /* C5000X-PL network device */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, + VIRTIO_TRANS_ID_NET, + PCI_VENDOR_ID_INTEL, + VIRTIO_ID_NET) }, + /* C5000X-PL block device */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, + VIRTIO_TRANS_ID_BLOCK, + PCI_VENDOR_ID_INTEL, + VIRTIO_ID_BLOCK) }, { 0 }, }; diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h index b6cc53ba980c..0002b2136b48 100644 --- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h +++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h @@ -35,12 +35,14 @@ struct mlx5_vdpa_mr { /* serialize mkey creation and destruction */ struct mutex mkey_mtx; + bool user_mr; }; struct mlx5_vdpa_resources { u32 pdn; struct mlx5_uars_page *uar; void __iomem *kick_addr; + u64 phys_kick_addr; u16 uid; u32 null_mkey; bool valid; diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c index 800cfd1967ad..dcee6039e966 100644 --- a/drivers/vdpa/mlx5/core/mr.c +++ b/drivers/vdpa/mlx5/core/mr.c @@ -219,11 +219,6 @@ static void destroy_indirect_key(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_m mlx5_vdpa_destroy_mkey(mvdev, &mkey->mkey); } -static struct device *get_dma_device(struct mlx5_vdpa_dev *mvdev) -{ - return &mvdev->mdev->pdev->dev; -} - static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr, struct vhost_iotlb *iotlb) { @@ -239,7 +234,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr u64 pa; u64 paend; struct scatterlist *sg; - struct device *dma = get_dma_device(mvdev); + struct device *dma = mvdev->vdev.dma_dev; for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1); map; map = vhost_iotlb_itree_next(map, start, mr->end - 1)) { @@ -298,7 +293,7 @@ err_map: static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr) { - struct device *dma = get_dma_device(mvdev); + struct device *dma = mvdev->vdev.dma_dev; destroy_direct_mr(mvdev, mr); dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0); @@ -360,7 +355,7 @@ err_alloc: * indirect memory key that provides access to the enitre address space given * by iotlb. */ -static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) { struct mlx5_vdpa_mr *mr = &mvdev->mr; struct mlx5_vdpa_direct_mr *dmr; @@ -374,9 +369,6 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb int err = 0; int nnuls; - if (mr->initialized) - return 0; - INIT_LIST_HEAD(&mr->head); for (map = vhost_iotlb_itree_first(iotlb, start, last); map; map = vhost_iotlb_itree_next(map, start, last)) { @@ -414,7 +406,7 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb if (err) goto err_chain; - mr->initialized = true; + mr->user_mr = true; return 0; err_chain: @@ -426,33 +418,94 @@ err_chain: return err; } -int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +static int create_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr) +{ + int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); + void *mkc; + u32 *in; + int err; + + in = kzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); + + MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA); + MLX5_SET(mkc, mkc, length64, 1); + MLX5_SET(mkc, mkc, lw, 1); + MLX5_SET(mkc, mkc, lr, 1); + MLX5_SET(mkc, mkc, pd, mvdev->res.pdn); + MLX5_SET(mkc, mkc, qpn, 0xffffff); + + err = mlx5_vdpa_create_mkey(mvdev, &mr->mkey, in, inlen); + if (!err) + mr->user_mr = false; + + kfree(in); + return err; +} + +static void destroy_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr) +{ + mlx5_vdpa_destroy_mkey(mvdev, &mr->mkey); +} + +static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) { struct mlx5_vdpa_mr *mr = &mvdev->mr; int err; - mutex_lock(&mr->mkey_mtx); - err = _mlx5_vdpa_create_mr(mvdev, iotlb); - mutex_unlock(&mr->mkey_mtx); + if (mr->initialized) + return 0; + + if (iotlb) + err = create_user_mr(mvdev, iotlb); + else + err = create_dma_mr(mvdev, mr); + + if (!err) + mr->initialized = true; + return err; } -void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev) +int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb) +{ + int err; + + mutex_lock(&mvdev->mr.mkey_mtx); + err = _mlx5_vdpa_create_mr(mvdev, iotlb); + mutex_unlock(&mvdev->mr.mkey_mtx); + return err; +} + +static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr) { - struct mlx5_vdpa_mr *mr = &mvdev->mr; struct mlx5_vdpa_direct_mr *dmr; struct mlx5_vdpa_direct_mr *n; - mutex_lock(&mr->mkey_mtx); - if (!mr->initialized) - goto out; - destroy_indirect_key(mvdev, mr); list_for_each_entry_safe_reverse(dmr, n, &mr->head, list) { list_del_init(&dmr->list); unmap_direct_mr(mvdev, dmr); kfree(dmr); } +} + +void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev) +{ + struct mlx5_vdpa_mr *mr = &mvdev->mr; + + mutex_lock(&mr->mkey_mtx); + if (!mr->initialized) + goto out; + + if (mr->user_mr) + destroy_user_mr(mvdev, mr); + else + destroy_dma_mr(mvdev, mr); + memset(mr, 0, sizeof(*mr)); mr->initialized = false; out: diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c index 6521cbd0f5c2..d4606213f88a 100644 --- a/drivers/vdpa/mlx5/core/resources.c +++ b/drivers/vdpa/mlx5/core/resources.c @@ -54,6 +54,9 @@ static int create_uctx(struct mlx5_vdpa_dev *mvdev, u16 *uid) void *in; int err; + if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) + return 0; + /* 0 means not supported */ if (!MLX5_CAP_GEN(mvdev->mdev, log_max_uctx)) return -EOPNOTSUPP; @@ -79,6 +82,9 @@ static void destroy_uctx(struct mlx5_vdpa_dev *mvdev, u32 uid) u32 out[MLX5_ST_SZ_DW(destroy_uctx_out)] = {}; u32 in[MLX5_ST_SZ_DW(destroy_uctx_in)] = {}; + if (!uid) + return; + MLX5_SET(destroy_uctx_in, in, opcode, MLX5_CMD_OP_DESTROY_UCTX); MLX5_SET(destroy_uctx_in, in, uid, uid); @@ -247,6 +253,7 @@ int mlx5_vdpa_alloc_resources(struct mlx5_vdpa_dev *mvdev) goto err_key; kick_addr = mdev->bar_addr + offset; + res->phys_kick_addr = kick_addr; res->kick_addr = ioremap(kick_addr, PAGE_SIZE); if (!res->kick_addr) { diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index dda5dc6f7737..2a31467f7ac5 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -611,8 +611,8 @@ static void cq_destroy(struct mlx5_vdpa_net *ndev, u16 idx) mlx5_db_free(ndev->mvdev.mdev, &vcq->db); } -static int umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num, - struct mlx5_vdpa_umem **umemp) +static void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num, + struct mlx5_vdpa_umem **umemp) { struct mlx5_core_dev *mdev = ndev->mvdev.mdev; int p_a; @@ -635,7 +635,7 @@ static int umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq *umemp = &mvq->umem3; break; } - return p_a * mvq->num_ent + p_b; + (*umemp)->size = p_a * mvq->num_ent + p_b; } static void umem_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem) @@ -651,15 +651,10 @@ static int create_umem(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m void *in; int err; __be64 *pas; - int size; struct mlx5_vdpa_umem *umem; - size = umem_size(ndev, mvq, num, &umem); - if (size < 0) - return size; - - umem->size = size; - err = umem_frag_buf_alloc(ndev, umem, size); + set_umem_size(ndev, mvq, num, &umem); + err = umem_frag_buf_alloc(ndev, umem, umem->size); if (err) return err; @@ -829,9 +824,9 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id); MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size); MLX5_SET(virtio_q, vq_ctx, umem_2_id, mvq->umem2.id); - MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem1.size); + MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem2.size); MLX5_SET(virtio_q, vq_ctx, umem_3_id, mvq->umem3.id); - MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem1.size); + MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem3.size); MLX5_SET(virtio_q, vq_ctx, pd, ndev->mvdev.res.pdn); if (MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, eth_frame_offload_type)) MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, 1); @@ -1428,8 +1423,8 @@ static int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx, return -EINVAL; } - mvq->used_idx = state->avail_index; - mvq->avail_idx = state->avail_index; + mvq->used_idx = state->split.avail_index; + mvq->avail_idx = state->split.avail_index; return 0; } @@ -1450,7 +1445,7 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa * Since both values should be identical, we take the value of * used_idx which is reported correctly. */ - state->avail_index = mvq->used_idx; + state->split.avail_index = mvq->used_idx; return 0; } @@ -1459,7 +1454,7 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa mlx5_vdpa_warn(mvdev, "failed to query virtqueue\n"); return err; } - state->avail_index = attr.used_index; + state->split.avail_index = attr.used_index; return 0; } @@ -1772,6 +1767,14 @@ out: mutex_unlock(&ndev->reslock); } +static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) +{ + int i; + + for (i = 0; i < ndev->mvdev.max_vqs; i++) + ndev->vqs[i].ready = false; +} + static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); @@ -1782,10 +1785,15 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) if (!status) { mlx5_vdpa_info(mvdev, "performing device reset\n"); teardown_driver(ndev); + clear_vqs_ready(ndev); mlx5_vdpa_destroy_mr(&ndev->mvdev); ndev->mvdev.status = 0; ndev->mvdev.mlx_features = 0; ++mvdev->generation; + if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { + if (mlx5_vdpa_create_mr(mvdev, NULL)) + mlx5_vdpa_warn(mvdev, "create MR failed\n"); + } return; } @@ -1866,6 +1874,7 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev) ndev = to_mlx5_vdpa_ndev(mvdev); free_resources(ndev); + mlx5_vdpa_destroy_mr(mvdev); if (!is_zero_ether_addr(ndev->config.mac)) { pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); mlx5_mpfs_del_mac(pfmdev, ndev->config.mac); @@ -1876,8 +1885,22 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev) static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx) { + struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct vdpa_notification_area ret = {}; + struct mlx5_vdpa_net *ndev; + phys_addr_t addr; + /* If SF BAR size is smaller than PAGE_SIZE, do not use direct + * notification to avoid the risk of mapping pages that contain BAR of more + * than one SF + */ + if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT) + return ret; + + ndev = to_mlx5_vdpa_ndev(mvdev); + addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr; + ret.addr = addr; + ret.size = PAGE_SIZE; return ret; } @@ -2037,14 +2060,20 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name) goto err_mtu; } - mvdev->vdev.dma_dev = mdev->device; + mvdev->vdev.dma_dev = &mdev->pdev->dev; err = mlx5_vdpa_alloc_resources(&ndev->mvdev); if (err) goto err_mpfs; + if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) { + err = mlx5_vdpa_create_mr(mvdev, NULL); + if (err) + goto err_res; + } + err = alloc_resources(ndev); if (err) - goto err_res; + goto err_mr; mvdev->vdev.mdev = &mgtdev->mgtdev; err = _vdpa_register_device(&mvdev->vdev, 2 * mlx5_vdpa_max_qps(max_vqs)); @@ -2056,6 +2085,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name) err_reg: free_resources(ndev); +err_mr: + mlx5_vdpa_destroy_mr(mvdev); err_res: mlx5_vdpa_free_resources(&ndev->mvdev); err_mpfs: diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 98f793bc9376..14e024de5cbf 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -374,7 +374,7 @@ static int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, struct vringh *vrh = &vq->vring; spin_lock(&vdpasim->lock); - vrh->last_avail_idx = state->avail_index; + vrh->last_avail_idx = state->split.avail_index; spin_unlock(&vdpasim->lock); return 0; @@ -387,7 +387,7 @@ static int vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx, struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; struct vringh *vrh = &vq->vring; - state->avail_index = vrh->last_avail_idx; + state->split.avail_index = vrh->last_avail_idx; return 0; } diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index 5bfe1c281645..a790903f243e 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "vdpa_sim.h" diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c index c76ebb531212..7b4a6396c553 100644 --- a/drivers/vdpa/virtio_pci/vp_vdpa.c +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c @@ -210,13 +210,49 @@ static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid, return -EOPNOTSUPP; } +static int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa, + const struct vdpa_vq_state *state) +{ + const struct vdpa_vq_state_split *split = &state->split; + + if (split->avail_index == 0) + return 0; + + return -EOPNOTSUPP; +} + +static int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa, + const struct vdpa_vq_state *state) +{ + const struct vdpa_vq_state_packed *packed = &state->packed; + + if (packed->last_avail_counter == 1 && + packed->last_avail_idx == 0 && + packed->last_used_counter == 1 && + packed->last_used_idx == 0) + return 0; + + return -EOPNOTSUPP; +} + static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid, const struct vdpa_vq_state *state) { - /* Note that this is not supported by virtio specification, so - * we return -ENOPOTSUPP here. This means we can't support live - * migration, vhost device start/stop. + struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); + + /* Note that this is not supported by virtio specification. + * But if the state is by chance equal to the device initial + * state, we can let it go. */ + if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) && + !vp_modern_get_queue_enable(mdev, qid)) { + if (vp_modern_get_driver_features(mdev) & + BIT_ULL(VIRTIO_F_RING_PACKED)) + return vp_vdpa_set_vq_state_packed(vdpa, state); + else + return vp_vdpa_set_vq_state_split(vdpa, state); + } + return -EOPNOTSUPP; } @@ -442,6 +478,7 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) vp_modern_map_vq_notify(mdev, i, &vp_vdpa->vring[i].notify_pa); if (!vp_vdpa->vring[i].notify) { + ret = -EINVAL; dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i); goto err; } diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c index 0fd3f87e913c..0582079e4bcc 100644 --- a/drivers/vhost/iotlb.c +++ b/drivers/vhost/iotlb.c @@ -83,7 +83,7 @@ int vhost_iotlb_add_range(struct vhost_iotlb *iotlb, EXPORT_SYMBOL_GPL(vhost_iotlb_add_range); /** - * vring_iotlb_del_range - delete overlapped ranges from vhost IOTLB + * vhost_iotlb_del_range - delete overlapped ranges from vhost IOTLB * @iotlb: the IOTLB * @start: start of the IOVA range * @last: last of IOVA range diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index d16c04dcc144..46f897e41217 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1430,11 +1430,6 @@ static void vhost_scsi_handle_kick(struct vhost_work *work) vhost_scsi_handle_vq(vs, vq); } -static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index) -{ - vhost_poll_flush(&vs->vqs[index].vq.poll); -} - /* Callers must hold dev mutex */ static void vhost_scsi_flush(struct vhost_scsi *vs) { @@ -1453,10 +1448,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs) kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight); /* Flush both the vhost poll and vhost work */ - for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) - vhost_scsi_flush_vq(vs, i); - vhost_work_flush(&vs->dev, &vs->vs_completion_work); - vhost_work_flush(&vs->dev, &vs->vs_event_work); + vhost_work_dev_flush(&vs->dev); /* Wait for all reqs issued before the flush to be finished */ for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) @@ -1740,11 +1732,12 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, mutex_lock(&vq->mutex); vhost_vq_set_backend(vq, NULL); mutex_unlock(&vq->mutex); - /* - * Make sure cmds are not running before tearing them - * down. - */ - vhost_scsi_flush(vs); + } + /* Make sure cmds are not running before tearing them down. */ + vhost_scsi_flush(vs); + + for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) { + vq = &vs->vqs[i].vq; vhost_scsi_destroy_vq_cmds(vq); } } diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index fb41db3da611..210ab35a7ebf 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -383,7 +383,7 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, if (r) return r; - vq->last_avail_idx = vq_state.avail_index; + vq->last_avail_idx = vq_state.split.avail_index; break; } @@ -401,7 +401,7 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, break; case VHOST_SET_VRING_BASE: - vq_state.avail_index = vq->last_avail_idx; + vq_state.split.avail_index = vq->last_avail_idx; if (ops->set_vq_state(vdpa, idx, &vq_state)) r = -EINVAL; break; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 5ccb0705beae..b9e853e6094d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -231,7 +231,7 @@ void vhost_poll_stop(struct vhost_poll *poll) } EXPORT_SYMBOL_GPL(vhost_poll_stop); -void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work) +void vhost_work_dev_flush(struct vhost_dev *dev) { struct vhost_flush_struct flush; @@ -243,13 +243,13 @@ void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work) wait_for_completion(&flush.wait_event); } } -EXPORT_SYMBOL_GPL(vhost_work_flush); +EXPORT_SYMBOL_GPL(vhost_work_dev_flush); /* Flush any work that has been scheduled. When calling this, don't hold any * locks that are also used by the callback. */ void vhost_poll_flush(struct vhost_poll *poll) { - vhost_work_flush(poll->dev, &poll->work); + vhost_work_dev_flush(poll->dev); } EXPORT_SYMBOL_GPL(vhost_poll_flush); @@ -538,7 +538,7 @@ static int vhost_attach_cgroups(struct vhost_dev *dev) attach.owner = current; vhost_work_init(&attach.work, vhost_attach_cgroups_work); vhost_work_queue(dev, &attach.work); - vhost_work_flush(dev, &attach.work); + vhost_work_dev_flush(dev); return attach.ret; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index b063324c7669..638bb640d6b4 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -20,20 +20,20 @@ typedef void (*vhost_work_fn_t)(struct vhost_work *work); #define VHOST_WORK_QUEUED 1 struct vhost_work { - struct llist_node node; - vhost_work_fn_t fn; - unsigned long flags; + struct llist_node node; + vhost_work_fn_t fn; + unsigned long flags; }; /* Poll a file (eventfd or socket) */ /* Note: there's nothing vhost specific about this structure. */ struct vhost_poll { - poll_table table; - wait_queue_head_t *wqh; - wait_queue_entry_t wait; - struct vhost_work work; - __poll_t mask; - struct vhost_dev *dev; + poll_table table; + wait_queue_head_t *wqh; + wait_queue_entry_t wait; + struct vhost_work work; + __poll_t mask; + struct vhost_dev *dev; }; void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn); @@ -46,8 +46,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file); void vhost_poll_stop(struct vhost_poll *poll); void vhost_poll_flush(struct vhost_poll *poll); void vhost_poll_queue(struct vhost_poll *poll); -void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work); -long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp); +void vhost_work_dev_flush(struct vhost_dev *dev); struct vhost_log { u64 addr; diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index d38c996b4f46..f249622ef11b 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -708,7 +708,7 @@ static void vhost_vsock_flush(struct vhost_vsock *vsock) for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) if (vsock->vqs[i].handle_kick) vhost_poll_flush(&vsock->vqs[i].poll); - vhost_work_flush(&vsock->dev, &vsock->send_pkt_work); + vhost_work_dev_flush(&vsock->dev); } static void vhost_vsock_reset_orphans(struct sock *sk) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index ee33b8ec62bb..840d9813b0bc 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -9,7 +9,7 @@ config VGA_CONSOLE bool "VGA text console" if EXPERT || !X86 depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 + !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 && !UML default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index dc2a2e2b2ff8..09ed55de07d7 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -75,10 +75,14 @@ enum virtio_mem_sbm_mb_state { VIRTIO_MEM_SBM_MB_OFFLINE, /* Partially plugged, fully added to Linux, offline. */ VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL, - /* Fully plugged, fully added to Linux, online. */ - VIRTIO_MEM_SBM_MB_ONLINE, - /* Partially plugged, fully added to Linux, online. */ - VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL, + /* Fully plugged, fully added to Linux, onlined to a kernel zone. */ + VIRTIO_MEM_SBM_MB_KERNEL, + /* Partially plugged, fully added to Linux, online to a kernel zone */ + VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL, + /* Fully plugged, fully added to Linux, onlined to ZONE_MOVABLE. */ + VIRTIO_MEM_SBM_MB_MOVABLE, + /* Partially plugged, fully added to Linux, onlined to ZONE_MOVABLE. */ + VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL, VIRTIO_MEM_SBM_MB_COUNT }; @@ -698,18 +702,6 @@ static int virtio_mem_sbm_remove_mb(struct virtio_mem *vm, unsigned long mb_id) return virtio_mem_remove_memory(vm, addr, size); } -/* - * See virtio_mem_remove_memory(): Try to remove all Linux memory blocks covered - * by the big block. - */ -static int virtio_mem_bbm_remove_bb(struct virtio_mem *vm, unsigned long bb_id) -{ - const uint64_t addr = virtio_mem_bb_id_to_phys(vm, bb_id); - const uint64_t size = vm->bbm.bb_size; - - return virtio_mem_remove_memory(vm, addr, size); -} - /* * Try offlining and removing memory from Linux. * @@ -832,11 +824,13 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm, unsigned long mb_id) { switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) { - case VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL: + case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL: + case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL: virtio_mem_sbm_set_mb_state(vm, mb_id, VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL); break; - case VIRTIO_MEM_SBM_MB_ONLINE: + case VIRTIO_MEM_SBM_MB_KERNEL: + case VIRTIO_MEM_SBM_MB_MOVABLE: virtio_mem_sbm_set_mb_state(vm, mb_id, VIRTIO_MEM_SBM_MB_OFFLINE); break; @@ -847,21 +841,29 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm, } static void virtio_mem_sbm_notify_online(struct virtio_mem *vm, - unsigned long mb_id) + unsigned long mb_id, + unsigned long start_pfn) { + const bool is_movable = page_zonenum(pfn_to_page(start_pfn)) == + ZONE_MOVABLE; + int new_state; + switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) { case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL: - virtio_mem_sbm_set_mb_state(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL); + new_state = VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL; + if (is_movable) + new_state = VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL; break; case VIRTIO_MEM_SBM_MB_OFFLINE: - virtio_mem_sbm_set_mb_state(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE); + new_state = VIRTIO_MEM_SBM_MB_KERNEL; + if (is_movable) + new_state = VIRTIO_MEM_SBM_MB_MOVABLE; break; default: BUG(); break; } + virtio_mem_sbm_set_mb_state(vm, mb_id, new_state); } static void virtio_mem_sbm_notify_going_offline(struct virtio_mem *vm, @@ -1015,7 +1017,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, break; case MEM_ONLINE: if (vm->in_sbm) - virtio_mem_sbm_notify_online(vm, id); + virtio_mem_sbm_notify_online(vm, id, mhp->start_pfn); atomic64_sub(size, &vm->offline_size); /* @@ -1137,7 +1139,7 @@ static void virtio_mem_fake_online(unsigned long pfn, unsigned long nr_pages) */ static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages) { - const bool is_movable = zone_idx(page_zone(pfn_to_page(pfn))) == + const bool is_movable = page_zonenum(pfn_to_page(pfn)) == ZONE_MOVABLE; int rc, retry_count; @@ -1455,8 +1457,8 @@ static int virtio_mem_bbm_plug_bb(struct virtio_mem *vm, unsigned long bb_id) * * Note: can fail after some subblocks were unplugged. */ -static int virtio_mem_sbm_unplug_any_sb(struct virtio_mem *vm, - unsigned long mb_id, uint64_t *nb_sb) +static int virtio_mem_sbm_unplug_any_sb_raw(struct virtio_mem *vm, + unsigned long mb_id, uint64_t *nb_sb) { int sb_id, count; int rc; @@ -1498,7 +1500,7 @@ static int virtio_mem_sbm_unplug_mb(struct virtio_mem *vm, unsigned long mb_id) { uint64_t nb_sb = vm->sbm.sbs_per_mb; - return virtio_mem_sbm_unplug_any_sb(vm, mb_id, &nb_sb); + return virtio_mem_sbm_unplug_any_sb_raw(vm, mb_id, &nb_sb); } /* @@ -1585,9 +1587,9 @@ static int virtio_mem_sbm_plug_and_add_mb(struct virtio_mem *vm, * Note: Can fail after some subblocks were successfully plugged. */ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm, - unsigned long mb_id, uint64_t *nb_sb, - bool online) + unsigned long mb_id, uint64_t *nb_sb) { + const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id); unsigned long pfn, nr_pages; int sb_id, count; int rc; @@ -1609,7 +1611,7 @@ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm, if (rc) return rc; *nb_sb -= count; - if (!online) + if (old_state == VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) continue; /* fake-online the pages if the memory block is online */ @@ -1619,23 +1621,22 @@ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm, virtio_mem_fake_online(pfn, nr_pages); } - if (virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) { - if (online) - virtio_mem_sbm_set_mb_state(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE); - else - virtio_mem_sbm_set_mb_state(vm, mb_id, - VIRTIO_MEM_SBM_MB_OFFLINE); - } + if (virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) + virtio_mem_sbm_set_mb_state(vm, mb_id, old_state - 1); return 0; } static int virtio_mem_sbm_plug_request(struct virtio_mem *vm, uint64_t diff) { + const int mb_states[] = { + VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL, + VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL, + VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL, + }; uint64_t nb_sb = diff / vm->sbm.sb_size; unsigned long mb_id; - int rc; + int rc, i; if (!nb_sb) return 0; @@ -1643,22 +1644,13 @@ static int virtio_mem_sbm_plug_request(struct virtio_mem *vm, uint64_t diff) /* Don't race with onlining/offlining */ mutex_lock(&vm->hotplug_mutex); - /* Try to plug subblocks of partially plugged online blocks. */ - virtio_mem_sbm_for_each_mb(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL) { - rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb, true); - if (rc || !nb_sb) - goto out_unlock; - cond_resched(); - } - - /* Try to plug subblocks of partially plugged offline blocks. */ - virtio_mem_sbm_for_each_mb(vm, mb_id, - VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) { - rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb, false); - if (rc || !nb_sb) - goto out_unlock; - cond_resched(); + for (i = 0; i < ARRAY_SIZE(mb_states); i++) { + virtio_mem_sbm_for_each_mb(vm, mb_id, mb_states[i]) { + rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb); + if (rc || !nb_sb) + goto out_unlock; + cond_resched(); + } } /* @@ -1819,7 +1811,7 @@ static int virtio_mem_sbm_unplug_any_sb_offline(struct virtio_mem *vm, { int rc; - rc = virtio_mem_sbm_unplug_any_sb(vm, mb_id, nb_sb); + rc = virtio_mem_sbm_unplug_any_sb_raw(vm, mb_id, nb_sb); /* some subblocks might have been unplugged even on failure */ if (!virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) @@ -1856,6 +1848,7 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm, int count) { const unsigned long nr_pages = PFN_DOWN(vm->sbm.sb_size) * count; + const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id); unsigned long start_pfn; int rc; @@ -1874,8 +1867,17 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm, return rc; } - virtio_mem_sbm_set_mb_state(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL); + switch (old_state) { + case VIRTIO_MEM_SBM_MB_KERNEL: + virtio_mem_sbm_set_mb_state(vm, mb_id, + VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL); + break; + case VIRTIO_MEM_SBM_MB_MOVABLE: + virtio_mem_sbm_set_mb_state(vm, mb_id, + VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL); + break; + } + return 0; } @@ -1942,11 +1944,50 @@ unplugged: return 0; } +/* + * Unplug the desired number of plugged subblocks of a memory block that is + * already added to Linux. Will skip subblock of online memory blocks that are + * busy (by the OS). Will fail if any subblock that's not busy cannot get + * unplugged. + * + * Will modify the state of the memory block. Might temporarily drop the + * hotplug_mutex. + * + * Note: Can fail after some subblocks were successfully unplugged. Can + * return 0 even if subblocks were busy and could not get unplugged. + */ +static int virtio_mem_sbm_unplug_any_sb(struct virtio_mem *vm, + unsigned long mb_id, + uint64_t *nb_sb) +{ + const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id); + + switch (old_state) { + case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL: + case VIRTIO_MEM_SBM_MB_KERNEL: + case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL: + case VIRTIO_MEM_SBM_MB_MOVABLE: + return virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, nb_sb); + case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL: + case VIRTIO_MEM_SBM_MB_OFFLINE: + return virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, nb_sb); + } + return -EINVAL; +} + static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff) { + const int mb_states[] = { + VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL, + VIRTIO_MEM_SBM_MB_OFFLINE, + VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL, + VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL, + VIRTIO_MEM_SBM_MB_MOVABLE, + VIRTIO_MEM_SBM_MB_KERNEL, + }; uint64_t nb_sb = diff / vm->sbm.sb_size; unsigned long mb_id; - int rc; + int rc, i; if (!nb_sb) return 0; @@ -1958,47 +1999,26 @@ static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff) */ mutex_lock(&vm->hotplug_mutex); - /* Try to unplug subblocks of partially plugged offline blocks. */ - virtio_mem_sbm_for_each_mb_rev(vm, mb_id, - VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) { - rc = virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, &nb_sb); - if (rc || !nb_sb) - goto out_unlock; - cond_resched(); - } - - /* Try to unplug subblocks of plugged offline blocks. */ - virtio_mem_sbm_for_each_mb_rev(vm, mb_id, VIRTIO_MEM_SBM_MB_OFFLINE) { - rc = virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, &nb_sb); - if (rc || !nb_sb) - goto out_unlock; - cond_resched(); - } - - if (!unplug_online) { - mutex_unlock(&vm->hotplug_mutex); - return 0; - } - - /* Try to unplug subblocks of partially plugged online blocks. */ - virtio_mem_sbm_for_each_mb_rev(vm, mb_id, - VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL) { - rc = virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, &nb_sb); - if (rc || !nb_sb) - goto out_unlock; - mutex_unlock(&vm->hotplug_mutex); - cond_resched(); - mutex_lock(&vm->hotplug_mutex); - } - - /* Try to unplug subblocks of plugged online blocks. */ - virtio_mem_sbm_for_each_mb_rev(vm, mb_id, VIRTIO_MEM_SBM_MB_ONLINE) { - rc = virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, &nb_sb); - if (rc || !nb_sb) - goto out_unlock; - mutex_unlock(&vm->hotplug_mutex); - cond_resched(); - mutex_lock(&vm->hotplug_mutex); + /* + * We try unplug from partially plugged blocks first, to try removing + * whole memory blocks along with metadata. We prioritize ZONE_MOVABLE + * as it's more reliable to unplug memory and remove whole memory + * blocks, and we don't want to trigger a zone imbalances by + * accidentially removing too much kernel memory. + */ + for (i = 0; i < ARRAY_SIZE(mb_states); i++) { + virtio_mem_sbm_for_each_mb_rev(vm, mb_id, mb_states[i]) { + rc = virtio_mem_sbm_unplug_any_sb(vm, mb_id, &nb_sb); + if (rc || !nb_sb) + goto out_unlock; + mutex_unlock(&vm->hotplug_mutex); + cond_resched(); + mutex_lock(&vm->hotplug_mutex); + } + if (!unplug_online && i == 1) { + mutex_unlock(&vm->hotplug_mutex); + return 0; + } } mutex_unlock(&vm->hotplug_mutex); @@ -2084,35 +2104,6 @@ rollback_safe_unplug: return rc; } -/* - * Try to remove a big block from Linux and unplug it. Will fail with - * -EBUSY if some memory is online. - * - * Will modify the state of the memory block. - */ -static int virtio_mem_bbm_remove_and_unplug_bb(struct virtio_mem *vm, - unsigned long bb_id) -{ - int rc; - - if (WARN_ON_ONCE(virtio_mem_bbm_get_bb_state(vm, bb_id) != - VIRTIO_MEM_BBM_BB_ADDED)) - return -EINVAL; - - rc = virtio_mem_bbm_remove_bb(vm, bb_id); - if (rc) - return -EBUSY; - - rc = virtio_mem_bbm_unplug_bb(vm, bb_id); - if (rc) - virtio_mem_bbm_set_bb_state(vm, bb_id, - VIRTIO_MEM_BBM_BB_PLUGGED); - else - virtio_mem_bbm_set_bb_state(vm, bb_id, - VIRTIO_MEM_BBM_BB_UNUSED); - return rc; -} - /* * Test if a big block is completely offline. */ @@ -2132,46 +2123,64 @@ static bool virtio_mem_bbm_bb_is_offline(struct virtio_mem *vm, return true; } +/* + * Test if a big block is completely onlined to ZONE_MOVABLE (or offline). + */ +static bool virtio_mem_bbm_bb_is_movable(struct virtio_mem *vm, + unsigned long bb_id) +{ + const unsigned long start_pfn = PFN_DOWN(virtio_mem_bb_id_to_phys(vm, bb_id)); + const unsigned long nr_pages = PFN_DOWN(vm->bbm.bb_size); + struct page *page; + unsigned long pfn; + + for (pfn = start_pfn; pfn < start_pfn + nr_pages; + pfn += PAGES_PER_SECTION) { + page = pfn_to_online_page(pfn); + if (!page) + continue; + if (page_zonenum(page) != ZONE_MOVABLE) + return false; + } + + return true; +} + static int virtio_mem_bbm_unplug_request(struct virtio_mem *vm, uint64_t diff) { uint64_t nb_bb = diff / vm->bbm.bb_size; uint64_t bb_id; - int rc; + int rc, i; if (!nb_bb) return 0; - /* Try to unplug completely offline big blocks first. */ - virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) { - cond_resched(); - /* - * As we're holding no locks, this check is racy as memory - * can get onlined in the meantime - but we'll fail gracefully. - */ - if (!virtio_mem_bbm_bb_is_offline(vm, bb_id)) - continue; - rc = virtio_mem_bbm_remove_and_unplug_bb(vm, bb_id); - if (rc == -EBUSY) - continue; - if (!rc) - nb_bb--; - if (rc || !nb_bb) - return rc; - } + /* + * Try to unplug big blocks. Similar to SBM, start with offline + * big blocks. + */ + for (i = 0; i < 3; i++) { + virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) { + cond_resched(); - if (!unplug_online) - return 0; - - /* Try to unplug any big blocks. */ - virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) { - cond_resched(); - rc = virtio_mem_bbm_offline_remove_and_unplug_bb(vm, bb_id); - if (rc == -EBUSY) - continue; - if (!rc) - nb_bb--; - if (rc || !nb_bb) - return rc; + /* + * As we're holding no locks, these checks are racy, + * but we don't care. + */ + if (i == 0 && !virtio_mem_bbm_bb_is_offline(vm, bb_id)) + continue; + if (i == 1 && !virtio_mem_bbm_bb_is_movable(vm, bb_id)) + continue; + rc = virtio_mem_bbm_offline_remove_and_unplug_bb(vm, bb_id); + if (rc == -EBUSY) + continue; + if (!rc) + nb_bb--; + if (rc || !nb_bb) + return rc; + } + if (i == 0 && !unplug_online) + return 0; } return nb_bb ? -EBUSY : 0; @@ -2422,6 +2431,10 @@ static int virtio_mem_init(struct virtio_mem *vm) dev_warn(&vm->vdev->dev, "Some device memory is not addressable/pluggable. This can make some memory unusable.\n"); + /* Prepare the offline threshold - make sure we can add two blocks. */ + vm->offline_threshold = max_t(uint64_t, 2 * memory_block_size_bytes(), + VIRTIO_MEM_DEFAULT_OFFLINE_THRESHOLD); + /* * We want subblocks to span at least MAX_ORDER_NR_PAGES and * pageblock_nr_pages pages. This: @@ -2468,14 +2481,11 @@ static int virtio_mem_init(struct virtio_mem *vm) vm->bbm.bb_size - 1; vm->bbm.first_bb_id = virtio_mem_phys_to_bb_id(vm, addr); vm->bbm.next_bb_id = vm->bbm.first_bb_id; - } - /* Prepare the offline threshold - make sure we can add two blocks. */ - vm->offline_threshold = max_t(uint64_t, 2 * memory_block_size_bytes(), - VIRTIO_MEM_DEFAULT_OFFLINE_THRESHOLD); - /* In BBM, we also want at least two big blocks. */ - vm->offline_threshold = max_t(uint64_t, 2 * vm->bbm.bb_size, - vm->offline_threshold); + /* Make sure we can add two big blocks. */ + vm->offline_threshold = max_t(uint64_t, 2 * vm->bbm.bb_size, + vm->offline_threshold); + } dev_info(&vm->vdev->dev, "start address: 0x%llx", vm->addr); dev_info(&vm->vdev->dev, "region size: 0x%llx", vm->region_size); diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c index 54f297028586..e11ed748e661 100644 --- a/drivers/virtio/virtio_pci_modern_dev.c +++ b/drivers/virtio/virtio_pci_modern_dev.c @@ -383,6 +383,27 @@ u64 vp_modern_get_features(struct virtio_pci_modern_device *mdev) } EXPORT_SYMBOL_GPL(vp_modern_get_features); +/* + * vp_modern_get_driver_features - get driver features from device + * @mdev: the modern virtio-pci device + * + * Returns the driver features read from the device + */ +u64 vp_modern_get_driver_features(struct virtio_pci_modern_device *mdev) +{ + struct virtio_pci_common_cfg __iomem *cfg = mdev->common; + + u64 features; + + vp_iowrite32(0, &cfg->guest_feature_select); + features = vp_ioread32(&cfg->guest_feature); + vp_iowrite32(1, &cfg->guest_feature_select); + features |= ((u64)vp_ioread32(&cfg->guest_feature) << 32); + + return features; +} +EXPORT_SYMBOL_GPL(vp_modern_get_driver_features); + /* * vp_modern_set_features - set features to device * @mdev: the modern virtio-pci device diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 71e16b53e9c1..89bfe46a8a7f 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -74,14 +74,14 @@ struct vring_desc_state_packed { void *data; /* Data for callback. */ struct vring_packed_desc *indir_desc; /* Indirect descriptor, if any. */ u16 num; /* Descriptor list length. */ - u16 next; /* The next desc state in a list. */ u16 last; /* The last desc state in a list. */ }; -struct vring_desc_extra_packed { +struct vring_desc_extra { dma_addr_t addr; /* Buffer DMA addr. */ u32 len; /* Buffer length. */ u16 flags; /* Descriptor flags. */ + u16 next; /* The next desc state in a list. */ }; struct vring_virtqueue { @@ -113,6 +113,9 @@ struct vring_virtqueue { /* Last used index we've seen. */ u16 last_used_idx; + /* Hint for event idx: already triggered no need to disable. */ + bool event_triggered; + union { /* Available for split ring */ struct { @@ -130,6 +133,7 @@ struct vring_virtqueue { /* Per-descriptor state. */ struct vring_desc_state_split *desc_state; + struct vring_desc_extra *desc_extra; /* DMA address and size information */ dma_addr_t queue_dma_addr; @@ -166,7 +170,7 @@ struct vring_virtqueue { /* Per-descriptor state. */ struct vring_desc_state_packed *desc_state; - struct vring_desc_extra_packed *desc_extra; + struct vring_desc_extra *desc_extra; /* DMA address and size information */ dma_addr_t ring_dma_addr; @@ -364,8 +368,8 @@ static int vring_mapping_error(const struct vring_virtqueue *vq, * Split ring specific functions - *_split(). */ -static void vring_unmap_one_split(const struct vring_virtqueue *vq, - struct vring_desc *desc) +static void vring_unmap_one_split_indirect(const struct vring_virtqueue *vq, + struct vring_desc *desc) { u16 flags; @@ -389,6 +393,35 @@ static void vring_unmap_one_split(const struct vring_virtqueue *vq, } } +static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq, + unsigned int i) +{ + struct vring_desc_extra *extra = vq->split.desc_extra; + u16 flags; + + if (!vq->use_dma_api) + goto out; + + flags = extra[i].flags; + + if (flags & VRING_DESC_F_INDIRECT) { + dma_unmap_single(vring_dma_dev(vq), + extra[i].addr, + extra[i].len, + (flags & VRING_DESC_F_WRITE) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + } else { + dma_unmap_page(vring_dma_dev(vq), + extra[i].addr, + extra[i].len, + (flags & VRING_DESC_F_WRITE) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + } + +out: + return extra[i].next; +} + static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq, unsigned int total_sg, gfp_t gfp) @@ -412,6 +445,35 @@ static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq, return desc; } +static inline unsigned int virtqueue_add_desc_split(struct virtqueue *vq, + struct vring_desc *desc, + unsigned int i, + dma_addr_t addr, + unsigned int len, + u16 flags, + bool indirect) +{ + struct vring_virtqueue *vring = to_vvq(vq); + struct vring_desc_extra *extra = vring->split.desc_extra; + u16 next; + + desc[i].flags = cpu_to_virtio16(vq->vdev, flags); + desc[i].addr = cpu_to_virtio64(vq->vdev, addr); + desc[i].len = cpu_to_virtio32(vq->vdev, len); + + if (!indirect) { + next = extra[i].next; + desc[i].next = cpu_to_virtio16(vq->vdev, next); + + extra[i].addr = addr; + extra[i].len = len; + extra[i].flags = flags; + } else + next = virtio16_to_cpu(vq->vdev, desc[i].next); + + return next; +} + static inline int virtqueue_add_split(struct virtqueue *_vq, struct scatterlist *sgs[], unsigned int total_sg, @@ -484,11 +546,13 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, if (vring_mapping_error(vq, addr)) goto unmap_release; - desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT); - desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); - desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); prev = i; - i = virtio16_to_cpu(_vq->vdev, desc[i].next); + /* Note that we trust indirect descriptor + * table since it use stream DMA mapping. + */ + i = virtqueue_add_desc_split(_vq, desc, i, addr, sg->length, + VRING_DESC_F_NEXT, + indirect); } } for (; n < (out_sgs + in_sgs); n++) { @@ -497,15 +561,22 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, if (vring_mapping_error(vq, addr)) goto unmap_release; - desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE); - desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); - desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); prev = i; - i = virtio16_to_cpu(_vq->vdev, desc[i].next); + /* Note that we trust indirect descriptor + * table since it use stream DMA mapping. + */ + i = virtqueue_add_desc_split(_vq, desc, i, addr, + sg->length, + VRING_DESC_F_NEXT | + VRING_DESC_F_WRITE, + indirect); } } /* Last one doesn't continue. */ desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT); + if (!indirect && vq->use_dma_api) + vq->split.desc_extra[prev & (vq->split.vring.num - 1)].flags = + ~VRING_DESC_F_NEXT; if (indirect) { /* Now that the indirect table is filled in, map it. */ @@ -515,13 +586,11 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, if (vring_mapping_error(vq, addr)) goto unmap_release; - vq->split.vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, - VRING_DESC_F_INDIRECT); - vq->split.vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, - addr); - - vq->split.vring.desc[head].len = cpu_to_virtio32(_vq->vdev, - total_sg * sizeof(struct vring_desc)); + virtqueue_add_desc_split(_vq, vq->split.vring.desc, + head, addr, + total_sg * sizeof(struct vring_desc), + VRING_DESC_F_INDIRECT, + false); } /* We're using some buffers from the free list. */ @@ -529,8 +598,7 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, /* Update free pointer */ if (indirect) - vq->free_head = virtio16_to_cpu(_vq->vdev, - vq->split.vring.desc[head].next); + vq->free_head = vq->split.desc_extra[head].next; else vq->free_head = i; @@ -575,8 +643,11 @@ unmap_release: for (n = 0; n < total_sg; n++) { if (i == err_idx) break; - vring_unmap_one_split(vq, &desc[i]); - i = virtio16_to_cpu(_vq->vdev, desc[i].next); + if (indirect) { + vring_unmap_one_split_indirect(vq, &desc[i]); + i = virtio16_to_cpu(_vq->vdev, desc[i].next); + } else + i = vring_unmap_one_split(vq, i); } if (indirect) @@ -630,14 +701,13 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head, i = head; while (vq->split.vring.desc[i].flags & nextflag) { - vring_unmap_one_split(vq, &vq->split.vring.desc[i]); - i = virtio16_to_cpu(vq->vq.vdev, vq->split.vring.desc[i].next); + vring_unmap_one_split(vq, i); + i = vq->split.desc_extra[i].next; vq->vq.num_free++; } - vring_unmap_one_split(vq, &vq->split.vring.desc[i]); - vq->split.vring.desc[i].next = cpu_to_virtio16(vq->vq.vdev, - vq->free_head); + vring_unmap_one_split(vq, i); + vq->split.desc_extra[i].next = vq->free_head; vq->free_head = head; /* Plus final descriptor */ @@ -652,15 +722,14 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head, if (!indir_desc) return; - len = virtio32_to_cpu(vq->vq.vdev, - vq->split.vring.desc[head].len); + len = vq->split.desc_extra[head].len; - BUG_ON(!(vq->split.vring.desc[head].flags & - cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))); + BUG_ON(!(vq->split.desc_extra[head].flags & + VRING_DESC_F_INDIRECT)); BUG_ON(len == 0 || len % sizeof(struct vring_desc)); for (j = 0; j < len / sizeof(struct vring_desc); j++) - vring_unmap_one_split(vq, &indir_desc[j]); + vring_unmap_one_split_indirect(vq, &indir_desc[j]); kfree(indir_desc); vq->split.desc_state[head].indir_desc = NULL; @@ -739,7 +808,10 @@ static void virtqueue_disable_cb_split(struct virtqueue *_vq) if (!(vq->split.avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; - if (!vq->event) + if (vq->event) + /* TODO: this is a hack. Figure out a cleaner value to write. */ + vring_used_event(&vq->split.vring) = 0x0; + else vq->split.vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->split.avail_flags_shadow); @@ -912,7 +984,7 @@ static struct virtqueue *vring_create_virtqueue_split( */ static void vring_unmap_state_packed(const struct vring_virtqueue *vq, - struct vring_desc_extra_packed *state) + struct vring_desc_extra *state) { u16 flags; @@ -1061,7 +1133,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, 1 << VRING_PACKED_DESC_F_USED; } vq->packed.next_avail_idx = n; - vq->free_head = vq->packed.desc_state[id].next; + vq->free_head = vq->packed.desc_extra[id].next; /* Store token and indirect buffer state. */ vq->packed.desc_state[id].num = 1; @@ -1169,7 +1241,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq, le16_to_cpu(flags); } prev = curr; - curr = vq->packed.desc_state[curr].next; + curr = vq->packed.desc_extra[curr].next; if ((unlikely(++i >= vq->packed.vring.num))) { i = 0; @@ -1213,13 +1285,16 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq, unmap_release: err_idx = i; i = head; + curr = vq->free_head; vq->packed.avail_used_flags = avail_used_flags; for (n = 0; n < total_sg; n++) { if (i == err_idx) break; - vring_unmap_desc_packed(vq, &desc[i]); + vring_unmap_state_packed(vq, + &vq->packed.desc_extra[curr]); + curr = vq->packed.desc_extra[curr].next; i++; if (i >= vq->packed.vring.num) i = 0; @@ -1290,7 +1365,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq, /* Clear data ptr. */ state->data = NULL; - vq->packed.desc_state[state->last].next = vq->free_head; + vq->packed.desc_extra[state->last].next = vq->free_head; vq->free_head = id; vq->vq.num_free += state->num; @@ -1299,7 +1374,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq, for (i = 0; i < state->num; i++) { vring_unmap_state_packed(vq, &vq->packed.desc_extra[curr]); - curr = vq->packed.desc_state[curr].next; + curr = vq->packed.desc_extra[curr].next; } } @@ -1550,6 +1625,25 @@ static void *virtqueue_detach_unused_buf_packed(struct virtqueue *_vq) return NULL; } +static struct vring_desc_extra *vring_alloc_desc_extra(struct vring_virtqueue *vq, + unsigned int num) +{ + struct vring_desc_extra *desc_extra; + unsigned int i; + + desc_extra = kmalloc_array(num, sizeof(struct vring_desc_extra), + GFP_KERNEL); + if (!desc_extra) + return NULL; + + memset(desc_extra, 0, num * sizeof(struct vring_desc_extra)); + + for (i = 0; i < num - 1; i++) + desc_extra[i].next = i + 1; + + return desc_extra; +} + static struct virtqueue *vring_create_virtqueue_packed( unsigned int index, unsigned int num, @@ -1567,7 +1661,6 @@ static struct virtqueue *vring_create_virtqueue_packed( struct vring_packed_desc_event *driver, *device; dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr; size_t ring_size_in_bytes, event_size_in_bytes; - unsigned int i; ring_size_in_bytes = num * sizeof(struct vring_packed_desc); @@ -1605,6 +1698,7 @@ static struct virtqueue *vring_create_virtqueue_packed( vq->weak_barriers = weak_barriers; vq->broken = false; vq->last_used_idx = 0; + vq->event_triggered = false; vq->num_added = 0; vq->packed_ring = true; vq->use_dma_api = vring_use_dma_api(vdev); @@ -1649,18 +1743,11 @@ static struct virtqueue *vring_create_virtqueue_packed( /* Put everything in free lists. */ vq->free_head = 0; - for (i = 0; i < num-1; i++) - vq->packed.desc_state[i].next = i + 1; - vq->packed.desc_extra = kmalloc_array(num, - sizeof(struct vring_desc_extra_packed), - GFP_KERNEL); + vq->packed.desc_extra = vring_alloc_desc_extra(vq, num); if (!vq->packed.desc_extra) goto err_desc_extra; - memset(vq->packed.desc_extra, 0, - num * sizeof(struct vring_desc_extra_packed)); - /* No callback? Tell other side not to bother us. */ if (!callback) { vq->packed.event_flags_shadow = VRING_PACKED_EVENT_FLAG_DISABLE; @@ -1875,7 +1962,7 @@ bool virtqueue_kick(struct virtqueue *vq) EXPORT_SYMBOL_GPL(virtqueue_kick); /** - * virtqueue_get_buf - get the next used buffer + * virtqueue_get_buf_ctx - get the next used buffer * @_vq: the struct virtqueue we're talking about. * @len: the length written into the buffer * @ctx: extra context for the token @@ -1919,6 +2006,12 @@ void virtqueue_disable_cb(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); + /* If device triggered an event already it won't trigger one again: + * no need to disable. + */ + if (vq->event_triggered) + return; + if (vq->packed_ring) virtqueue_disable_cb_packed(_vq); else @@ -1942,6 +2035,9 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); + if (vq->event_triggered) + vq->event_triggered = false; + return vq->packed_ring ? virtqueue_enable_cb_prepare_packed(_vq) : virtqueue_enable_cb_prepare_split(_vq); } @@ -2005,6 +2101,9 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); + if (vq->event_triggered) + vq->event_triggered = false; + return vq->packed_ring ? virtqueue_enable_cb_delayed_packed(_vq) : virtqueue_enable_cb_delayed_split(_vq); } @@ -2044,6 +2143,10 @@ irqreturn_t vring_interrupt(int irq, void *_vq) if (unlikely(vq->broken)) return IRQ_HANDLED; + /* Just a hint for performance: so it's ok that this can be racy! */ + if (vq->event) + vq->event_triggered = true; + pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); if (vq->vq.callback) vq->vq.callback(&vq->vq); @@ -2062,7 +2165,6 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, void (*callback)(struct virtqueue *), const char *name) { - unsigned int i; struct vring_virtqueue *vq; if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) @@ -2083,6 +2185,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, vq->weak_barriers = weak_barriers; vq->broken = false; vq->last_used_idx = 0; + vq->event_triggered = false; vq->num_added = 0; vq->use_dma_api = vring_use_dma_api(vdev); #ifdef DEBUG @@ -2114,20 +2217,26 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, vq->split.desc_state = kmalloc_array(vring.num, sizeof(struct vring_desc_state_split), GFP_KERNEL); - if (!vq->split.desc_state) { - kfree(vq); - return NULL; - } + if (!vq->split.desc_state) + goto err_state; + + vq->split.desc_extra = vring_alloc_desc_extra(vq, vring.num); + if (!vq->split.desc_extra) + goto err_extra; /* Put everything in free lists. */ vq->free_head = 0; - for (i = 0; i < vring.num-1; i++) - vq->split.vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); memset(vq->split.desc_state, 0, vring.num * sizeof(struct vring_desc_state_split)); list_add_tail(&vq->vq.list, &vdev->vqs); return &vq->vq; + +err_extra: + kfree(vq->split.desc_state); +err_state: + kfree(vq); + return NULL; } EXPORT_SYMBOL_GPL(__vring_new_virtqueue); @@ -2208,8 +2317,10 @@ void vring_del_virtqueue(struct virtqueue *_vq) vq->split.queue_dma_addr); } } - if (!vq->packed_ring) + if (!vq->packed_ring) { kfree(vq->split.desc_state); + kfree(vq->split.desc_extra); + } list_del(&_vq->list); kfree(vq); } diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index e28acf482e0c..e1a141135992 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -142,6 +142,8 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, struct vdpa_callback cb; struct virtqueue *vq; u64 desc_addr, driver_addr, device_addr; + /* Assume split virtqueue, switch to packed if necessary */ + struct vdpa_vq_state state = {0}; unsigned long flags; u32 align, num; int err; @@ -191,6 +193,19 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, goto err_vq; } + /* reset virtqueue state index */ + if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) { + struct vdpa_vq_state_packed *s = &state.packed; + + s->last_avail_counter = 1; + s->last_avail_idx = 0; + s->last_used_counter = 1; + s->last_used_idx = 0; + } + err = ops->set_vq_state(vdpa, index, &state); + if (err) + goto err_vq; + ops->set_vq_ready(vdpa, index, 1); vq->priv = info; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 355100dad60a..546dfc1e2349 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -22,9 +22,9 @@ menuconfig WATCHDOG The watchdog is usually used together with the watchdog daemon which is available from - . This daemon can - also monitor NFS connections and can reboot the machine when the process - table is full. + . This daemon + can also monitor NFS connections and can reboot the machine when the + process table is full. If unsure, say N. @@ -73,6 +73,14 @@ config WATCHDOG_SYSFS Say Y here if you want to enable watchdog device status read through sysfs attributes. +config WATCHDOG_HRTIMER_PRETIMEOUT + bool "Enable watchdog hrtimer-based pretimeouts" + help + Enable this if you want to use a hrtimer timer based pretimeout for + watchdogs that do not natively support pretimeout support. Be aware + that because this pretimeout functionality uses hrtimers, it may not + be able to fire before the actual watchdog fires in some situations. + comment "Watchdog Pretimeout Governors" config WATCHDOG_PRETIMEOUT_GOV @@ -302,7 +310,7 @@ config XILINX_WATCHDOG depends on HAS_IOMEM select WATCHDOG_CORE help - Watchdog driver for the xps_timebase_wdt ip core. + Watchdog driver for the xps_timebase_wdt IP core. To compile this driver as a module, choose M here: the module will be called of_xilinx_wdt. @@ -404,8 +412,8 @@ config ASM9260_WATCHDOG select WATCHDOG_CORE select RESET_CONTROLLER help - Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your - system when the timeout is reached. + Watchdog timer embedded into Alphascale asm9260 chips. This will + reboot your system when the timeout is reached. config AT91RM9200_WATCHDOG tristate "AT91RM9200 watchdog" @@ -548,8 +556,9 @@ config OMAP_WATCHDOG depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || COMPILE_TEST select WATCHDOG_CORE help - Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' - here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. + Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. + Say 'Y' here to enable the + OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. config PNX4008_WATCHDOG tristate "LPC32XX Watchdog" @@ -980,6 +989,18 @@ config VISCONTI_WATCHDOG Say Y here to include support for the watchdog timer in Toshiba Visconti SoCs. +config MSC313E_WATCHDOG + tristate "MStar MSC313e watchdog" + depends on ARCH_MSTARV7 || COMPILE_TEST + select WATCHDOG_CORE + help + Say Y here to include support for the Watchdog timer embedded + into MStar MSC313e chips. This will reboot your system when the + timeout is reached. + + To compile this driver as a module, choose M here: the + module will be called msc313e_wdt. + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT @@ -1096,13 +1117,16 @@ config SBC_FITPC2_WATCHDOG This is the driver for the built-in watchdog timer on the fit-PC2, fit-PC2i, CM-iAM single-board computers made by Compulab. - It`s possible to enable watchdog timer either from BIOS (F2) or from booted Linux. - When "Watchdog Timer Value" enabled one can set 31-255 s operational range. + It's possible to enable the watchdog timer either from BIOS (F2) or + from booted Linux. + When the "Watchdog Timer Value" is enabled one can set 31-255 seconds + operational range. - Entering BIOS setup temporary disables watchdog operation regardless to current state, - so system will not be restarted while user in BIOS setup. + Entering BIOS setup temporarily disables watchdog operation regardless + of current state, so system will not be restarted while user is in + BIOS setup. - Once watchdog was enabled the system will be restarted every + Once the watchdog is enabled the system will be restarted every "Watchdog Timer Value" period, so to prevent it user can restart or disable the watchdog. @@ -1124,11 +1148,12 @@ config IB700_WDT depends on X86 help This is the driver for the hardware watchdog on the IB700 Single - Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. + Board Computer produced by TMC Technology (www.tmc-uk.com). This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of time. - This driver is like the WDT501 driver but for slightly different hardware. + This driver is like the WDT501 driver but for slightly different + hardware. To compile this driver as a module, choose M here: the module will be called ib700wdt. @@ -1807,10 +1832,10 @@ config PIC32_DMT select WATCHDOG_CORE depends on MACH_PIC32 || (MIPS && COMPILE_TEST) help - Watchdog driver for PIC32 instruction fetch counting timer. This specific - timer is typically be used in misson critical and safety critical - applications, where any single failure of the software functionality - and sequencing must be detected. + Watchdog driver for PIC32 instruction fetch counting timer. This + specific timer is typically be used in mission critical and safety + critical applications, where any single failure of the software + functionality and sequencing must be detected. To compile this driver as a loadable module, choose M here. The module will be called pic32-dmt. @@ -1844,10 +1869,6 @@ config 8xxx_WDT For BookE processors (MPC85xx) use the BOOKE_WDT driver instead. -config MV64X60_WDT - tristate "MV64X60 (Marvell Discovery) Watchdog Timer" - depends on MV64X60 || COMPILE_TEST - config PIKA_WDT tristate "PIKA FPGA Watchdog" depends on WARP || (PPC64 && COMPILE_TEST) @@ -2013,8 +2034,8 @@ config PCWATCHDOG This card simply watches your kernel to make sure it doesn't freeze, and if it does, it reboots your computer after a certain amount of time. This driver is like the WDT501 driver but for different - hardware. Please read . The PC - watchdog cards can be ordered from . + hardware. Please read . + The PC watchdog cards can be ordered from . To compile this driver as a module, choose M here: the module will be called pcwd. @@ -2115,7 +2136,7 @@ config KEEMBAY_WATCHDOG This option enable support for an In-secure watchdog timer driver for Intel Keem Bay SoC. This WDT has a 32 bit timer and decrements in every count unit. An interrupt will be triggered, when the count crosses - the thershold configured in the register. + the threshold configured in the register. To compile this driver as a module, choose M here: the module will be called keembay_wdt. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a7eade8b4d45..abaf2ebd814e 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o watchdog-objs += watchdog_core.o watchdog_dev.o watchdog-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV) += watchdog_pretimeout.o +watchdog-$(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT) += watchdog_hrtimer_pretimeout.o obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP) += pretimeout_noop.o obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC) += pretimeout_panic.o @@ -92,6 +93,7 @@ obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o +obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o @@ -175,7 +177,6 @@ obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o # POWERPC Architecture obj-$(CONFIG_GEF_WDT) += gef_wdt.o obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o -obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_PIKA_WDT) += pika_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 7e00960651fa..436571b6fc79 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -147,7 +147,7 @@ static int aspeed_wdt_set_timeout(struct watchdog_device *wdd, wdd->timeout = timeout; - actual = min(timeout, wdd->max_hw_heartbeat_ms * 1000); + actual = min(timeout, wdd->max_hw_heartbeat_ms / 1000); writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE); writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART); @@ -175,8 +175,8 @@ static ssize_t access_cs0_show(struct device *dev, struct aspeed_wdt *wdt = dev_get_drvdata(dev); u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS); - return sprintf(buf, "%u\n", - !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)); + return sysfs_emit(buf, "%u\n", + !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)); } static ssize_t access_cs0_store(struct device *dev, diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index 979caa18d3c8..acaaa0005d5b 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c @@ -34,6 +34,25 @@ struct bcm7038_watchdog { static bool nowayout = WATCHDOG_NOWAYOUT; +static inline void bcm7038_wdt_write(u32 value, void __iomem *addr) +{ + /* MIPS chips strapped for BE will automagically configure the + * peripheral registers for CPU-native byte order. + */ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + __raw_writel(value, addr); + else + writel_relaxed(value, addr); +} + +static inline u32 bcm7038_wdt_read(void __iomem *addr) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + return __raw_readl(addr); + else + return readl_relaxed(addr); +} + static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog) { struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); @@ -41,15 +60,15 @@ static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog) timeout = wdt->rate * wdog->timeout; - writel(timeout, wdt->base + WDT_TIMEOUT_REG); + bcm7038_wdt_write(timeout, wdt->base + WDT_TIMEOUT_REG); } static int bcm7038_wdt_ping(struct watchdog_device *wdog) { struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); - writel(WDT_START_1, wdt->base + WDT_CMD_REG); - writel(WDT_START_2, wdt->base + WDT_CMD_REG); + bcm7038_wdt_write(WDT_START_1, wdt->base + WDT_CMD_REG); + bcm7038_wdt_write(WDT_START_2, wdt->base + WDT_CMD_REG); return 0; } @@ -66,8 +85,8 @@ static int bcm7038_wdt_stop(struct watchdog_device *wdog) { struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); - writel(WDT_STOP_1, wdt->base + WDT_CMD_REG); - writel(WDT_STOP_2, wdt->base + WDT_CMD_REG); + bcm7038_wdt_write(WDT_STOP_1, wdt->base + WDT_CMD_REG); + bcm7038_wdt_write(WDT_STOP_2, wdt->base + WDT_CMD_REG); return 0; } @@ -88,7 +107,7 @@ static unsigned int bcm7038_wdt_get_timeleft(struct watchdog_device *wdog) struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); u32 time_left; - time_left = readl(wdt->base + WDT_CMD_REG); + time_left = bcm7038_wdt_read(wdt->base + WDT_CMD_REG); return time_left / wdt->rate; } diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 7817fb976f9c..5e4dc1a0f2c6 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -148,7 +148,7 @@ static void __booke_wdt_enable(void *data) } /** - * booke_wdt_disable - disable the watchdog on the given CPU + * __booke_wdt_disable - disable the watchdog on the given CPU * * This function is called on each CPU. It disables the watchdog on that CPU. * diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index aafc8d98bf9f..4cb10877017c 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c @@ -118,8 +118,6 @@ static int wdt_start(struct watchdog_device *dev) if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status)) return -EBUSY; - ret = -ENODEV; - if (MACHINE_IS_VM) { ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); if (!ebc_cmd) { @@ -167,8 +165,6 @@ static int wdt_ping(struct watchdog_device *dev) int ret; unsigned int func; - ret = -ENODEV; - if (MACHINE_IS_VM) { ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); if (!ebc_cmd) diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 32d0e1781e63..cd578843277e 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -13,22 +13,21 @@ */ #include -#include -#include #include +#include #include #include +#include #include #include +#include #include #include -#include #include -#include #include +#include #include #include -#include #define WDOG_CONTROL_REG_OFFSET 0x00 #define WDOG_CONTROL_REG_WDT_EN_MASK 0x01 diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c index 2418ebb707bd..ce682942662c 100644 --- a/drivers/watchdog/eurotechwdt.c +++ b/drivers/watchdog/eurotechwdt.c @@ -392,7 +392,7 @@ static struct notifier_block eurwdt_notifier = { }; /** - * cleanup_module: + * eurwdt_exit: * * Unload the watchdog. You cannot do this with any file handles open. * If your watchdog is set to continue ticking on close and you unload diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 22ddba3802ef..a5006a58e0db 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -45,6 +45,7 @@ static unsigned long __iomem *hpwdt_timer_con; static const struct pci_device_id hpwdt_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ + { PCI_DEVICE(PCI_VENDOR_ID_HP_3PAR, 0x0389) }, /* PCtrl */ {0}, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index bf31d7b67a69..b3f604669e2c 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -71,6 +71,8 @@ #define TCOBASE(p) ((p)->tco_res->start) /* SMI Control and Enable Register */ #define SMI_EN(p) ((p)->smi_res->start) +#define TCO_EN (1 << 13) +#define GBL_SMI_EN (1 << 0) #define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */ #define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/ @@ -355,8 +357,12 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) tmrval = seconds_to_ticks(p, t); - /* For TCO v1 the timer counts down twice before rebooting */ - if (p->iTCO_version == 1) + /* + * If TCO SMIs are off, the timer counts down twice before rebooting. + * Otherwise, the BIOS generally reboots when the SMI triggers. + */ + if (p->smi_res && + (SMI_EN(p) & (TCO_EN | GBL_SMI_EN)) != (TCO_EN | GBL_SMI_EN)) tmrval /= 2; /* from the specs: */ @@ -479,13 +485,13 @@ static int iTCO_wdt_probe(struct platform_device *pdev) if (!devm_request_region(dev, p->smi_res->start, resource_size(p->smi_res), pdev->name)) { - pr_err("I/O address 0x%04llx already in use, device disabled\n", + dev_err(dev, "I/O address 0x%04llx already in use, device disabled\n", (u64)SMI_EN(p)); return -EBUSY; } } else if (iTCO_vendorsupport || turn_SMI_watchdog_clear_off >= p->iTCO_version) { - pr_err("SMI I/O resource is missing\n"); + dev_err(dev, "SMI I/O resource is missing\n"); return -ENODEV; } @@ -521,7 +527,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev) * Disables TCO logic generating an SMI# */ val32 = inl(SMI_EN(p)); - val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ + val32 &= ~TCO_EN; /* Turn off SMI clearing watchdog */ outl(val32, SMI_EN(p)); } diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index b84f80f7d342..cc86018c5eb5 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -65,6 +65,7 @@ struct imx2_wdt_device { struct regmap *regmap; struct watchdog_device wdog; bool ext_reset; + bool clk_is_on; }; static bool nowayout = WATCHDOG_NOWAYOUT; @@ -160,6 +161,9 @@ static int imx2_wdt_ping(struct watchdog_device *wdog) { struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); + if (!wdev->clk_is_on) + return 0; + regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1); regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2); return 0; @@ -301,6 +305,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) if (ret) return ret; + wdev->clk_is_on = true; + regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val); wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0; @@ -361,6 +367,8 @@ static int __maybe_unused imx2_wdt_suspend(struct device *dev) clk_disable_unprepare(wdev->clk); + wdev->clk_is_on = false; + return 0; } @@ -375,6 +383,8 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev) if (ret) return ret; + wdev->clk_is_on = true; + if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) { /* * If the watchdog is still active and resumes diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c index e9ee22a7cb45..8ac021748d16 100644 --- a/drivers/watchdog/imx_sc_wdt.c +++ b/drivers/watchdog/imx_sc_wdt.c @@ -183,16 +183,12 @@ static int imx_sc_wdt_probe(struct platform_device *pdev) watchdog_stop_on_reboot(wdog); watchdog_stop_on_unregister(wdog); - ret = devm_watchdog_register_device(dev, wdog); - if (ret) - return ret; - ret = imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG, SC_IRQ_WDOG, true); if (ret) { dev_warn(dev, "Enable irq failed, pretimeout NOT supported\n"); - return 0; + goto register_device; } imx_sc_wdd->wdt_notifier.notifier_call = imx_sc_wdt_notify; @@ -203,7 +199,7 @@ static int imx_sc_wdt_probe(struct platform_device *pdev) false); dev_warn(dev, "Register irq notifier failed, pretimeout NOT supported\n"); - return 0; + goto register_device; } ret = devm_add_action_or_reset(dev, imx_sc_wdt_action, @@ -213,7 +209,8 @@ static int imx_sc_wdt_probe(struct platform_device *pdev) else dev_warn(dev, "Add action failed, pretimeout NOT supported\n"); - return 0; +register_device: + return devm_watchdog_register_device(dev, wdog); } static int __maybe_unused imx_sc_wdt_suspend(struct device *dev) diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index 2b4831842162..bb1122909396 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -152,14 +152,6 @@ static inline int superio_inw(int reg) return val; } -static inline void superio_outw(int val, int reg) -{ - outb(reg++, REG); - outb(val >> 8, VAL); - outb(reg, REG); - outb(val, VAL); -} - /* Internal function, should be called after superio_select(GPIO) */ static void _wdt_update_timeout(unsigned int t) { diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index bdf9564efa29..395bde79e292 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -176,9 +176,9 @@ static int jz4740_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(jz4740_wdt, drvdata); drvdata->map = device_node_to_regmap(dev->parent->of_node); - if (!drvdata->map) { + if (IS_ERR(drvdata->map)) { dev_err(dev, "regmap not found\n"); - return -EINVAL; + return PTR_ERR(drvdata->map); } return devm_watchdog_register_device(dev, &drvdata->wdt); diff --git a/drivers/watchdog/keembay_wdt.c b/drivers/watchdog/keembay_wdt.c index 547d3fea33ff..2a39114dbc64 100644 --- a/drivers/watchdog/keembay_wdt.c +++ b/drivers/watchdog/keembay_wdt.c @@ -23,12 +23,19 @@ #define TIM_WDOG_EN 0x8 #define TIM_SAFE 0xc -#define WDT_ISR_MASK GENMASK(9, 8) -#define WDT_ISR_CLEAR 0x8200ff18 +#define WDT_TH_INT_MASK BIT(8) +#define WDT_TO_INT_MASK BIT(9) +#define WDT_INT_CLEAR_SMC 0x8200ff18 + #define WDT_UNLOCK 0xf1d0dead +#define WDT_DISABLE 0x0 +#define WDT_ENABLE 0x1 + #define WDT_LOAD_MAX U32_MAX #define WDT_LOAD_MIN 1 + #define WDT_TIMEOUT 5 +#define WDT_PRETIMEOUT 4 static unsigned int timeout = WDT_TIMEOUT; module_param(timeout, int, 0); @@ -82,8 +89,7 @@ static int keembay_wdt_start(struct watchdog_device *wdog) { struct keembay_wdt *wdt = watchdog_get_drvdata(wdog); - keembay_wdt_set_timeout_reg(wdog); - keembay_wdt_writel(wdt, TIM_WDOG_EN, 1); + keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_ENABLE); return 0; } @@ -92,7 +98,7 @@ static int keembay_wdt_stop(struct watchdog_device *wdog) { struct keembay_wdt *wdt = watchdog_get_drvdata(wdog); - keembay_wdt_writel(wdt, TIM_WDOG_EN, 0); + keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_DISABLE); return 0; } @@ -108,6 +114,7 @@ static int keembay_wdt_set_timeout(struct watchdog_device *wdog, u32 t) { wdog->timeout = t; keembay_wdt_set_timeout_reg(wdog); + keembay_wdt_set_pretimeout_reg(wdog); return 0; } @@ -139,9 +146,8 @@ static irqreturn_t keembay_wdt_to_isr(int irq, void *dev_id) struct keembay_wdt *wdt = dev_id; struct arm_smccc_res res; - keembay_wdt_writel(wdt, TIM_WATCHDOG, 1); - arm_smccc_smc(WDT_ISR_CLEAR, WDT_ISR_MASK, 0, 0, 0, 0, 0, 0, &res); - dev_crit(wdt->wdd.parent, "Intel Keem Bay non-sec wdt timeout.\n"); + arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TO_INT_MASK, 0, 0, 0, 0, 0, 0, &res); + dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt timeout.\n"); emergency_restart(); return IRQ_HANDLED; @@ -152,8 +158,10 @@ static irqreturn_t keembay_wdt_th_isr(int irq, void *dev_id) struct keembay_wdt *wdt = dev_id; struct arm_smccc_res res; - arm_smccc_smc(WDT_ISR_CLEAR, WDT_ISR_MASK, 0, 0, 0, 0, 0, 0, &res); - dev_crit(wdt->wdd.parent, "Intel Keem Bay non-sec wdt pre-timeout.\n"); + keembay_wdt_set_pretimeout(&wdt->wdd, 0x0); + + arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TH_INT_MASK, 0, 0, 0, 0, 0, 0, &res); + dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt pre-timeout.\n"); watchdog_notify_pretimeout(&wdt->wdd); return IRQ_HANDLED; @@ -224,11 +232,13 @@ static int keembay_wdt_probe(struct platform_device *pdev) wdt->wdd.min_timeout = WDT_LOAD_MIN; wdt->wdd.max_timeout = WDT_LOAD_MAX / wdt->rate; wdt->wdd.timeout = WDT_TIMEOUT; + wdt->wdd.pretimeout = WDT_PRETIMEOUT; watchdog_set_drvdata(&wdt->wdd, wdt); watchdog_set_nowayout(&wdt->wdd, nowayout); watchdog_init_timeout(&wdt->wdd, timeout, dev); keembay_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); + keembay_wdt_set_pretimeout(&wdt->wdd, wdt->wdd.pretimeout); ret = devm_watchdog_register_device(dev, &wdt->wdd); if (ret) @@ -271,8 +281,8 @@ static const struct of_device_id keembay_wdt_match[] = { MODULE_DEVICE_TABLE(of, keembay_wdt_match); static struct platform_driver keembay_wdt_driver = { - .probe = keembay_wdt_probe, - .driver = { + .probe = keembay_wdt_probe, + .driver = { .name = "keembay_wdt", .of_match_table = keembay_wdt_match, .pm = &keembay_wdt_pm_ops, diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index 78cf11c94941..60b6d74f267d 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -292,7 +292,7 @@ static int lpc18xx_wdt_remove(struct platform_device *pdev) struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n"); - del_timer(&lpc18xx_wdt->timer); + del_timer_sync(&lpc18xx_wdt->timer); return 0; } diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index c8ac36135e28..c7a7235e6224 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -105,7 +105,7 @@ struct mei_wdt { #endif /* CONFIG_DEBUG_FS */ }; -/* +/** * struct mei_mc_hdr - Management Control Command Header * * @command: Management Control (0x2) @@ -474,7 +474,7 @@ out: complete(&wdt->response); } -/* +/** * mei_wdt_notif - callback for event notification * * @cldev: bus device diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 459f3ae02c91..539feaa1f904 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c @@ -162,7 +162,6 @@ static int meson_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct meson_wdt_dev *meson_wdt; - const struct of_device_id *of_id; int err; meson_wdt = devm_kzalloc(dev, sizeof(*meson_wdt), GFP_KERNEL); @@ -173,12 +172,7 @@ static int meson_wdt_probe(struct platform_device *pdev) if (IS_ERR(meson_wdt->wdt_base)) return PTR_ERR(meson_wdt->wdt_base); - of_id = of_match_device(meson_wdt_dt_ids, dev); - if (!of_id) { - dev_err(dev, "Unable to initialize WDT data\n"); - return -ENODEV; - } - meson_wdt->data = of_id->data; + meson_wdt->data = device_get_match_data(dev); meson_wdt->wdt_dev.parent = dev; meson_wdt->wdt_dev.info = &meson_wdt_info; diff --git a/drivers/watchdog/msc313e_wdt.c b/drivers/watchdog/msc313e_wdt.c new file mode 100644 index 000000000000..0d497aa0fb7d --- /dev/null +++ b/drivers/watchdog/msc313e_wdt.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MStar WDT driver + * + * Copyright (C) 2019 - 2021 Daniel Palmer + * Copyright (C) 2021 Romain Perier + * + */ + +#include +#include +#include +#include +#include +#include + +#define REG_WDT_CLR 0x0 +#define REG_WDT_MAX_PRD_L 0x10 +#define REG_WDT_MAX_PRD_H 0x14 + +#define MSC313E_WDT_MIN_TIMEOUT 1 +#define MSC313E_WDT_DEFAULT_TIMEOUT 30 + +static unsigned int timeout; + +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); + +struct msc313e_wdt_priv { + void __iomem *base; + struct watchdog_device wdev; + struct clk *clk; +}; + +static int msc313e_wdt_start(struct watchdog_device *wdev) +{ + struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev); + u32 timeout; + int err; + + err = clk_prepare_enable(priv->clk); + if (err) + return err; + + timeout = wdev->timeout * clk_get_rate(priv->clk); + writew(timeout & 0xffff, priv->base + REG_WDT_MAX_PRD_L); + writew((timeout >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H); + writew(1, priv->base + REG_WDT_CLR); + return 0; +} + +static int msc313e_wdt_ping(struct watchdog_device *wdev) +{ + struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev); + + writew(1, priv->base + REG_WDT_CLR); + return 0; +} + +static int msc313e_wdt_stop(struct watchdog_device *wdev) +{ + struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev); + + writew(0, priv->base + REG_WDT_MAX_PRD_L); + writew(0, priv->base + REG_WDT_MAX_PRD_H); + writew(0, priv->base + REG_WDT_CLR); + clk_disable_unprepare(priv->clk); + return 0; +} + +static int msc313e_wdt_settimeout(struct watchdog_device *wdev, unsigned int new_time) +{ + wdev->timeout = new_time; + + return msc313e_wdt_start(wdev); +} + +static const struct watchdog_info msc313e_wdt_ident = { + .identity = "MSC313e watchdog", + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, +}; + +static const struct watchdog_ops msc313e_wdt_ops = { + .owner = THIS_MODULE, + .start = msc313e_wdt_start, + .stop = msc313e_wdt_stop, + .ping = msc313e_wdt_ping, + .set_timeout = msc313e_wdt_settimeout, +}; + +static const struct of_device_id msc313e_wdt_of_match[] = { + { .compatible = "mstar,msc313e-wdt", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, msc313e_wdt_of_match); + +static int msc313e_wdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct msc313e_wdt_priv *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "No input clock\n"); + return PTR_ERR(priv->clk); + } + + priv->wdev.info = &msc313e_wdt_ident, + priv->wdev.ops = &msc313e_wdt_ops, + priv->wdev.parent = dev; + priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT; + priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk); + priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT; + + watchdog_set_drvdata(&priv->wdev, priv); + + watchdog_init_timeout(&priv->wdev, timeout, dev); + watchdog_stop_on_reboot(&priv->wdev); + watchdog_stop_on_unregister(&priv->wdev); + + return devm_watchdog_register_device(dev, &priv->wdev); +} + +static int __maybe_unused msc313e_wdt_suspend(struct device *dev) +{ + struct msc313e_wdt_priv *priv = dev_get_drvdata(dev); + + if (watchdog_active(&priv->wdev)) + msc313e_wdt_stop(&priv->wdev); + + return 0; +} + +static int __maybe_unused msc313e_wdt_resume(struct device *dev) +{ + struct msc313e_wdt_priv *priv = dev_get_drvdata(dev); + + if (watchdog_active(&priv->wdev)) + msc313e_wdt_start(&priv->wdev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume); + +static struct platform_driver msc313e_wdt_driver = { + .driver = { + .name = "msc313e-wdt", + .of_match_table = msc313e_wdt_of_match, + .pm = &msc313e_wdt_pm_ops, + }, + .probe = msc313e_wdt_probe, +}; +module_platform_driver(msc313e_wdt_driver); + +MODULE_AUTHOR("Daniel Palmer "); +MODULE_DESCRIPTION("Watchdog driver for MStar MSC313e"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 97ca993bd009..16b6aff324a7 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -25,9 +25,10 @@ #include #include #include +#include #define WDT_MAX_TIMEOUT 31 -#define WDT_MIN_TIMEOUT 1 +#define WDT_MIN_TIMEOUT 2 #define WDT_LENGTH_TIMEOUT(n) ((n) << 5) #define WDT_LENGTH 0x04 @@ -187,12 +188,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev, u32 reg; wdt_dev->timeout = timeout; + /* + * In dual mode, irq will be triggered at timeout / 2 + * the real timeout occurs at timeout + */ + if (wdt_dev->pretimeout) + wdt_dev->pretimeout = timeout / 2; /* * One bit is the value of 512 ticks * The clock has 32 KHz */ - reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY; + reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6) + | WDT_LENGTH_KEY; iowrite32(reg, wdt_base + WDT_LENGTH); mtk_wdt_ping(wdt_dev); @@ -239,13 +247,48 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev) return ret; reg = ioread32(wdt_base + WDT_MODE); - reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); + if (wdt_dev->pretimeout) + reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); + else + reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); reg |= (WDT_MODE_EN | WDT_MODE_KEY); iowrite32(reg, wdt_base + WDT_MODE); return 0; } +static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd); + void __iomem *wdt_base = mtk_wdt->wdt_base; + u32 reg = ioread32(wdt_base + WDT_MODE); + + if (timeout && !wdd->pretimeout) { + wdd->pretimeout = wdd->timeout / 2; + reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); + } else if (!timeout && wdd->pretimeout) { + wdd->pretimeout = 0; + reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); + } else { + return 0; + } + + reg |= WDT_MODE_KEY; + iowrite32(reg, wdt_base + WDT_MODE); + + return mtk_wdt_set_timeout(wdd, wdd->timeout); +} + +static irqreturn_t mtk_wdt_isr(int irq, void *arg) +{ + struct watchdog_device *wdd = arg; + + watchdog_notify_pretimeout(wdd); + + return IRQ_HANDLED; +} + static const struct watchdog_info mtk_wdt_info = { .identity = DRV_NAME, .options = WDIOF_SETTIMEOUT | @@ -253,12 +296,21 @@ static const struct watchdog_info mtk_wdt_info = { WDIOF_MAGICCLOSE, }; +static const struct watchdog_info mtk_wdt_pt_info = { + .identity = DRV_NAME, + .options = WDIOF_SETTIMEOUT | + WDIOF_PRETIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + static const struct watchdog_ops mtk_wdt_ops = { .owner = THIS_MODULE, .start = mtk_wdt_start, .stop = mtk_wdt_stop, .ping = mtk_wdt_ping, .set_timeout = mtk_wdt_set_timeout, + .set_pretimeout = mtk_wdt_set_pretimeout, .restart = mtk_wdt_restart, }; @@ -267,7 +319,7 @@ static int mtk_wdt_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mtk_wdt_dev *mtk_wdt; const struct mtk_wdt_data *wdt_data; - int err; + int err, irq; mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL); if (!mtk_wdt) @@ -279,7 +331,22 @@ static int mtk_wdt_probe(struct platform_device *pdev) if (IS_ERR(mtk_wdt->wdt_base)) return PTR_ERR(mtk_wdt->wdt_base); - mtk_wdt->wdt_dev.info = &mtk_wdt_info; + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark", + &mtk_wdt->wdt_dev); + if (err) + return err; + + mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info; + mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2; + } else { + if (irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + + mtk_wdt->wdt_dev.info = &mtk_wdt_info; + } + mtk_wdt->wdt_dev.ops = &mtk_wdt_ops; mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT; mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000; diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 8aa1cb4a295f..ea1bbf5ee528 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -41,8 +41,6 @@ #include #include -#include - #define MTX1_WDT_INTERVAL (5 * HZ) static int ticks = 100 * HZ; diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c deleted file mode 100644 index 894aa63488d3..000000000000 --- a/drivers/watchdog/mv64x60_wdt.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface - * - * Author: James Chapman - * - * Platform-specific setup code should configure the dog to generate - * interrupt or reset as required. This code only enables/disables - * and services the watchdog. - * - * Derived from mpc8xx_wdt.c, with the following copyright. - * - * 2002 (c) Florian Schirmer - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MV64x60_WDT_WDC_OFFSET 0 - -/* - * The watchdog configuration register contains a pair of 2-bit fields, - * 1. a reload field, bits 27-26, which triggers a reload of - * the countdown register, and - * 2. an enable field, bits 25-24, which toggles between - * enabling and disabling the watchdog timer. - * Bit 31 is a read-only field which indicates whether the - * watchdog timer is currently enabled. - * - * The low 24 bits contain the timer reload value. - */ -#define MV64x60_WDC_ENABLE_SHIFT 24 -#define MV64x60_WDC_SERVICE_SHIFT 26 -#define MV64x60_WDC_ENABLED_SHIFT 31 - -#define MV64x60_WDC_ENABLED_TRUE 1 -#define MV64x60_WDC_ENABLED_FALSE 0 - -/* Flags bits */ -#define MV64x60_WDOG_FLAG_OPENED 0 - -static unsigned long wdt_flags; -static int wdt_status; -static void __iomem *mv64x60_wdt_regs; -static int mv64x60_wdt_timeout; -static int mv64x60_wdt_count; -static unsigned int bus_clk; -static char expect_close; -static DEFINE_SPINLOCK(mv64x60_wdt_spinlock); - -static bool nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, bool, 0); -MODULE_PARM_DESC(nowayout, - "Watchdog cannot be stopped once started (default=" - __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); - -static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) -{ - u32 data; - u32 enabled; - int ret = 0; - - spin_lock(&mv64x60_wdt_spinlock); - data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); - enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1; - - /* only toggle the requested field if enabled state matches predicate */ - if ((enabled ^ enabled_predicate) == 0) { - /* We write a 1, then a 2 -- to the appropriate field */ - data = (1 << field_shift) | mv64x60_wdt_count; - writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); - - data = (2 << field_shift) | mv64x60_wdt_count; - writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET); - ret = 1; - } - spin_unlock(&mv64x60_wdt_spinlock); - - return ret; -} - -static void mv64x60_wdt_service(void) -{ - mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE, - MV64x60_WDC_SERVICE_SHIFT); -} - -static void mv64x60_wdt_handler_enable(void) -{ - if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE, - MV64x60_WDC_ENABLE_SHIFT)) { - mv64x60_wdt_service(); - pr_notice("watchdog activated\n"); - } -} - -static void mv64x60_wdt_handler_disable(void) -{ - if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE, - MV64x60_WDC_ENABLE_SHIFT)) - pr_notice("watchdog deactivated\n"); -} - -static void mv64x60_wdt_set_timeout(unsigned int timeout) -{ - /* maximum bus cycle count is 0xFFFFFFFF */ - if (timeout > 0xFFFFFFFF / bus_clk) - timeout = 0xFFFFFFFF / bus_clk; - - mv64x60_wdt_count = timeout * bus_clk >> 8; - mv64x60_wdt_timeout = timeout; -} - -static int mv64x60_wdt_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) - return -EBUSY; - - if (nowayout) - __module_get(THIS_MODULE); - - mv64x60_wdt_handler_enable(); - - return stream_open(inode, file); -} - -static int mv64x60_wdt_release(struct inode *inode, struct file *file) -{ - if (expect_close == 42) - mv64x60_wdt_handler_disable(); - else { - pr_crit("unexpected close, not stopping timer!\n"); - mv64x60_wdt_service(); - } - expect_close = 0; - - clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); - - return 0; -} - -static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - if (len) { - if (!nowayout) { - size_t i; - - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - expect_close = 42; - } - } - mv64x60_wdt_service(); - } - - return len; -} - -static long mv64x60_wdt_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int timeout; - int options; - void __user *argp = (void __user *)arg; - static const struct watchdog_info info = { - .options = WDIOF_SETTIMEOUT | - WDIOF_MAGICCLOSE | - WDIOF_KEEPALIVEPING, - .firmware_version = 0, - .identity = "MV64x60 watchdog", - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(wdt_status, (int __user *)argp)) - return -EFAULT; - wdt_status &= ~WDIOF_KEEPALIVEPING; - break; - - case WDIOC_GETTEMP: - return -EOPNOTSUPP; - - case WDIOC_SETOPTIONS: - if (get_user(options, (int __user *)argp)) - return -EFAULT; - - if (options & WDIOS_DISABLECARD) - mv64x60_wdt_handler_disable(); - - if (options & WDIOS_ENABLECARD) - mv64x60_wdt_handler_enable(); - break; - - case WDIOC_KEEPALIVE: - mv64x60_wdt_service(); - wdt_status |= WDIOF_KEEPALIVEPING; - break; - - case WDIOC_SETTIMEOUT: - if (get_user(timeout, (int __user *)argp)) - return -EFAULT; - mv64x60_wdt_set_timeout(timeout); - fallthrough; - - case WDIOC_GETTIMEOUT: - if (put_user(mv64x60_wdt_timeout, (int __user *)argp)) - return -EFAULT; - break; - - default: - return -ENOTTY; - } - - return 0; -} - -static const struct file_operations mv64x60_wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = mv64x60_wdt_write, - .unlocked_ioctl = mv64x60_wdt_ioctl, - .compat_ioctl = compat_ptr_ioctl, - .open = mv64x60_wdt_open, - .release = mv64x60_wdt_release, -}; - -static struct miscdevice mv64x60_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &mv64x60_wdt_fops, -}; - -static int mv64x60_wdt_probe(struct platform_device *dev) -{ - struct mv64x60_wdt_pdata *pdata = dev_get_platdata(&dev->dev); - struct resource *r; - int timeout = 10; - - bus_clk = 133; /* in MHz */ - if (pdata) { - timeout = pdata->timeout; - bus_clk = pdata->bus_clk; - } - - /* Since bus_clk is truncated MHz, actual frequency could be - * up to 1MHz higher. Round up, since it's better to time out - * too late than too soon. - */ - bus_clk++; - bus_clk *= 1000000; /* convert to Hz */ - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) - return -ENODEV; - - mv64x60_wdt_regs = devm_ioremap(&dev->dev, r->start, resource_size(r)); - if (mv64x60_wdt_regs == NULL) - return -ENOMEM; - - mv64x60_wdt_set_timeout(timeout); - - mv64x60_wdt_handler_disable(); /* in case timer was already running */ - - return misc_register(&mv64x60_wdt_miscdev); -} - -static int mv64x60_wdt_remove(struct platform_device *dev) -{ - misc_deregister(&mv64x60_wdt_miscdev); - - mv64x60_wdt_handler_disable(); - - return 0; -} - -static struct platform_driver mv64x60_wdt_driver = { - .probe = mv64x60_wdt_probe, - .remove = mv64x60_wdt_remove, - .driver = { - .name = MV64x60_WDT_NAME, - }, -}; - -static int __init mv64x60_wdt_init(void) -{ - pr_info("MV64x60 watchdog driver\n"); - - return platform_driver_register(&mv64x60_wdt_driver); -} - -static void __exit mv64x60_wdt_exit(void) -{ - platform_driver_unregister(&mv64x60_wdt_driver); -} - -module_init(mv64x60_wdt_init); -module_exit(mv64x60_wdt_exit); - -MODULE_AUTHOR("James Chapman "); -MODULE_DESCRIPTION("MV64x60 watchdog driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" MV64x60_WDT_NAME); diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 391c774a1f67..0fe71f7e66d5 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -120,7 +120,7 @@ static int cpu2core(int cpu) } /** - * Poke the watchdog when an interrupt is received + * octeon_wdt_poke_irq - Poke the watchdog when an interrupt is received * * @cpl: * @dev_id: @@ -154,7 +154,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id) extern int prom_putchar(char c); /** - * Write a string to the uart + * octeon_wdt_write_string - Write a string to the uart * * @str: String to write */ @@ -166,7 +166,7 @@ static void octeon_wdt_write_string(const char *str) } /** - * Write a hex number out of the uart + * octeon_wdt_write_hex() - Write a hex number out of the uart * * @value: Number to display * @digits: Number of digits to print (1 to 16) @@ -193,6 +193,8 @@ static const char reg_name[][3] = { }; /** + * octeon_wdt_nmi_stage3: + * * NMI stage 3 handler. NMIs are handled in the following manner: * 1) The first NMI handler enables CVMSEG and transfers from * the bootbus region into normal memory. It is careful to not @@ -514,7 +516,7 @@ static struct watchdog_device octeon_wdt = { static enum cpuhp_state octeon_wdt_online; /** - * Module/ driver initialization. + * octeon_wdt_init - Module/ driver initialization. * * Returns Zero on success */ @@ -586,7 +588,7 @@ err: } /** - * Module / driver shutdown + * octeon_wdt_cleanup - Module / driver shutdown */ static void __exit octeon_wdt_cleanup(void) { diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 7fe4f7c3f7ce..3318544366b8 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -6,6 +6,7 @@ * (C) Copyright 2011 (Alejandro Cabrera ) */ +#include #include #include #include @@ -24,12 +25,12 @@ #define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */ /* Control/Status Register Masks */ -#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */ -#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */ -#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */ +#define XWT_CSR0_WRS_MASK BIT(3) /* Reset status */ +#define XWT_CSR0_WDS_MASK BIT(2) /* Timer state */ +#define XWT_CSR0_EWDT1_MASK BIT(1) /* Enable bit 1 */ /* Control/Status Register 0/1 bits */ -#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */ +#define XWT_CSRX_EWDT2_MASK BIT(0) /* Enable bit 2 */ /* SelfTest constants */ #define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000 @@ -40,7 +41,7 @@ struct xwdt_device { void __iomem *base; u32 wdt_interval; - spinlock_t spinlock; + spinlock_t spinlock; /* spinlock for register handling */ struct watchdog_device xilinx_wdt_wdd; struct clk *clk; }; @@ -70,6 +71,8 @@ static int xilinx_wdt_start(struct watchdog_device *wdd) spin_unlock(&xdev->spinlock); + dev_dbg(wdd->parent, "Watchdog Started!\n"); + return 0; } @@ -91,7 +94,7 @@ static int xilinx_wdt_stop(struct watchdog_device *wdd) clk_disable(xdev->clk); - pr_info("Stopped!\n"); + dev_dbg(wdd->parent, "Watchdog Stopped!\n"); return 0; } @@ -208,6 +211,15 @@ static int xwdt_probe(struct platform_device *pdev) "The watchdog clock freq cannot be obtained\n"); } else { pfreq = clk_get_rate(xdev->clk); + rc = clk_prepare_enable(xdev->clk); + if (rc) { + dev_err(dev, "unable to enable clock\n"); + return rc; + } + rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare, + xdev->clk); + if (rc) + return rc; } /* @@ -221,16 +233,6 @@ static int xwdt_probe(struct platform_device *pdev) spin_lock_init(&xdev->spinlock); watchdog_set_drvdata(xilinx_wdt_wdd, xdev); - rc = clk_prepare_enable(xdev->clk); - if (rc) { - dev_err(dev, "unable to enable clock\n"); - return rc; - } - rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare, - xdev->clk); - if (rc) - return rc; - rc = xwdt_selftest(xdev); if (rc == XWT_TIMER_FAILED) { dev_err(dev, "SelfTest routine error\n"); @@ -243,8 +245,8 @@ static int xwdt_probe(struct platform_device *pdev) clk_disable(xdev->clk); - dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", - xdev->base, xilinx_wdt_wdd->timeout); + dev_info(dev, "Xilinx Watchdog Timer with timeout %ds\n", + xilinx_wdt_wdd->timeout); platform_set_drvdata(pdev, xdev); diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 4ddb4ea2e4a3..127eefc9161d 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -174,7 +174,7 @@ static int armadaxp_wdt_clock_init(struct platform_device *pdev, return ret; } - /* Fix the wdt and timer1 clock freqency to 25MHz */ + /* Fix the wdt and timer1 clock frequency to 25MHz */ val = WDT_AXP_FIXED_ENABLE_BIT | TIMER1_FIXED_ENABLE_BIT; atomic_io_modify(dev->reg + TIMER_CTRL, val, val); diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c index 2d4504302c9e..9f9a340427fc 100644 --- a/drivers/watchdog/pc87413_wdt.c +++ b/drivers/watchdog/pc87413_wdt.c @@ -445,7 +445,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd, /* -- Notifier funtions -----------------------------------------*/ /** - * notify_sys: + * pc87413_notify_sys: * @this: our notifier block * @code: the event being reported * @unused: unused diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index e38a87ffe5f5..0d2209c5eaca 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -329,7 +329,9 @@ static int __maybe_unused qcom_wdt_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume); +static const struct dev_pm_ops qcom_wdt_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(qcom_wdt_suspend, qcom_wdt_resume) +}; static const struct of_device_id qcom_wdt_of_table[] = { { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr }, diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index e5d11d6a2600..ec20ad4e534f 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -268,8 +268,10 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) wdd->min_timeout = MIN_WDT_TIMEOUT; wdd->max_timeout = MAX_WDT_TIMEOUT; wdt->last_ping = jiffies; - wdt->sam9x60_support = of_device_is_compatible(dev->of_node, - "microchip,sam9x60-wdt"); + + if (of_device_is_compatible(dev->of_node, "microchip,sam9x60-wdt") || + of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt")) + wdt->sam9x60_support = true; watchdog_set_drvdata(wdd, wdt); @@ -329,6 +331,10 @@ static const struct of_device_id sama5d4_wdt_of_match[] = { { .compatible = "microchip,sam9x60-wdt", }, + { + .compatible = "microchip,sama7g5-wdt", + }, + { } }; MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c index a947a63fb44a..7b974802dfc7 100644 --- a/drivers/watchdog/sbc60xxwdt.c +++ b/drivers/watchdog/sbc60xxwdt.c @@ -146,7 +146,7 @@ static void wdt_startup(void) static void wdt_turnoff(void) { /* Stop the timer */ - del_timer(&timer); + del_timer_sync(&timer); inb_p(wdt_stop); pr_info("Watchdog timer is now disabled...\n"); } diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index f0f1e3b2e463..ee9ff38929eb 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -73,16 +73,21 @@ #define SBSA_GWDT_WCS_WS0 BIT(1) #define SBSA_GWDT_WCS_WS1 BIT(2) +#define SBSA_GWDT_VERSION_MASK 0xF +#define SBSA_GWDT_VERSION_SHIFT 16 + /** * struct sbsa_gwdt - Internal representation of the SBSA GWDT * @wdd: kernel watchdog_device structure * @clk: store the System Counter clock frequency, in Hz. + * @version: store the architecture version * @refresh_base: Virtual address of the watchdog refresh frame * @control_base: Virtual address of the watchdog control frame */ struct sbsa_gwdt { struct watchdog_device wdd; u32 clk; + int version; void __iomem *refresh_base; void __iomem *control_base; }; @@ -112,6 +117,30 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +/* + * Arm Base System Architecture 1.0 introduces watchdog v1 which + * increases the length watchdog offset register to 48 bits. + * - For version 0: WOR is 32 bits; + * - For version 1: WOR is 48 bits which comprises the register + * offset 0x8 and 0xC, and the bits [63:48] are reserved which are + * Read-As-Zero and Writes-Ignored. + */ +static u64 sbsa_gwdt_reg_read(struct sbsa_gwdt *gwdt) +{ + if (gwdt->version == 0) + return readl(gwdt->control_base + SBSA_GWDT_WOR); + else + return readq(gwdt->control_base + SBSA_GWDT_WOR); +} + +static void sbsa_gwdt_reg_write(u64 val, struct sbsa_gwdt *gwdt) +{ + if (gwdt->version == 0) + writel((u32)val, gwdt->control_base + SBSA_GWDT_WOR); + else + writeq(val, gwdt->control_base + SBSA_GWDT_WOR); +} + /* * watchdog operation functions */ @@ -123,16 +152,14 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd, wdd->timeout = timeout; if (action) - writel(gwdt->clk * timeout, - gwdt->control_base + SBSA_GWDT_WOR); + sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt); else /* * In the single stage mode, The first signal (WS0) is ignored, * the timeout is (WOR * 2), so the WOR should be configured * to half value of timeout. */ - writel(gwdt->clk / 2 * timeout, - gwdt->control_base + SBSA_GWDT_WOR); + sbsa_gwdt_reg_write(gwdt->clk / 2 * timeout, gwdt); return 0; } @@ -149,7 +176,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) */ if (!action && !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) - timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); + timeleft += sbsa_gwdt_reg_read(gwdt); timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - arch_timer_read_counter(); @@ -172,6 +199,17 @@ static int sbsa_gwdt_keepalive(struct watchdog_device *wdd) return 0; } +static void sbsa_gwdt_get_version(struct watchdog_device *wdd) +{ + struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); + int ver; + + ver = readl(gwdt->control_base + SBSA_GWDT_W_IIDR); + ver = (ver >> SBSA_GWDT_VERSION_SHIFT) & SBSA_GWDT_VERSION_MASK; + + gwdt->version = ver; +} + static int sbsa_gwdt_start(struct watchdog_device *wdd) { struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); @@ -252,10 +290,14 @@ static int sbsa_gwdt_probe(struct platform_device *pdev) wdd->info = &sbsa_gwdt_info; wdd->ops = &sbsa_gwdt_ops; wdd->min_timeout = 1; - wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000; wdd->timeout = DEFAULT_TIMEOUT; watchdog_set_drvdata(wdd, gwdt); watchdog_set_nowayout(wdd, nowayout); + sbsa_gwdt_get_version(wdd); + if (gwdt->version == 0) + wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000; + else + wdd->max_hw_heartbeat_ms = GENMASK_ULL(47, 0) / gwdt->clk * 1000; status = readl(cf_base + SBSA_GWDT_WCS); if (status & SBSA_GWDT_WCS_WS1) { diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index e66e6b905964..ca65468f4b9c 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c @@ -186,7 +186,7 @@ static int wdt_startup(void) static int wdt_turnoff(void) { /* Stop the timer */ - del_timer(&timer); + del_timer_sync(&timer); /* Stop the watchdog */ wdt_config(0); diff --git a/drivers/watchdog/sl28cpld_wdt.c b/drivers/watchdog/sl28cpld_wdt.c index a45047d8d9ab..2de93298475f 100644 --- a/drivers/watchdog/sl28cpld_wdt.c +++ b/drivers/watchdog/sl28cpld_wdt.c @@ -164,7 +164,7 @@ static int sl28cpld_wdt_probe(struct platform_device *pdev) /* * Initial timeout value, may be overwritten by device tree or module - * parmeter in watchdog_init_timeout(). + * parameter in watchdog_init_timeout(). * * Reading a zero here means that either the hardware has a default * value of zero (which is very unlikely and definitely a hardware diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 58a00e1ab23b..dbeb2146c968 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -11,7 +11,6 @@ * warranty of any kind, whether express or implied. */ -#include #include #include #include @@ -23,8 +22,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -58,7 +57,8 @@ * @wdd: instance of struct watchdog_device * @lock: spin lock protecting dev structure and io access * @base: base address of wdt - * @clk: clock structure of wdt + * @clk: (optional) clock structure of wdt + * @rate: (optional) clock rate when provided via properties * @adev: amba device structure of wdt * @status: current status of wdt * @load_val: load value to be set for current timeout @@ -231,6 +231,7 @@ static int sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) { struct sp805_wdt *wdt; + u64 rate = 0; int ret = 0; wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL); @@ -243,25 +244,23 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); - if (adev->dev.of_node) { - wdt->clk = devm_clk_get(&adev->dev, NULL); - if (IS_ERR(wdt->clk)) { - dev_err(&adev->dev, "Clock not found\n"); - return PTR_ERR(wdt->clk); - } - wdt->rate = clk_get_rate(wdt->clk); - } else if (has_acpi_companion(&adev->dev)) { - /* - * When Driver probe with ACPI device, clock devices - * are not available, so watchdog rate get from - * clock-frequency property given in _DSD object. - */ - device_property_read_u64(&adev->dev, "clock-frequency", - &wdt->rate); - if (!wdt->rate) { - dev_err(&adev->dev, "no clock-frequency property\n"); - return -ENODEV; - } + /* + * When driver probe with ACPI device, clock devices + * are not available, so watchdog rate get from + * clock-frequency property given in _DSD object. + */ + device_property_read_u64(&adev->dev, "clock-frequency", &rate); + + wdt->clk = devm_clk_get_optional(&adev->dev, NULL); + if (IS_ERR(wdt->clk)) + return dev_err_probe(&adev->dev, PTR_ERR(wdt->clk), "Clock not found\n"); + + wdt->rate = clk_get_rate(wdt->clk); + if (!wdt->rate) + wdt->rate = rate; + if (!wdt->rate) { + dev_err(&adev->dev, "no clock-frequency property\n"); + return -ENODEV; } wdt->adev = adev; diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c index 5772cc5d3780..f2650863fd02 100644 --- a/drivers/watchdog/w83877f_wdt.c +++ b/drivers/watchdog/w83877f_wdt.c @@ -166,7 +166,7 @@ static void wdt_startup(void) static void wdt_turnoff(void) { /* Stop the timer */ - del_timer(&timer); + del_timer_sync(&timer); wdt_change(WDT_DISABLE); diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h index a5062e8e0d13..5b35a8439e26 100644 --- a/drivers/watchdog/watchdog_core.h +++ b/drivers/watchdog/watchdog_core.h @@ -7,6 +7,8 @@ * * (c) Copyright 2008-2011 Wim Van Sebroeck . * + * (c) Copyright 2021 Hewlett Packard Enterprise Development LP. + * * This source code is part of the generic code that can be used * by all the watchdog timer drivers. * @@ -22,8 +24,38 @@ * This material is provided "AS-IS" and at no charge. */ +#include +#include + #define MAX_DOGS 32 /* Maximum number of watchdog devices */ +/* + * struct watchdog_core_data - watchdog core internal data + * @dev: The watchdog's internal device + * @cdev: The watchdog's Character device. + * @wdd: Pointer to watchdog device. + * @lock: Lock for watchdog core. + * @status: Watchdog core internal status bits. + */ +struct watchdog_core_data { + struct device dev; + struct cdev cdev; + struct watchdog_device *wdd; + struct mutex lock; + ktime_t last_keepalive; + ktime_t last_hw_keepalive; + ktime_t open_deadline; + struct hrtimer timer; + struct kthread_work work; +#if IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT) + struct hrtimer pretimeout_timer; +#endif + unsigned long status; /* Internal status bits */ +#define _WDOG_DEV_OPEN 0 /* Opened ? */ +#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */ +#define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */ +}; + /* * Functions/procedures to be called by the core */ @@ -31,3 +63,19 @@ extern int watchdog_dev_register(struct watchdog_device *); extern void watchdog_dev_unregister(struct watchdog_device *); extern int __init watchdog_dev_init(void); extern void __exit watchdog_dev_exit(void); + +static inline bool watchdog_have_pretimeout(struct watchdog_device *wdd) +{ + return wdd->info->options & WDIOF_PRETIMEOUT || + IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT); +} + +#if IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT) +void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd); +void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd); +void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd); +#else +static inline void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd) {} +static inline void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd) {} +static inline void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd) {} +#endif diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 2946f3a63110..3bab32485273 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -7,6 +7,7 @@ * * (c) Copyright 2008-2011 Wim Van Sebroeck . * + * (c) Copyright 2021 Hewlett Packard Enterprise Development LP. * * This source code is part of the generic code that can be used * by all the watchdog timer drivers. @@ -46,30 +47,6 @@ #include "watchdog_core.h" #include "watchdog_pretimeout.h" -/* - * struct watchdog_core_data - watchdog core internal data - * @dev: The watchdog's internal device - * @cdev: The watchdog's Character device. - * @wdd: Pointer to watchdog device. - * @lock: Lock for watchdog core. - * @status: Watchdog core internal status bits. - */ -struct watchdog_core_data { - struct device dev; - struct cdev cdev; - struct watchdog_device *wdd; - struct mutex lock; - ktime_t last_keepalive; - ktime_t last_hw_keepalive; - ktime_t open_deadline; - struct hrtimer timer; - struct kthread_work work; - unsigned long status; /* Internal status bits */ -#define _WDOG_DEV_OPEN 0 /* Opened ? */ -#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */ -#define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */ -}; - /* the dev_t structure to store the dynamically allocated watchdog devices */ static dev_t watchdog_devt; /* Reference to watchdog device behind /dev/watchdog */ @@ -185,6 +162,9 @@ static int __watchdog_ping(struct watchdog_device *wdd) else err = wdd->ops->start(wdd); /* restart watchdog */ + if (err == 0) + watchdog_hrtimer_pretimeout_start(wdd); + watchdog_update_worker(wdd); return err; @@ -275,8 +255,10 @@ static int watchdog_start(struct watchdog_device *wdd) started_at = ktime_get(); if (watchdog_hw_running(wdd) && wdd->ops->ping) { err = __watchdog_ping(wdd); - if (err == 0) + if (err == 0) { set_bit(WDOG_ACTIVE, &wdd->status); + watchdog_hrtimer_pretimeout_start(wdd); + } } else { err = wdd->ops->start(wdd); if (err == 0) { @@ -284,6 +266,7 @@ static int watchdog_start(struct watchdog_device *wdd) wd_data->last_keepalive = started_at; wd_data->last_hw_keepalive = started_at; watchdog_update_worker(wdd); + watchdog_hrtimer_pretimeout_start(wdd); } } @@ -325,6 +308,7 @@ static int watchdog_stop(struct watchdog_device *wdd) if (err == 0) { clear_bit(WDOG_ACTIVE, &wdd->status); watchdog_update_worker(wdd); + watchdog_hrtimer_pretimeout_stop(wdd); } return err; @@ -361,6 +345,9 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd) if (test_and_clear_bit(_WDOG_KEEPALIVE, &wd_data->status)) status |= WDIOF_KEEPALIVEPING; + if (IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT)) + status |= WDIOF_PRETIMEOUT; + return status; } @@ -408,7 +395,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd, { int err = 0; - if (!(wdd->info->options & WDIOF_PRETIMEOUT)) + if (!watchdog_have_pretimeout(wdd)) return -EOPNOTSUPP; if (watchdog_pretimeout_invalid(wdd, timeout)) @@ -451,7 +438,8 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status)); + return sysfs_emit(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, + &wdd->status)); } static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr, @@ -485,7 +473,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, status = watchdog_get_status(wdd); mutex_unlock(&wd_data->lock); - return sprintf(buf, "0x%x\n", status); + return sysfs_emit(buf, "0x%x\n", status); } static DEVICE_ATTR_RO(status); @@ -494,7 +482,7 @@ static ssize_t bootstatus_show(struct device *dev, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->bootstatus); + return sysfs_emit(buf, "%u\n", wdd->bootstatus); } static DEVICE_ATTR_RO(bootstatus); @@ -510,7 +498,7 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, status = watchdog_get_timeleft(wdd, &val); mutex_unlock(&wd_data->lock); if (!status) - status = sprintf(buf, "%u\n", val); + status = sysfs_emit(buf, "%u\n", val); return status; } @@ -521,16 +509,34 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->timeout); + return sysfs_emit(buf, "%u\n", wdd->timeout); } static DEVICE_ATTR_RO(timeout); +static ssize_t min_timeout_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", wdd->min_timeout); +} +static DEVICE_ATTR_RO(min_timeout); + +static ssize_t max_timeout_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", wdd->max_timeout); +} +static DEVICE_ATTR_RO(max_timeout); + static ssize_t pretimeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->pretimeout); + return sysfs_emit(buf, "%u\n", wdd->pretimeout); } static DEVICE_ATTR_RO(pretimeout); @@ -539,7 +545,7 @@ static ssize_t identity_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", wdd->info->identity); + return sysfs_emit(buf, "%s\n", wdd->info->identity); } static DEVICE_ATTR_RO(identity); @@ -549,9 +555,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, struct watchdog_device *wdd = dev_get_drvdata(dev); if (watchdog_active(wdd)) - return sprintf(buf, "active\n"); + return sysfs_emit(buf, "active\n"); - return sprintf(buf, "inactive\n"); + return sysfs_emit(buf, "inactive\n"); } static DEVICE_ATTR_RO(state); @@ -594,13 +600,11 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) mode = 0; - else if (attr == &dev_attr_pretimeout.attr && - !(wdd->info->options & WDIOF_PRETIMEOUT)) + else if (attr == &dev_attr_pretimeout.attr && !watchdog_have_pretimeout(wdd)) mode = 0; else if ((attr == &dev_attr_pretimeout_governor.attr || attr == &dev_attr_pretimeout_available_governors.attr) && - (!(wdd->info->options & WDIOF_PRETIMEOUT) || - !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) + (!watchdog_have_pretimeout(wdd) || !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) mode = 0; return mode; @@ -609,6 +613,8 @@ static struct attribute *wdt_attrs[] = { &dev_attr_state.attr, &dev_attr_identity.attr, &dev_attr_timeout.attr, + &dev_attr_min_timeout.attr, + &dev_attr_max_timeout.attr, &dev_attr_pretimeout.attr, &dev_attr_timeleft.attr, &dev_attr_bootstatus.attr, @@ -1009,6 +1015,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd) kthread_init_work(&wd_data->work, watchdog_ping_work); hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); wd_data->timer.function = watchdog_timer_expired; + watchdog_hrtimer_pretimeout_init(wdd); if (wdd->id == 0) { old_wd_data = wd_data; @@ -1096,6 +1103,7 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd) hrtimer_cancel(&wd_data->timer); kthread_cancel_work_sync(&wd_data->work); + watchdog_hrtimer_pretimeout_stop(wdd); put_device(&wd_data->dev); } diff --git a/drivers/watchdog/watchdog_hrtimer_pretimeout.c b/drivers/watchdog/watchdog_hrtimer_pretimeout.c new file mode 100644 index 000000000000..940b53718a91 --- /dev/null +++ b/drivers/watchdog/watchdog_hrtimer_pretimeout.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (c) Copyright 2021 Hewlett Packard Enterprise Development LP. + */ + +#include +#include + +#include "watchdog_core.h" +#include "watchdog_pretimeout.h" + +static enum hrtimer_restart watchdog_hrtimer_pretimeout(struct hrtimer *timer) +{ + struct watchdog_core_data *wd_data; + + wd_data = container_of(timer, struct watchdog_core_data, pretimeout_timer); + + watchdog_notify_pretimeout(wd_data->wdd); + return HRTIMER_NORESTART; +} + +void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd) +{ + struct watchdog_core_data *wd_data = wdd->wd_data; + + hrtimer_init(&wd_data->pretimeout_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + wd_data->pretimeout_timer.function = watchdog_hrtimer_pretimeout; +} + +void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd) +{ + if (!(wdd->info->options & WDIOF_PRETIMEOUT) && + !watchdog_pretimeout_invalid(wdd, wdd->pretimeout)) + hrtimer_start(&wdd->wd_data->pretimeout_timer, + ktime_set(wdd->timeout - wdd->pretimeout, 0), + HRTIMER_MODE_REL); + else + hrtimer_cancel(&wdd->wd_data->pretimeout_timer); +} + +void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd) +{ + hrtimer_cancel(&wdd->wd_data->pretimeout_timer); +} diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c index 01ca84be240f..376a495ab80c 100644 --- a/drivers/watchdog/watchdog_pretimeout.c +++ b/drivers/watchdog/watchdog_pretimeout.c @@ -9,6 +9,7 @@ #include #include +#include "watchdog_core.h" #include "watchdog_pretimeout.h" /* Default watchdog pretimeout governor */ @@ -55,7 +56,7 @@ int watchdog_pretimeout_available_governors_get(char *buf) mutex_lock(&governor_lock); list_for_each_entry(priv, &governor_list, entry) - count += sprintf(buf + count, "%s\n", priv->gov->name); + count += sysfs_emit_at(buf, count, "%s\n", priv->gov->name); mutex_unlock(&governor_lock); @@ -68,7 +69,7 @@ int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf) spin_lock_irq(&pretimeout_lock); if (wdd->gov) - count = sprintf(buf, "%s\n", wdd->gov->name); + count = sysfs_emit(buf, "%s\n", wdd->gov->name); spin_unlock_irq(&pretimeout_lock); return count; @@ -177,7 +178,7 @@ int watchdog_register_pretimeout(struct watchdog_device *wdd) { struct watchdog_pretimeout *p; - if (!(wdd->info->options & WDIOF_PRETIMEOUT)) + if (!watchdog_have_pretimeout(wdd)) return 0; p = kzalloc(sizeof(*p), GFP_KERNEL); @@ -197,7 +198,7 @@ void watchdog_unregister_pretimeout(struct watchdog_device *wdd) { struct watchdog_pretimeout *p, *t; - if (!(wdd->info->options & WDIOF_PRETIMEOUT)) + if (!watchdog_have_pretimeout(wdd)) return; spin_lock_irq(&pretimeout_lock); diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index cec7917790e5..195c8c004b69 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -208,7 +208,7 @@ static int wdat_wdt_enable_reboot(struct wdat_wdt *wdat) /* * WDAT specification says that the watchdog is required to reboot * the system when it fires. However, it also states that it is - * recommeded to make it configurable through hardware register. We + * recommended to make it configurable through hardware register. We * enable reboot now if it is configurable, just in case. */ ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_REBOOT, 0, NULL); @@ -475,7 +475,7 @@ static int wdat_wdt_suspend_noirq(struct device *dev) return 0; /* - * We need to stop the watchdog if firmare is not doing it or if we + * We need to stop the watchdog if firmware is not doing it or if we * are going suspend to idle (where firmware is not involved). If * firmware is stopping the watchdog we kick it here one more time * to give it some time. diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index a9e40b5c633e..183876156243 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c @@ -494,7 +494,7 @@ static int wdt_temp_release(struct inode *inode, struct file *file) } /** - * notify_sys: + * wdt_notify_sys: * @this: our notifier block * @code: the event being reported * @unused: unused @@ -558,7 +558,7 @@ static struct notifier_block wdt_notifier = { }; /** - * cleanup_module: + * wdt_exit: * * Unload the watchdog. You cannot do this with any file handles open. * If your watchdog is set to continue ticking on close and you unload diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index c3254ba5ace6..d5e56b601351 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c @@ -537,7 +537,7 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file) } /** - * notify_sys: + * wdtpci_notify_sys: * @this: our notifier block * @code: the event being reported * @unused: unused diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c index 4297280807ca..c5a9b820d43a 100644 --- a/drivers/watchdog/ziirave_wdt.c +++ b/drivers/watchdog/ziirave_wdt.c @@ -69,9 +69,6 @@ static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL, #define ZIIRAVE_CMD_JUMP_TO_BOOTLOADER_MAGIC 1 #define ZIIRAVE_CMD_RESET_PROCESSOR_MAGIC 1 -#define ZIIRAVE_FW_VERSION_FMT "02.%02u.%02u" -#define ZIIRAVE_BL_VERSION_FMT "01.%02u.%02u" - struct ziirave_wdt_rev { unsigned char major; unsigned char minor; @@ -445,8 +442,9 @@ static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev, if (ret) return ret; - ret = sprintf(buf, ZIIRAVE_FW_VERSION_FMT, w_priv->firmware_rev.major, - w_priv->firmware_rev.minor); + ret = sysfs_emit(buf, "02.%02u.%02u\n", + w_priv->firmware_rev.major, + w_priv->firmware_rev.minor); mutex_unlock(&w_priv->sysfs_mutex); @@ -468,8 +466,9 @@ static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev, if (ret) return ret; - ret = sprintf(buf, ZIIRAVE_BL_VERSION_FMT, w_priv->bootloader_rev.major, - w_priv->bootloader_rev.minor); + ret = sysfs_emit(buf, "01.%02u.%02u\n", + w_priv->bootloader_rev.major, + w_priv->bootloader_rev.minor); mutex_unlock(&w_priv->sysfs_mutex); @@ -491,7 +490,7 @@ static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev, if (ret) return ret; - ret = sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]); + ret = sysfs_emit(buf, "%s\n", ziirave_reasons[w_priv->reset_reason]); mutex_unlock(&w_priv->sysfs_mutex); @@ -536,7 +535,7 @@ static ssize_t ziirave_wdt_sysfs_store_firm(struct device *dev, } dev_info(&client->dev, - "Firmware updated to version " ZIIRAVE_FW_VERSION_FMT "\n", + "Firmware updated to version 02.%02u.%02u\n", w_priv->firmware_rev.major, w_priv->firmware_rev.minor); /* Restore the watchdog timeout */ @@ -677,7 +676,7 @@ static int ziirave_wdt_probe(struct i2c_client *client, } dev_info(&client->dev, - "Firmware version: " ZIIRAVE_FW_VERSION_FMT "\n", + "Firmware version: 02.%02u.%02u\n", w_priv->firmware_rev.major, w_priv->firmware_rev.minor); ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev, @@ -688,7 +687,7 @@ static int ziirave_wdt_probe(struct i2c_client *client, } dev_info(&client->dev, - "Bootloader version: " ZIIRAVE_BL_VERSION_FMT "\n", + "Bootloader version: 01.%02u.%02u\n", w_priv->bootloader_rev.major, w_priv->bootloader_rev.minor); w_priv->reset_reason = i2c_smbus_read_byte_data(client, diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 1bcdd5227771..47aa3a1ccaf5 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c @@ -92,7 +92,7 @@ static int xen_pcpu_up(uint32_t cpu_id) return HYPERVISOR_platform_op(&op); } -static ssize_t show_online(struct device *dev, +static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -101,7 +101,7 @@ static ssize_t show_online(struct device *dev, return sprintf(buf, "%u\n", !!(cpu->flags & XEN_PCPU_FLAGS_ONLINE)); } -static ssize_t __ref store_online(struct device *dev, +static ssize_t __ref online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -130,7 +130,7 @@ static ssize_t __ref store_online(struct device *dev, ret = count; return ret; } -static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); +static DEVICE_ATTR_RW(online); static struct attribute *pcpu_dev_attrs[] = { &dev_attr_online.attr, diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index a8d24433c8e9..8cd583db20b1 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -134,13 +134,13 @@ void xen_balloon_init(void) EXPORT_SYMBOL_GPL(xen_balloon_init); #define BALLOON_SHOW(name, format, args...) \ - static ssize_t show_##name(struct device *dev, \ + static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ return sprintf(buf, format, ##args); \ } \ - static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + static DEVICE_ATTR_RO(name) BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); @@ -152,16 +152,15 @@ static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); static DEVICE_BOOL_ATTR(scrub_pages, 0644, xen_scrub_pages); -static ssize_t show_target_kb(struct device *dev, struct device_attribute *attr, +static ssize_t target_kb_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); } -static ssize_t store_target_kb(struct device *dev, +static ssize_t target_kb_store(struct device *dev, struct device_attribute *attr, - const char *buf, - size_t count) + const char *buf, size_t count) { char *endchar; unsigned long long target_bytes; @@ -176,22 +175,19 @@ static ssize_t store_target_kb(struct device *dev, return count; } -static DEVICE_ATTR(target_kb, S_IRUGO | S_IWUSR, - show_target_kb, store_target_kb); +static DEVICE_ATTR_RW(target_kb); - -static ssize_t show_target(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t target_show(struct device *dev, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%llu\n", (unsigned long long)balloon_stats.target_pages << PAGE_SHIFT); } -static ssize_t store_target(struct device *dev, +static ssize_t target_store(struct device *dev, struct device_attribute *attr, - const char *buf, - size_t count) + const char *buf, size_t count) { char *endchar; unsigned long long target_bytes; @@ -206,9 +202,7 @@ static ssize_t store_target(struct device *dev, return count; } -static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, - show_target, store_target); - +static DEVICE_ATTR_RW(target); static struct attribute *balloon_attrs[] = { &dev_attr_target_kb.attr, diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 97f0d234482d..33d09b3f6211 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -207,7 +207,7 @@ void xenbus_otherend_changed(struct xenbus_watch *watch, EXPORT_SYMBOL_GPL(xenbus_otherend_changed); #define XENBUS_SHOW_STAT(name) \ -static ssize_t show_##name(struct device *_dev, \ +static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, \ char *buf) \ { \ @@ -215,14 +215,14 @@ static ssize_t show_##name(struct device *_dev, \ \ return sprintf(buf, "%d\n", atomic_read(&dev->name)); \ } \ -static DEVICE_ATTR(name, 0444, show_##name, NULL) +static DEVICE_ATTR_RO(name) XENBUS_SHOW_STAT(event_channels); XENBUS_SHOW_STAT(events); XENBUS_SHOW_STAT(spurious_events); XENBUS_SHOW_STAT(jiffies_eoi_delayed); -static ssize_t show_spurious_threshold(struct device *_dev, +static ssize_t spurious_threshold_show(struct device *_dev, struct device_attribute *attr, char *buf) { @@ -231,9 +231,9 @@ static ssize_t show_spurious_threshold(struct device *_dev, return sprintf(buf, "%d\n", dev->spurious_threshold); } -static ssize_t set_spurious_threshold(struct device *_dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t spurious_threshold_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct xenbus_device *dev = to_xenbus_device(_dev); unsigned int val; @@ -248,8 +248,7 @@ static ssize_t set_spurious_threshold(struct device *_dev, return count; } -static DEVICE_ATTR(spurious_threshold, 0644, show_spurious_threshold, - set_spurious_threshold); +static DEVICE_ATTR_RW(spurious_threshold); static struct attribute *xenbus_attrs[] = { &dev_attr_event_channels.attr, diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index c1570fada3d8..a1e2813731d1 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -82,10 +82,6 @@ static int ceph_set_page_dirty(struct page *page) struct inode *inode; struct ceph_inode_info *ci; struct ceph_snap_context *snapc; - int ret; - - if (unlikely(!mapping)) - return !TestSetPageDirty(page); if (PageDirty(page)) { dout("%p set_page_dirty %p idx %lu -- already dirty\n", @@ -130,11 +126,7 @@ static int ceph_set_page_dirty(struct page *page) BUG_ON(PagePrivate(page)); attach_page_private(page, snapc); - ret = __set_page_dirty_nobuffers(page); - WARN_ON(!PageLocked(page)); - WARN_ON(!page->mapping); - - return ret; + return __set_page_dirty_nobuffers(page); } /* @@ -226,7 +218,7 @@ static void finish_netfs_read(struct ceph_osd_request *req) int err = req->r_result; ceph_update_read_metrics(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + req->r_end_latency, osd_data->length, err); dout("%s: result %d subreq->len=%zu i_size=%lld\n", __func__, req->r_result, subreq->len, i_size_read(req->r_inode)); @@ -313,7 +305,7 @@ static void ceph_readahead_cleanup(struct address_space *mapping, void *priv) ceph_put_cap_refs(ci, got); } -const struct netfs_read_request_ops ceph_netfs_read_ops = { +static const struct netfs_read_request_ops ceph_netfs_read_ops = { .init_rreq = ceph_init_rreq, .is_cache_enabled = ceph_is_cache_enabled, .begin_cache_operation = ceph_begin_cache_operation, @@ -560,7 +552,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) err = ceph_osdc_wait_request(osdc, req); ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + req->r_end_latency, len, err); ceph_osdc_put_request(req); if (err == 0) @@ -635,6 +627,7 @@ static void writepages_finish(struct ceph_osd_request *req) struct ceph_snap_context *snapc = req->r_snapc; struct address_space *mapping = inode->i_mapping; struct ceph_fs_client *fsc = ceph_inode_to_client(inode); + unsigned int len = 0; bool remove_page; dout("writepages_finish %p rc %d\n", inode, rc); @@ -647,9 +640,6 @@ static void writepages_finish(struct ceph_osd_request *req) ceph_clear_error_write(ci); } - ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, rc); - /* * We lost the cache cap, need to truncate the page before * it is unlocked, otherwise we'd truncate it later in the @@ -666,6 +656,7 @@ static void writepages_finish(struct ceph_osd_request *req) osd_data = osd_req_op_extent_osd_data(req, i); BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_PAGES); + len += osd_data->length; num_pages = calc_pages_for((u64)osd_data->alignment, (u64)osd_data->length); total_pages += num_pages; @@ -696,6 +687,9 @@ static void writepages_finish(struct ceph_osd_request *req) release_pages(osd_data->pages, num_pages); } + ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, rc); + ceph_put_wrbuffer_cap_refs(ci, total_pages, snapc); osd_data = osd_req_op_extent_osd_data(req, 0); @@ -1711,7 +1705,7 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page) err = ceph_osdc_wait_request(&fsc->client->osdc, req); ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + req->r_end_latency, len, err); out_put: ceph_osdc_put_request(req); diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index a5e93b185515..7bdefd0c789a 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -645,9 +645,7 @@ void ceph_add_cap(struct inode *inode, dout("add_cap %p mds%d cap %llx %s seq %d\n", inode, session->s_mds, cap_id, ceph_cap_string(issued), seq); - spin_lock(&session->s_gen_ttl_lock); - gen = session->s_cap_gen; - spin_unlock(&session->s_gen_ttl_lock); + gen = atomic_read(&session->s_cap_gen); cap = __get_cap_for_mds(ci, mds); if (!cap) { @@ -785,10 +783,8 @@ static int __cap_is_valid(struct ceph_cap *cap) unsigned long ttl; u32 gen; - spin_lock(&cap->session->s_gen_ttl_lock); - gen = cap->session->s_cap_gen; + gen = atomic_read(&cap->session->s_cap_gen); ttl = cap->session->s_cap_ttl; - spin_unlock(&cap->session->s_gen_ttl_lock); if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) { dout("__cap_is_valid %p cap %p issued %s " @@ -1182,7 +1178,8 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) * s_cap_gen while session is in the reconnect state. */ if (queue_release && - (!session->s_cap_reconnect || cap->cap_gen == session->s_cap_gen)) { + (!session->s_cap_reconnect || + cap->cap_gen == atomic_read(&session->s_cap_gen))) { cap->queue_release = 1; if (removed) { __ceph_queue_cap_release(session, cap); @@ -1534,7 +1531,7 @@ static inline int __send_flush_snap(struct inode *inode, * asynchronously back to the MDS once sync writes complete and dirty * data is written out. * - * Called under i_ceph_lock. Takes s_mutex as needed. + * Called under i_ceph_lock. */ static void __ceph_flush_snaps(struct ceph_inode_info *ci, struct ceph_mds_session *session) @@ -1656,7 +1653,6 @@ retry: mds = ci->i_auth_cap->session->s_mds; if (session && session->s_mds != mds) { dout(" oops, wrong session %p mutex\n", session); - mutex_unlock(&session->s_mutex); ceph_put_mds_session(session); session = NULL; } @@ -1665,10 +1661,6 @@ retry: mutex_lock(&mdsc->mutex); session = __ceph_lookup_mds_session(mdsc, mds); mutex_unlock(&mdsc->mutex); - if (session) { - dout(" inverting session/ino locks on %p\n", session); - mutex_lock(&session->s_mutex); - } goto retry; } @@ -1680,12 +1672,10 @@ retry: out: spin_unlock(&ci->i_ceph_lock); - if (psession) { + if (psession) *psession = session; - } else if (session) { - mutex_unlock(&session->s_mutex); + else ceph_put_mds_session(session); - } /* we flushed them all; remove this inode from the queue */ spin_lock(&mdsc->snap_flush_lock); list_del_init(&ci->i_snap_flush_item); @@ -1915,7 +1905,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_cap *cap; u64 flush_tid, oldest_flush_tid; int file_wanted, used, cap_used; - int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */ int issued, implemented, want, retain, revoking, flushing = 0; int mds = -1; /* keep track of how far we've gone through i_caps list to avoid an infinite loop on retry */ @@ -1923,14 +1912,13 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, bool queue_invalidate = false; bool tried_invalidate = false; + if (session) + ceph_get_mds_session(session); + spin_lock(&ci->i_ceph_lock); if (ci->i_ceph_flags & CEPH_I_FLUSH) flags |= CHECK_CAPS_FLUSH; - - goto retry_locked; retry: - spin_lock(&ci->i_ceph_lock); -retry_locked: /* Caps wanted by virtue of active open files. */ file_wanted = __ceph_caps_file_wanted(ci); @@ -2010,7 +1998,7 @@ retry_locked: ci->i_rdcache_revoking = ci->i_rdcache_gen; } tried_invalidate = true; - goto retry_locked; + goto retry; } for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { @@ -2024,8 +2012,6 @@ retry_locked: ((flags & CHECK_CAPS_AUTHONLY) && cap != ci->i_auth_cap)) continue; - /* NOTE: no side-effects allowed, until we take s_mutex */ - /* * If we have an auth cap, we don't need to consider any * overlapping caps as used. @@ -2088,37 +2074,8 @@ retry_locked: continue; /* nope, all good */ ack: - if (session && session != cap->session) { - dout("oops, wrong session %p mutex\n", session); - mutex_unlock(&session->s_mutex); - session = NULL; - } - if (!session) { - session = cap->session; - if (mutex_trylock(&session->s_mutex) == 0) { - dout("inverting session/ino locks on %p\n", - session); - session = ceph_get_mds_session(session); - spin_unlock(&ci->i_ceph_lock); - if (took_snap_rwsem) { - up_read(&mdsc->snap_rwsem); - took_snap_rwsem = 0; - } - if (session) { - mutex_lock(&session->s_mutex); - ceph_put_mds_session(session); - } else { - /* - * Because we take the reference while - * holding the i_ceph_lock, it should - * never be NULL. Throw a warning if it - * ever is. - */ - WARN_ON_ONCE(true); - } - goto retry; - } - } + ceph_put_mds_session(session); + session = ceph_get_mds_session(cap->session); /* kick flushing and flush snaps before sending normal * cap message */ @@ -2130,20 +2087,7 @@ ack: if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS) __ceph_flush_snaps(ci, session); - goto retry_locked; - } - - /* take snap_rwsem after session mutex */ - if (!took_snap_rwsem) { - if (down_read_trylock(&mdsc->snap_rwsem) == 0) { - dout("inverting snap/in locks on %p\n", - inode); - spin_unlock(&ci->i_ceph_lock); - down_read(&mdsc->snap_rwsem); - took_snap_rwsem = 1; - goto retry; - } - took_snap_rwsem = 1; + goto retry; } if (cap == ci->i_auth_cap && ci->i_dirty_caps) { @@ -2165,9 +2109,10 @@ ack: __prep_cap(&arg, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, want, retain, flushing, flush_tid, oldest_flush_tid); - spin_unlock(&ci->i_ceph_lock); + spin_unlock(&ci->i_ceph_lock); __send_cap(&arg, ci); + spin_lock(&ci->i_ceph_lock); goto retry; /* retake i_ceph_lock and restart our cap scan. */ } @@ -2182,13 +2127,9 @@ ack: spin_unlock(&ci->i_ceph_lock); + ceph_put_mds_session(session); if (queue_invalidate) ceph_queue_invalidate(inode); - - if (session) - mutex_unlock(&session->s_mutex); - if (took_snap_rwsem) - up_read(&mdsc->snap_rwsem); } /* @@ -2198,26 +2139,17 @@ static int try_flush_caps(struct inode *inode, u64 *ptid) { struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); - struct ceph_mds_session *session = NULL; int flushing = 0; u64 flush_tid = 0, oldest_flush_tid = 0; -retry: spin_lock(&ci->i_ceph_lock); retry_locked: if (ci->i_dirty_caps && ci->i_auth_cap) { struct ceph_cap *cap = ci->i_auth_cap; struct cap_msg_args arg; + struct ceph_mds_session *session = cap->session; - if (session != cap->session) { - spin_unlock(&ci->i_ceph_lock); - if (session) - mutex_unlock(&session->s_mutex); - session = cap->session; - mutex_lock(&session->s_mutex); - goto retry; - } - if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) { + if (session->s_state < CEPH_MDS_SESSION_OPEN) { spin_unlock(&ci->i_ceph_lock); goto out; } @@ -2254,9 +2186,6 @@ retry_locked: spin_unlock(&ci->i_ceph_lock); } out: - if (session) - mutex_unlock(&session->s_mutex); - *ptid = flush_tid; return flushing; } @@ -3213,8 +3142,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, if (complete_capsnap) wake_up_all(&ci->i_cap_wq); while (put-- > 0) { - /* avoid calling iput_final() in osd dispatch threads */ - ceph_async_iput(inode); + iput(inode); } } @@ -3288,7 +3216,7 @@ static void handle_cap_grant(struct inode *inode, u64 size = le64_to_cpu(grant->size); u64 max_size = le64_to_cpu(grant->max_size); unsigned char check_caps = 0; - bool was_stale = cap->cap_gen < session->s_cap_gen; + bool was_stale = cap->cap_gen < atomic_read(&session->s_cap_gen); bool wake = false; bool writeback = false; bool queue_trunc = false; @@ -3340,7 +3268,7 @@ static void handle_cap_grant(struct inode *inode, } /* side effects now are allowed */ - cap->cap_gen = session->s_cap_gen; + cap->cap_gen = atomic_read(&session->s_cap_gen); cap->seq = seq; __check_cap_issue(ci, cap, newcaps); @@ -3553,13 +3481,12 @@ static void handle_cap_grant(struct inode *inode, if (wake) wake_up_all(&ci->i_cap_wq); + mutex_unlock(&session->s_mutex); if (check_caps == 1) ceph_check_caps(ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL, session); else if (check_caps == 2) ceph_check_caps(ci, CHECK_CAPS_NOINVAL, session); - else - mutex_unlock(&session->s_mutex); } /* @@ -4203,8 +4130,7 @@ done: mutex_unlock(&session->s_mutex); done_unlocked: ceph_put_string(extra_info.pool_ns); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); return; flush_cap_releases: @@ -4246,8 +4172,7 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) spin_unlock(&mdsc->cap_delay_lock); dout("check_delayed_caps on %p\n", inode); ceph_check_caps(ci, 0, NULL); - /* avoid calling iput_final() in tick thread */ - ceph_async_iput(inode); + iput(inode); spin_lock(&mdsc->cap_delay_lock); } } diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 425f3356332a..38b78b45811f 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -127,7 +127,7 @@ static int mdsc_show(struct seq_file *s, void *p) return 0; } -#define CEPH_METRIC_SHOW(name, total, avg, min, max, sq) { \ +#define CEPH_LAT_METRIC_SHOW(name, total, avg, min, max, sq) { \ s64 _total, _avg, _min, _max, _sq, _st; \ _avg = ktime_to_us(avg); \ _min = ktime_to_us(min == KTIME_MAX ? 0 : min); \ @@ -140,6 +140,12 @@ static int mdsc_show(struct seq_file *s, void *p) name, total, _avg, _min, _max, _st); \ } +#define CEPH_SZ_METRIC_SHOW(name, total, avg, min, max, sum) { \ + u64 _min = min == U64_MAX ? 0 : min; \ + seq_printf(s, "%-14s%-12lld%-16llu%-16llu%-16llu%llu\n", \ + name, total, avg, _min, max, sum); \ +} + static int metric_show(struct seq_file *s, void *p) { struct ceph_fs_client *fsc = s->private; @@ -147,6 +153,7 @@ static int metric_show(struct seq_file *s, void *p) struct ceph_client_metric *m = &mdsc->metric; int nr_caps = 0; s64 total, sum, avg, min, max, sq; + u64 sum_sz, avg_sz, min_sz, max_sz; sum = percpu_counter_sum(&m->total_inodes); seq_printf(s, "item total\n"); @@ -170,7 +177,7 @@ static int metric_show(struct seq_file *s, void *p) max = m->read_latency_max; sq = m->read_latency_sq_sum; spin_unlock(&m->read_metric_lock); - CEPH_METRIC_SHOW("read", total, avg, min, max, sq); + CEPH_LAT_METRIC_SHOW("read", total, avg, min, max, sq); spin_lock(&m->write_metric_lock); total = m->total_writes; @@ -180,7 +187,7 @@ static int metric_show(struct seq_file *s, void *p) max = m->write_latency_max; sq = m->write_latency_sq_sum; spin_unlock(&m->write_metric_lock); - CEPH_METRIC_SHOW("write", total, avg, min, max, sq); + CEPH_LAT_METRIC_SHOW("write", total, avg, min, max, sq); spin_lock(&m->metadata_metric_lock); total = m->total_metadatas; @@ -190,7 +197,29 @@ static int metric_show(struct seq_file *s, void *p) max = m->metadata_latency_max; sq = m->metadata_latency_sq_sum; spin_unlock(&m->metadata_metric_lock); - CEPH_METRIC_SHOW("metadata", total, avg, min, max, sq); + CEPH_LAT_METRIC_SHOW("metadata", total, avg, min, max, sq); + + seq_printf(s, "\n"); + seq_printf(s, "item total avg_sz(bytes) min_sz(bytes) max_sz(bytes) total_sz(bytes)\n"); + seq_printf(s, "----------------------------------------------------------------------------------------\n"); + + spin_lock(&m->read_metric_lock); + total = m->total_reads; + sum_sz = m->read_size_sum; + avg_sz = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum_sz, total) : 0; + min_sz = m->read_size_min; + max_sz = m->read_size_max; + spin_unlock(&m->read_metric_lock); + CEPH_SZ_METRIC_SHOW("read", total, avg_sz, min_sz, max_sz, sum_sz); + + spin_lock(&m->write_metric_lock); + total = m->total_writes; + sum_sz = m->write_size_sum; + avg_sz = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum_sz, total) : 0; + min_sz = m->write_size_min; + max_sz = m->write_size_max; + spin_unlock(&m->write_metric_lock); + CEPH_SZ_METRIC_SHOW("write", total, avg_sz, min_sz, max_sz, sum_sz); seq_printf(s, "\n"); seq_printf(s, "item total miss hit\n"); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 9ba79b6531fb..133dbd9338e7 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -788,6 +788,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, mask |= CEPH_CAP_XATTR_SHARED; req->r_args.getattr.mask = cpu_to_le32(mask); + ihold(dir); req->r_parent = dir; set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); err = ceph_mdsc_do_request(mdsc, NULL, req); @@ -868,6 +869,7 @@ static int ceph_mknod(struct user_namespace *mnt_userns, struct inode *dir, req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_args.mknod.mode = cpu_to_le32(mode); req->r_args.mknod.rdev = cpu_to_le32(rdev); @@ -929,6 +931,8 @@ static int ceph_symlink(struct user_namespace *mnt_userns, struct inode *dir, goto out; } req->r_parent = dir; + ihold(dir); + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_dentry = dget(dentry); req->r_num_caps = 2; @@ -993,6 +997,7 @@ static int ceph_mkdir(struct user_namespace *mnt_userns, struct inode *dir, req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_args.mkdir.mode = cpu_to_le32(mode); req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL; @@ -1037,6 +1042,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir, req->r_num_caps = 2; req->r_old_dentry = dget(old_dentry); req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_unless = CEPH_CAP_FILE_EXCL; @@ -1158,6 +1164,7 @@ retry: req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_unless = CEPH_CAP_FILE_EXCL; req->r_inode_drop = ceph_drop_caps_for_unlink(inode); @@ -1232,6 +1239,7 @@ static int ceph_rename(struct user_namespace *mnt_userns, struct inode *old_dir, req->r_old_dentry = dget(old_dentry); req->r_old_dentry_dir = old_dir; req->r_parent = new_dir; + ihold(new_dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; @@ -1548,10 +1556,8 @@ static bool __dentry_lease_is_valid(struct ceph_dentry_info *di) u32 gen; unsigned long ttl; - spin_lock(&session->s_gen_ttl_lock); - gen = session->s_cap_gen; + gen = atomic_read(&session->s_cap_gen); ttl = session->s_cap_ttl; - spin_unlock(&session->s_gen_ttl_lock); if (di->lease_gen == gen && time_before(jiffies, ttl) && @@ -1730,6 +1736,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED; if (ceph_security_xattr_wanted(dir)) @@ -1809,8 +1816,7 @@ static void ceph_d_release(struct dentry *dentry) dentry->d_fsdata = NULL; spin_unlock(&dentry->d_lock); - if (di->lease_session) - ceph_put_mds_session(di->lease_session); + ceph_put_mds_session(di->lease_session); kmem_cache_free(ceph_dentry_cachep, di); } diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 65540a4429b2..1d65934c1262 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -542,6 +542,7 @@ static int ceph_get_name(struct dentry *parent, char *name, ihold(inode); req->r_ino2 = ceph_vino(d_inode(parent)); req->r_parent = d_inode(parent); + ihold(req->r_parent); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index d51af3698032..d1755ac1d964 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -706,6 +706,7 @@ retry: mask |= CEPH_CAP_XATTR_SHARED; req->r_args.open.mask = cpu_to_le32(mask); req->r_parent = dir; + ihold(dir); if (flags & O_CREAT) { struct ceph_file_layout lo; @@ -903,7 +904,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to, ceph_update_read_metrics(&fsc->mdsc->metric, req->r_start_latency, req->r_end_latency, - ret); + len, ret); ceph_osdc_put_request(req); @@ -1035,12 +1036,12 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) struct ceph_aio_request *aio_req = req->r_priv; struct ceph_osd_data *osd_data = osd_req_op_extent_osd_data(req, 0); struct ceph_client_metric *metric = &ceph_sb_to_mdsc(inode->i_sb)->metric; + unsigned int len = osd_data->bvec_pos.iter.bi_size; BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_BVECS); BUG_ON(!osd_data->num_bvecs); - dout("ceph_aio_complete_req %p rc %d bytes %u\n", - inode, rc, osd_data->bvec_pos.iter.bi_size); + dout("ceph_aio_complete_req %p rc %d bytes %u\n", inode, rc, len); if (rc == -EOLDSNAPC) { struct ceph_aio_work *aio_work; @@ -1058,9 +1059,9 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } else if (!aio_req->write) { if (rc == -ENOENT) rc = 0; - if (rc >= 0 && osd_data->bvec_pos.iter.bi_size > rc) { + if (rc >= 0 && len > rc) { struct iov_iter i; - int zlen = osd_data->bvec_pos.iter.bi_size - rc; + int zlen = len - rc; /* * If read is satisfied by single OSD request, @@ -1077,8 +1078,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs, - osd_data->num_bvecs, - osd_data->bvec_pos.iter.bi_size); + osd_data->num_bvecs, len); iov_iter_advance(&i, rc); iov_iter_zero(zlen, &i); } @@ -1088,10 +1088,10 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) if (req->r_start_latency) { if (aio_req->write) ceph_update_write_metrics(metric, req->r_start_latency, - req->r_end_latency, rc); + req->r_end_latency, len, rc); else ceph_update_read_metrics(metric, req->r_start_latency, - req->r_end_latency, rc); + req->r_end_latency, len, rc); } put_bvecs(osd_data->bvec_pos.bvecs, osd_data->num_bvecs, @@ -1299,10 +1299,10 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, if (write) ceph_update_write_metrics(metric, req->r_start_latency, - req->r_end_latency, ret); + req->r_end_latency, len, ret); else ceph_update_read_metrics(metric, req->r_start_latency, - req->r_end_latency, ret); + req->r_end_latency, len, ret); size = i_size_read(inode); if (!write) { @@ -1476,7 +1476,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos, ret = ceph_osdc_wait_request(&fsc->client->osdc, req); ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, ret); + req->r_end_latency, len, ret); out: ceph_osdc_put_request(req); if (ret != 0) { diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index df0c8a724609..1bd2cc015913 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1124,7 +1124,7 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry, return; } - if (di->lease_gen == session->s_cap_gen && + if (di->lease_gen == atomic_read(&session->s_cap_gen) && time_before(ttl, di->time)) return; /* we already have a newer lease. */ @@ -1135,7 +1135,7 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry, if (!di->lease_session) di->lease_session = ceph_get_mds_session(session); - di->lease_gen = session->s_cap_gen; + di->lease_gen = atomic_read(&session->s_cap_gen); di->lease_seq = le32_to_cpu(lease->seq); di->lease_renew_after = half_ttl; di->lease_renew_from = 0; @@ -1154,8 +1154,7 @@ static inline void update_dentry_lease(struct inode *dir, struct dentry *dentry, __update_dentry_lease(dir, dentry, lease, session, from_time, &old_lease_session); spin_unlock(&dentry->d_lock); - if (old_lease_session) - ceph_put_mds_session(old_lease_session); + ceph_put_mds_session(old_lease_session); } /* @@ -1200,8 +1199,7 @@ static void update_dentry_lease_careful(struct dentry *dentry, from_time, &old_lease_session); out_unlock: spin_unlock(&dentry->d_lock); - if (old_lease_session) - ceph_put_mds_session(old_lease_session); + ceph_put_mds_session(old_lease_session); } /* @@ -1568,8 +1566,7 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req, unlock_new_inode(in); } - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(in); + iput(in); } return err; @@ -1766,13 +1763,11 @@ retry_lookup: if (ret < 0) { pr_err("ceph_fill_inode badness on %p\n", in); if (d_really_is_negative(dn)) { - /* avoid calling iput_final() in mds - * dispatch threads */ if (in->i_state & I_NEW) { ihold(in); discard_new_inode(in); } - ceph_async_iput(in); + iput(in); } d_drop(dn); err = ret; @@ -1785,7 +1780,7 @@ retry_lookup: if (ceph_security_xattr_deadlock(in)) { dout(" skip splicing dn %p to inode %p" " (security xattr deadlock)\n", dn, in); - ceph_async_iput(in); + iput(in); skipped++; goto next_item; } @@ -1836,25 +1831,6 @@ bool ceph_inode_set_size(struct inode *inode, loff_t size) return ret; } -/* - * Put reference to inode, but avoid calling iput_final() in current thread. - * iput_final() may wait for reahahead pages. The wait can cause deadlock in - * some contexts. - */ -void ceph_async_iput(struct inode *inode) -{ - if (!inode) - return; - for (;;) { - if (atomic_add_unless(&inode->i_count, -1, 1)) - break; - if (queue_work(ceph_inode_to_client(inode)->inode_wq, - &ceph_inode(inode)->i_work)) - break; - /* queue work failed, i_count must be at least 2 */ - } -} - void ceph_queue_inode_work(struct inode *inode, int work_bit) { struct ceph_fs_client *fsc = ceph_inode_to_client(inode); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index e5af591d3bd4..a818213c972f 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -664,6 +664,9 @@ struct ceph_mds_session *ceph_get_mds_session(struct ceph_mds_session *s) void ceph_put_mds_session(struct ceph_mds_session *s) { + if (IS_ERR_OR_NULL(s)) + return; + dout("mdsc put_session %p %d -> %d\n", s, refcount_read(&s->s_ref), refcount_read(&s->s_ref)-1); if (refcount_dec_and_test(&s->s_ref)) { @@ -746,8 +749,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr); - spin_lock_init(&s->s_gen_ttl_lock); - s->s_cap_gen = 1; + atomic_set(&s->s_cap_gen, 1); s->s_cap_ttl = jiffies - 1; spin_lock_init(&s->s_cap_lock); @@ -822,14 +824,13 @@ void ceph_mdsc_release_request(struct kref *kref) ceph_msg_put(req->r_reply); if (req->r_inode) { ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(req->r_inode); + iput(req->r_inode); } if (req->r_parent) { ceph_put_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN); - ceph_async_iput(req->r_parent); + iput(req->r_parent); } - ceph_async_iput(req->r_target_inode); + iput(req->r_target_inode); if (req->r_dentry) dput(req->r_dentry); if (req->r_old_dentry) @@ -843,7 +844,7 @@ void ceph_mdsc_release_request(struct kref *kref) */ ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir), CEPH_CAP_PIN); - ceph_async_iput(req->r_old_dentry_dir); + iput(req->r_old_dentry_dir); } kfree(req->r_path1); kfree(req->r_path2); @@ -958,8 +959,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc, } if (req->r_unsafe_dir) { - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(req->r_unsafe_dir); + iput(req->r_unsafe_dir); req->r_unsafe_dir = NULL; } @@ -1130,7 +1130,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, cap = rb_entry(rb_first(&ci->i_caps), struct ceph_cap, ci_node); if (!cap) { spin_unlock(&ci->i_ceph_lock); - ceph_async_iput(inode); + iput(inode); goto random; } mds = cap->session->s_mds; @@ -1139,9 +1139,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, cap == ci->i_auth_cap ? "auth " : "", cap); spin_unlock(&ci->i_ceph_lock); out: - /* avoid calling iput_final() while holding mdsc->mutex or - * in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); return mds; random: @@ -1438,8 +1436,7 @@ static void __open_export_target_sessions(struct ceph_mds_client *mdsc, for (i = 0; i < mi->num_export_targets; i++) { ts = __open_export_target_session(mdsc, mi->export_targets[i]); - if (!IS_ERR(ts)) - ceph_put_mds_session(ts); + ceph_put_mds_session(ts); } } @@ -1545,9 +1542,7 @@ int ceph_iterate_session_caps(struct ceph_mds_session *session, spin_unlock(&session->s_cap_lock); if (last_inode) { - /* avoid calling iput_final() while holding - * s_mutex or in mds dispatch threads */ - ceph_async_iput(last_inode); + iput(last_inode); last_inode = NULL; } if (old_cap) { @@ -1581,7 +1576,7 @@ out: session->s_cap_iterator = NULL; spin_unlock(&session->s_cap_lock); - ceph_async_iput(last_inode); + iput(last_inode); if (old_cap) ceph_put_cap(session->s_mdsc, old_cap); @@ -1721,8 +1716,7 @@ static void remove_session_caps(struct ceph_mds_session *session) spin_unlock(&session->s_cap_lock); inode = ceph_find_inode(sb, vino); - /* avoid calling iput_final() while holding s_mutex */ - ceph_async_iput(inode); + iput(inode); spin_lock(&session->s_cap_lock); } @@ -1761,7 +1755,7 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap, ci->i_requested_max_size = 0; spin_unlock(&ci->i_ceph_lock); } else if (ev == RENEWCAPS) { - if (cap->cap_gen < cap->session->s_cap_gen) { + if (cap->cap_gen < atomic_read(&cap->session->s_cap_gen)) { /* mds did not re-issue stale cap */ spin_lock(&ci->i_ceph_lock); cap->issued = cap->implemented = CEPH_CAP_PIN; @@ -2988,7 +2982,6 @@ int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc, struct inode *dir, ceph_take_cap_refs(ci, CEPH_CAP_PIN, false); __ceph_touch_fmode(ci, mdsc, fmode); spin_unlock(&ci->i_ceph_lock); - ihold(req->r_parent); } if (req->r_old_dentry_dir) ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), @@ -3499,10 +3492,8 @@ static void handle_session(struct ceph_mds_session *session, case CEPH_SESSION_STALE: pr_info("mds%d caps went stale, renewing\n", session->s_mds); - spin_lock(&session->s_gen_ttl_lock); - session->s_cap_gen++; + atomic_inc(&session->s_cap_gen); session->s_cap_ttl = jiffies - 1; - spin_unlock(&session->s_gen_ttl_lock); send_renew_caps(mdsc, session); break; @@ -3771,7 +3762,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, cap->seq = 0; /* reset cap seq */ cap->issue_seq = 0; /* and issue_seq */ cap->mseq = 0; /* and migrate_seq */ - cap->cap_gen = cap->session->s_cap_gen; + cap->cap_gen = atomic_read(&cap->session->s_cap_gen); /* These are lost when the session goes away */ if (S_ISDIR(inode->i_mode)) { @@ -4011,9 +4002,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, dout("session %p state %s\n", session, ceph_session_state_name(session->s_state)); - spin_lock(&session->s_gen_ttl_lock); - session->s_cap_gen++; - spin_unlock(&session->s_gen_ttl_lock); + atomic_inc(&session->s_cap_gen); spin_lock(&session->s_cap_lock); /* don't know if session is readonly */ @@ -4344,7 +4333,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, case CEPH_MDS_LEASE_RENEW: if (di->lease_session == session && - di->lease_gen == session->s_cap_gen && + di->lease_gen == atomic_read(&session->s_cap_gen) && di->lease_renew_from && di->lease_renew_after == 0) { unsigned long duration = @@ -4372,8 +4361,7 @@ release: out: mutex_unlock(&session->s_mutex); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); return; bad: diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 15c11a0f2caf..20e42d8b66c6 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -186,10 +186,8 @@ struct ceph_mds_session { struct ceph_auth_handshake s_auth; - /* protected by s_gen_ttl_lock */ - spinlock_t s_gen_ttl_lock; - u32 s_cap_gen; /* inc each time we get mds stale msg */ - unsigned long s_cap_ttl; /* when session caps expire */ + atomic_t s_cap_gen; /* inc each time we get mds stale msg */ + unsigned long s_cap_ttl; /* when session caps expire. protected by s_mutex */ /* protected by s_cap_lock */ spinlock_t s_cap_lock; diff --git a/fs/ceph/metric.c b/fs/ceph/metric.c index 28b6b42ad677..5ac151eb0d49 100644 --- a/fs/ceph/metric.c +++ b/fs/ceph/metric.c @@ -20,8 +20,11 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, struct ceph_opened_files *files; struct ceph_pinned_icaps *icaps; struct ceph_opened_inodes *inodes; + struct ceph_read_io_size *rsize; + struct ceph_write_io_size *wsize; struct ceph_client_metric *m = &mdsc->metric; u64 nr_caps = atomic64_read(&m->total_caps); + u32 header_len = sizeof(struct ceph_metric_header); struct ceph_msg *msg; struct timespec64 ts; s64 sum; @@ -30,7 +33,8 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, len = sizeof(*head) + sizeof(*cap) + sizeof(*read) + sizeof(*write) + sizeof(*meta) + sizeof(*dlease) + sizeof(*files) - + sizeof(*icaps) + sizeof(*inodes); + + sizeof(*icaps) + sizeof(*inodes) + sizeof(*rsize) + + sizeof(*wsize); msg = ceph_msg_new(CEPH_MSG_CLIENT_METRICS, len, GFP_NOFS, true); if (!msg) { @@ -43,10 +47,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the cap metric */ cap = (struct ceph_metric_cap *)(head + 1); - cap->type = cpu_to_le32(CLIENT_METRIC_TYPE_CAP_INFO); - cap->ver = 1; - cap->compat = 1; - cap->data_len = cpu_to_le32(sizeof(*cap) - 10); + cap->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_CAP_INFO); + cap->header.ver = 1; + cap->header.compat = 1; + cap->header.data_len = cpu_to_le32(sizeof(*cap) - header_len); cap->hit = cpu_to_le64(percpu_counter_sum(&m->i_caps_hit)); cap->mis = cpu_to_le64(percpu_counter_sum(&m->i_caps_mis)); cap->total = cpu_to_le64(nr_caps); @@ -54,10 +58,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the read latency metric */ read = (struct ceph_metric_read_latency *)(cap + 1); - read->type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_LATENCY); - read->ver = 1; - read->compat = 1; - read->data_len = cpu_to_le32(sizeof(*read) - 10); + read->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_LATENCY); + read->header.ver = 1; + read->header.compat = 1; + read->header.data_len = cpu_to_le32(sizeof(*read) - header_len); sum = m->read_latency_sum; jiffies_to_timespec64(sum, &ts); read->sec = cpu_to_le32(ts.tv_sec); @@ -66,10 +70,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the write latency metric */ write = (struct ceph_metric_write_latency *)(read + 1); - write->type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_LATENCY); - write->ver = 1; - write->compat = 1; - write->data_len = cpu_to_le32(sizeof(*write) - 10); + write->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_LATENCY); + write->header.ver = 1; + write->header.compat = 1; + write->header.data_len = cpu_to_le32(sizeof(*write) - header_len); sum = m->write_latency_sum; jiffies_to_timespec64(sum, &ts); write->sec = cpu_to_le32(ts.tv_sec); @@ -78,10 +82,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the metadata latency metric */ meta = (struct ceph_metric_metadata_latency *)(write + 1); - meta->type = cpu_to_le32(CLIENT_METRIC_TYPE_METADATA_LATENCY); - meta->ver = 1; - meta->compat = 1; - meta->data_len = cpu_to_le32(sizeof(*meta) - 10); + meta->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_METADATA_LATENCY); + meta->header.ver = 1; + meta->header.compat = 1; + meta->header.data_len = cpu_to_le32(sizeof(*meta) - header_len); sum = m->metadata_latency_sum; jiffies_to_timespec64(sum, &ts); meta->sec = cpu_to_le32(ts.tv_sec); @@ -90,10 +94,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the dentry lease metric */ dlease = (struct ceph_metric_dlease *)(meta + 1); - dlease->type = cpu_to_le32(CLIENT_METRIC_TYPE_DENTRY_LEASE); - dlease->ver = 1; - dlease->compat = 1; - dlease->data_len = cpu_to_le32(sizeof(*dlease) - 10); + dlease->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_DENTRY_LEASE); + dlease->header.ver = 1; + dlease->header.compat = 1; + dlease->header.data_len = cpu_to_le32(sizeof(*dlease) - header_len); dlease->hit = cpu_to_le64(percpu_counter_sum(&m->d_lease_hit)); dlease->mis = cpu_to_le64(percpu_counter_sum(&m->d_lease_mis)); dlease->total = cpu_to_le64(atomic64_read(&m->total_dentries)); @@ -103,34 +107,54 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the opened files metric */ files = (struct ceph_opened_files *)(dlease + 1); - files->type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_FILES); - files->ver = 1; - files->compat = 1; - files->data_len = cpu_to_le32(sizeof(*files) - 10); + files->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_FILES); + files->header.ver = 1; + files->header.compat = 1; + files->header.data_len = cpu_to_le32(sizeof(*files) - header_len); files->opened_files = cpu_to_le64(atomic64_read(&m->opened_files)); files->total = cpu_to_le64(sum); items++; /* encode the pinned icaps metric */ icaps = (struct ceph_pinned_icaps *)(files + 1); - icaps->type = cpu_to_le32(CLIENT_METRIC_TYPE_PINNED_ICAPS); - icaps->ver = 1; - icaps->compat = 1; - icaps->data_len = cpu_to_le32(sizeof(*icaps) - 10); + icaps->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_PINNED_ICAPS); + icaps->header.ver = 1; + icaps->header.compat = 1; + icaps->header.data_len = cpu_to_le32(sizeof(*icaps) - header_len); icaps->pinned_icaps = cpu_to_le64(nr_caps); icaps->total = cpu_to_le64(sum); items++; /* encode the opened inodes metric */ inodes = (struct ceph_opened_inodes *)(icaps + 1); - inodes->type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_INODES); - inodes->ver = 1; - inodes->compat = 1; - inodes->data_len = cpu_to_le32(sizeof(*inodes) - 10); + inodes->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_INODES); + inodes->header.ver = 1; + inodes->header.compat = 1; + inodes->header.data_len = cpu_to_le32(sizeof(*inodes) - header_len); inodes->opened_inodes = cpu_to_le64(percpu_counter_sum(&m->opened_inodes)); inodes->total = cpu_to_le64(sum); items++; + /* encode the read io size metric */ + rsize = (struct ceph_read_io_size *)(inodes + 1); + rsize->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_IO_SIZES); + rsize->header.ver = 1; + rsize->header.compat = 1; + rsize->header.data_len = cpu_to_le32(sizeof(*rsize) - header_len); + rsize->total_ops = cpu_to_le64(m->total_reads); + rsize->total_size = cpu_to_le64(m->read_size_sum); + items++; + + /* encode the write io size metric */ + wsize = (struct ceph_write_io_size *)(rsize + 1); + wsize->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_IO_SIZES); + wsize->header.ver = 1; + wsize->header.compat = 1; + wsize->header.data_len = cpu_to_le32(sizeof(*wsize) - header_len); + wsize->total_ops = cpu_to_le64(m->total_writes); + wsize->total_size = cpu_to_le64(m->write_size_sum); + items++; + put_unaligned_le32(items, &head->num); msg->front.iov_len = len; msg->hdr.version = cpu_to_le16(1); @@ -225,6 +249,9 @@ int ceph_metric_init(struct ceph_client_metric *m) m->read_latency_max = 0; m->total_reads = 0; m->read_latency_sum = 0; + m->read_size_min = U64_MAX; + m->read_size_max = 0; + m->read_size_sum = 0; spin_lock_init(&m->write_metric_lock); m->write_latency_sq_sum = 0; @@ -232,6 +259,9 @@ int ceph_metric_init(struct ceph_client_metric *m) m->write_latency_max = 0; m->total_writes = 0; m->write_latency_sum = 0; + m->write_size_min = U64_MAX; + m->write_size_max = 0; + m->write_size_sum = 0; spin_lock_init(&m->metadata_metric_lock); m->metadata_latency_sq_sum = 0; @@ -281,23 +311,21 @@ void ceph_metric_destroy(struct ceph_client_metric *m) cancel_delayed_work_sync(&m->delayed_work); - if (m->session) - ceph_put_mds_session(m->session); + ceph_put_mds_session(m->session); } -static inline void __update_latency(ktime_t *totalp, ktime_t *lsump, - ktime_t *min, ktime_t *max, - ktime_t *sq_sump, ktime_t lat) +#define METRIC_UPDATE_MIN_MAX(min, max, new) \ +{ \ + if (unlikely(new < min)) \ + min = new; \ + if (unlikely(new > max)) \ + max = new; \ +} + +static inline void __update_stdev(ktime_t total, ktime_t lsum, + ktime_t *sq_sump, ktime_t lat) { - ktime_t total, avg, sq, lsum; - - total = ++(*totalp); - lsum = (*lsump += lat); - - if (unlikely(lat < *min)) - *min = lat; - if (unlikely(lat > *max)) - *max = lat; + ktime_t avg, sq; if (unlikely(total == 1)) return; @@ -312,33 +340,51 @@ static inline void __update_latency(ktime_t *totalp, ktime_t *lsump, void ceph_update_read_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc) + unsigned int size, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc < 0 && rc != -ENOENT && rc != -ETIMEDOUT)) return; spin_lock(&m->read_metric_lock); - __update_latency(&m->total_reads, &m->read_latency_sum, - &m->read_latency_min, &m->read_latency_max, - &m->read_latency_sq_sum, lat); + total = ++m->total_reads; + m->read_size_sum += size; + m->read_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->read_size_min, + m->read_size_max, + size); + METRIC_UPDATE_MIN_MAX(m->read_latency_min, + m->read_latency_max, + lat); + __update_stdev(total, m->read_latency_sum, + &m->read_latency_sq_sum, lat); spin_unlock(&m->read_metric_lock); } void ceph_update_write_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc) + unsigned int size, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc && rc != -ETIMEDOUT)) return; spin_lock(&m->write_metric_lock); - __update_latency(&m->total_writes, &m->write_latency_sum, - &m->write_latency_min, &m->write_latency_max, - &m->write_latency_sq_sum, lat); + total = ++m->total_writes; + m->write_size_sum += size; + m->write_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->write_size_min, + m->write_size_max, + size); + METRIC_UPDATE_MIN_MAX(m->write_latency_min, + m->write_latency_max, + lat); + __update_stdev(total, m->write_latency_sum, + &m->write_latency_sq_sum, lat); spin_unlock(&m->write_metric_lock); } @@ -347,13 +393,18 @@ void ceph_update_metadata_metrics(struct ceph_client_metric *m, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc && rc != -ENOENT)) return; spin_lock(&m->metadata_metric_lock); - __update_latency(&m->total_metadatas, &m->metadata_latency_sum, - &m->metadata_latency_min, &m->metadata_latency_max, - &m->metadata_latency_sq_sum, lat); + total = ++m->total_metadatas; + m->metadata_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->metadata_latency_min, + m->metadata_latency_max, + lat); + __update_stdev(total, m->metadata_latency_sum, + &m->metadata_latency_sq_sum, lat); spin_unlock(&m->metadata_metric_lock); } diff --git a/fs/ceph/metric.h b/fs/ceph/metric.h index e984eb2bb14b..0133955a3c6a 100644 --- a/fs/ceph/metric.h +++ b/fs/ceph/metric.h @@ -17,8 +17,10 @@ enum ceph_metric_type { CLIENT_METRIC_TYPE_OPENED_FILES, CLIENT_METRIC_TYPE_PINNED_ICAPS, CLIENT_METRIC_TYPE_OPENED_INODES, + CLIENT_METRIC_TYPE_READ_IO_SIZES, + CLIENT_METRIC_TYPE_WRITE_IO_SIZES, - CLIENT_METRIC_TYPE_MAX = CLIENT_METRIC_TYPE_OPENED_INODES, + CLIENT_METRIC_TYPE_MAX = CLIENT_METRIC_TYPE_WRITE_IO_SIZES, }; /* @@ -34,18 +36,22 @@ enum ceph_metric_type { CLIENT_METRIC_TYPE_OPENED_FILES, \ CLIENT_METRIC_TYPE_PINNED_ICAPS, \ CLIENT_METRIC_TYPE_OPENED_INODES, \ + CLIENT_METRIC_TYPE_READ_IO_SIZES, \ + CLIENT_METRIC_TYPE_WRITE_IO_SIZES, \ \ CLIENT_METRIC_TYPE_MAX, \ } -/* metric caps header */ -struct ceph_metric_cap { +struct ceph_metric_header { __le32 type; /* ceph metric type */ - __u8 ver; __u8 compat; - __le32 data_len; /* length of sizeof(hit + mis + total) */ +} __packed; + +/* metric caps header */ +struct ceph_metric_cap { + struct ceph_metric_header header; __le64 hit; __le64 mis; __le64 total; @@ -53,48 +59,28 @@ struct ceph_metric_cap { /* metric read latency header */ struct ceph_metric_read_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; /* metric write latency header */ struct ceph_metric_write_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; /* metric metadata latency header */ struct ceph_metric_metadata_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; /* metric dentry lease header */ struct ceph_metric_dlease { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(hit + mis + total) */ + struct ceph_metric_header header; __le64 hit; __le64 mis; __le64 total; @@ -102,40 +88,39 @@ struct ceph_metric_dlease { /* metric opened files header */ struct ceph_opened_files { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(opened_files + total) */ + struct ceph_metric_header header; __le64 opened_files; __le64 total; } __packed; /* metric pinned i_caps header */ struct ceph_pinned_icaps { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(pinned_icaps + total) */ + struct ceph_metric_header header; __le64 pinned_icaps; __le64 total; } __packed; /* metric opened inodes header */ struct ceph_opened_inodes { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(opened_inodes + total) */ + struct ceph_metric_header header; __le64 opened_inodes; __le64 total; } __packed; +/* metric read io size header */ +struct ceph_read_io_size { + struct ceph_metric_header header; + __le64 total_ops; + __le64 total_size; +} __packed; + +/* metric write io size header */ +struct ceph_write_io_size { + struct ceph_metric_header header; + __le64 total_ops; + __le64 total_size; +} __packed; + struct ceph_metric_head { __le32 num; /* the number of metrics that will be sent */ } __packed; @@ -152,6 +137,9 @@ struct ceph_client_metric { spinlock_t read_metric_lock; u64 total_reads; + u64 read_size_sum; + u64 read_size_min; + u64 read_size_max; ktime_t read_latency_sum; ktime_t read_latency_sq_sum; ktime_t read_latency_min; @@ -159,6 +147,9 @@ struct ceph_client_metric { spinlock_t write_metric_lock; u64 total_writes; + u64 write_size_sum; + u64 write_size_min; + u64 write_size_max; ktime_t write_latency_sum; ktime_t write_latency_sq_sum; ktime_t write_latency_min; @@ -206,10 +197,10 @@ static inline void ceph_update_cap_mis(struct ceph_client_metric *m) extern void ceph_update_read_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc); + unsigned int size, int rc); extern void ceph_update_write_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc); + unsigned int size, int rc); extern void ceph_update_metadata_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, int rc); diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 4e32c9600ecc..620c691af40e 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -74,8 +74,7 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc, le64_to_cpu(h->max_files)); spin_unlock(&ci->i_ceph_lock); - /* avoid calling iput_final() in dispatch thread */ - ceph_async_iput(inode); + iput(inode); } static struct ceph_quotarealm_inode * @@ -247,8 +246,7 @@ restart: ci = ceph_inode(in); has_quota = __ceph_has_any_quota(ci); - /* avoid calling iput_final() while holding mdsc->snap_rwsem */ - ceph_async_iput(in); + iput(in); next = realm->parent; if (has_quota || !next) @@ -383,8 +381,7 @@ restart: pr_warn("Invalid quota check op (%d)\n", op); exceeded = true; /* Just break the loop */ } - /* avoid calling iput_final() while holding mdsc->snap_rwsem */ - ceph_async_iput(in); + iput(in); next = realm->parent; if (exceeded || !next) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 4ce18055d931..4ac0606dcbd4 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -60,11 +60,13 @@ /* * increase ref count for the realm * - * caller must hold snap_rwsem for write. + * caller must hold snap_rwsem. */ void ceph_get_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { + lockdep_assert_held(&mdsc->snap_rwsem); + dout("get_realm %p %d -> %d\n", realm, atomic_read(&realm->nref), atomic_read(&realm->nref)+1); /* @@ -113,6 +115,8 @@ static struct ceph_snap_realm *ceph_create_snap_realm( { struct ceph_snap_realm *realm; + lockdep_assert_held_write(&mdsc->snap_rwsem); + realm = kzalloc(sizeof(*realm), GFP_NOFS); if (!realm) return ERR_PTR(-ENOMEM); @@ -135,7 +139,7 @@ static struct ceph_snap_realm *ceph_create_snap_realm( /* * lookup the realm rooted at @ino. * - * caller must hold snap_rwsem for write. + * caller must hold snap_rwsem. */ static struct ceph_snap_realm *__lookup_snap_realm(struct ceph_mds_client *mdsc, u64 ino) @@ -143,6 +147,8 @@ static struct ceph_snap_realm *__lookup_snap_realm(struct ceph_mds_client *mdsc, struct rb_node *n = mdsc->snap_realms.rb_node; struct ceph_snap_realm *r; + lockdep_assert_held(&mdsc->snap_rwsem); + while (n) { r = rb_entry(n, struct ceph_snap_realm, node); if (ino < r->ino) @@ -176,6 +182,8 @@ static void __put_snap_realm(struct ceph_mds_client *mdsc, static void __destroy_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { + lockdep_assert_held_write(&mdsc->snap_rwsem); + dout("__destroy_snap_realm %p %llx\n", realm, realm->ino); rb_erase(&realm->node, &mdsc->snap_realms); @@ -198,6 +206,8 @@ static void __destroy_snap_realm(struct ceph_mds_client *mdsc, static void __put_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { + lockdep_assert_held_write(&mdsc->snap_rwsem); + dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, atomic_read(&realm->nref), atomic_read(&realm->nref)-1); if (atomic_dec_and_test(&realm->nref)) @@ -236,6 +246,8 @@ static void __cleanup_empty_realms(struct ceph_mds_client *mdsc) { struct ceph_snap_realm *realm; + lockdep_assert_held_write(&mdsc->snap_rwsem); + spin_lock(&mdsc->snap_empty_lock); while (!list_empty(&mdsc->snap_empty)) { realm = list_first_entry(&mdsc->snap_empty, @@ -269,6 +281,8 @@ static int adjust_snap_realm_parent(struct ceph_mds_client *mdsc, { struct ceph_snap_realm *parent; + lockdep_assert_held_write(&mdsc->snap_rwsem); + if (realm->parent_ino == parentino) return 0; @@ -460,7 +474,7 @@ static bool has_new_snaps(struct ceph_snap_context *o, * Caller must hold snap_rwsem for read (i.e., the realm topology won't * change). */ -void ceph_queue_cap_snap(struct ceph_inode_info *ci) +static void ceph_queue_cap_snap(struct ceph_inode_info *ci) { struct inode *inode = &ci->vfs_inode; struct ceph_cap_snap *capsnap; @@ -663,15 +677,13 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) if (!inode) continue; spin_unlock(&realm->inodes_with_caps_lock); - /* avoid calling iput_final() while holding - * mdsc->snap_rwsem or in mds dispatch threads */ - ceph_async_iput(lastinode); + iput(lastinode); lastinode = inode; ceph_queue_cap_snap(ci); spin_lock(&realm->inodes_with_caps_lock); } spin_unlock(&realm->inodes_with_caps_lock); - ceph_async_iput(lastinode); + iput(lastinode); dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); } @@ -696,6 +708,8 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, int err = -ENOMEM; LIST_HEAD(dirty_realms); + lockdep_assert_held_write(&mdsc->snap_rwsem); + dout("update_snap_trace deletion=%d\n", deletion); more: ceph_decode_need(&p, e, sizeof(*ri), bad); @@ -791,7 +805,7 @@ more: return 0; bad: - err = -EINVAL; + err = -EIO; fail: if (realm && !IS_ERR(realm)) ceph_put_snap_realm(mdsc, realm); @@ -823,17 +837,12 @@ static void flush_snaps(struct ceph_mds_client *mdsc) ihold(inode); spin_unlock(&mdsc->snap_flush_lock); ceph_flush_snaps(ci, &session); - /* avoid calling iput_final() while holding - * session->s_mutex or in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); spin_lock(&mdsc->snap_flush_lock); } spin_unlock(&mdsc->snap_flush_lock); - if (session) { - mutex_unlock(&session->s_mutex); - ceph_put_mds_session(session); - } + ceph_put_mds_session(session); dout("flush_snaps done\n"); } @@ -969,14 +978,12 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, ceph_get_snap_realm(mdsc, realm); ceph_put_snap_realm(mdsc, oldrealm); - /* avoid calling iput_final() while holding - * mdsc->snap_rwsem or mds in dispatch threads */ - ceph_async_iput(inode); + iput(inode); continue; skip_inode: spin_unlock(&ci->i_ceph_lock); - ceph_async_iput(inode); + iput(inode); } /* we may have taken some of the old realm's children. */ diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 839e6b0239ee..6b6332a5c113 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -931,7 +931,6 @@ extern int ceph_update_snap_trace(struct ceph_mds_client *m, extern void ceph_handle_snap(struct ceph_mds_client *mdsc, struct ceph_mds_session *session, struct ceph_msg *msg); -extern void ceph_queue_cap_snap(struct ceph_inode_info *ci); extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci, struct ceph_cap_snap *capsnap); extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc); @@ -989,8 +988,6 @@ extern int ceph_inode_holds_cap(struct inode *inode, int mask); extern bool ceph_inode_set_size(struct inode *inode, loff_t size); extern void __ceph_do_pending_vmtruncate(struct inode *inode); -extern void ceph_async_iput(struct inode *inode); - void ceph_queue_inode_work(struct inode *inode, int work_bit); static inline void ceph_queue_vmtruncate(struct inode *inode) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ec57cdb1590f..57f91311fdaa 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -151,6 +151,9 @@ char *cifs_compose_mount_options(const char *sb_mountdata, return ERR_PTR(-EINVAL); if (ref) { + if (WARN_ON_ONCE(!ref->node_name || ref->path_consumed < 0)) + return ERR_PTR(-EINVAL); + if (strlen(fullpath) - ref->path_consumed) { prepath = fullpath + ref->path_consumed; /* skip initial delimiter */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9fb874dd8d24..64b71c4e2a9d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -65,6 +65,7 @@ bool lookupCacheEnabled = true; bool disable_legacy_dialects; /* false by default */ bool enable_gcm_256 = true; bool require_gcm_256; /* false by default */ +bool enable_negotiate_signing; /* false by default */ unsigned int global_secflags = CIFSSEC_DEF; /* unsigned int ntlmv2_support = 0; */ unsigned int sign_CIFS_PDUs = 1; @@ -104,6 +105,9 @@ MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encr module_param(require_gcm_256, bool, 0644); MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0"); +module_param(enable_negotiate_signing, bool, 0644); +MODULE_PARM_DESC(enable_negotiate_signing, "Enable negotiating packet signing algorithm with server. Default: n/N/0"); + module_param(disable_legacy_dialects, bool, 0644); MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be " "helpful to restrict the ability to " diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 177f3e7ab86d..d25a4099b32e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -153,5 +153,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "2.32" +#define CIFS_VERSION "2.33" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3100f8b66e60..3c2e117bb926 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -577,6 +577,7 @@ struct TCP_Server_Info { char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; struct smb_version_operations *ops; struct smb_version_values *vals; + /* updates to tcpStatus protected by GlobalMid_Lock */ enum statusEnum tcpStatus; /* what we think the status is */ char *hostname; /* hostname portion of UNC string */ struct socket *ssocket; @@ -666,9 +667,11 @@ struct TCP_Server_Info { unsigned int max_write; unsigned int min_offload; __le16 compress_algorithm; + __u16 signing_algorithm; __le16 cipher_type; /* save initital negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; + bool signing_negotiated; /* true if valid signing context rcvd from server */ bool posix_ext_supported; struct delayed_work reconnect; /* reconnect workqueue job */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ @@ -1785,7 +1788,7 @@ require use of the stronger protocol */ * list operations on pending_mid_q and oplockQ * updates to XID counters, multiplex id and SMB sequence numbers * list operations on global DnotifyReqList - * updates to ses->status + * updates to ses->status and TCP_Server_Info->tcpStatus * updates to server->CurrentMid * tcp_ses_lock protects: * list operations on tcp and SMB session lists @@ -1868,6 +1871,7 @@ extern unsigned int global_secflags; /* if on, session setup sent extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */ extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */ +extern bool enable_negotiate_signing; /* request use of faster (GMAC) signing if available */ extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ extern unsigned int CIFSMaxBufSize; /* max size not including hdr */ extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 0923f72d27e9..f6e235001358 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1785,6 +1785,7 @@ struct smb_com_transaction2_sfi_req { __u16 Fid; __le16 InformationLevel; __u16 Reserved4; + __u8 payload[]; } __attribute__((packed)); struct smb_com_transaction2_sfi_rsp { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 58ebec4d4413..f72e3b3dca69 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2537,8 +2537,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(param_offset); + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ parm_data = (struct cifs_posix_lock *) - (((char *) &pSMB->hdr.Protocol) + offset); + (((char *)pSMB) + offset + 4); parm_data->lock_type = cpu_to_le16(lock_type); if (waitFlag) { @@ -2767,7 +2768,8 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ + data_offset = (char *)(pSMB) + offset + 4; rename_info = (struct set_file_rename *) data_offset; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ @@ -2925,7 +2927,8 @@ createSymLinkRetry: InformationLevel) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ + data_offset = (char *)pSMB + offset + 4; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = cifsConvertToUTF16((__le16 *) data_offset, toName, @@ -3009,7 +3012,8 @@ createHardLinkRetry: InformationLevel) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ + data_offset = (char *)pSMB + offset + 4; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = cifsConvertToUTF16((__le16 *) data_offset, fromName, @@ -5626,9 +5630,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(param_offset); + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ parm_data = - (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) - + offset); + (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4); pSMB->DataOffset = cpu_to_le16(offset); parm_data->FileSize = cpu_to_le64(size); pSMB->Fid = cfile->fid.netfid; @@ -5761,7 +5765,8 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ + data_offset = (char *)(pSMB) + offset + 4; count = 1; pSMB->MaxParameterCount = cpu_to_le16(2); @@ -6062,9 +6067,8 @@ setPermsRetry: param_offset = offsetof(struct smb_com_transaction2_spi_req, InformationLevel) - 4; offset = param_offset + params; - data_offset = - (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + - offset); + /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ + data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4); memset(data_offset, 0, count); pSMB->DataOffset = cpu_to_le16(offset); pSMB->ParameterOffset = cpu_to_le16(param_offset); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5d269f583dac..01dc45178f66 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1403,6 +1403,11 @@ smbd_connected: goto out_err_crypto_release; } tcp_ses->min_offload = ctx->min_offload; + /* + * at this point we are the only ones with the pointer + * to the struct since the kernel thread not created yet + * no need to spinlock this update of tcpStatus + */ tcp_ses->tcpStatus = CifsNeedNegotiate; if ((ctx->max_credits < 20) || (ctx->max_credits > 60000)) diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 92d4ab029c91..553adfbcc22a 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -322,7 +322,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx new_ctx->UNC = NULL; new_ctx->source = NULL; new_ctx->iocharset = NULL; - /* * Make sure to stay in sync with smb3_cleanup_fs_context_contents() */ @@ -792,6 +791,8 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, int i, opt; bool is_smb3 = !strcmp(fc->fs_type->name, "smb3"); bool skip_parsing = false; + kuid_t uid; + kgid_t gid; cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key); @@ -904,18 +905,31 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, } break; case Opt_uid: - ctx->linux_uid.val = result.uint_32; + uid = make_kuid(current_user_ns(), result.uint_32); + if (!uid_valid(uid)) + goto cifs_parse_mount_err; + ctx->linux_uid = uid; ctx->uid_specified = true; break; case Opt_cruid: - ctx->cred_uid.val = result.uint_32; + uid = make_kuid(current_user_ns(), result.uint_32); + if (!uid_valid(uid)) + goto cifs_parse_mount_err; + ctx->cred_uid = uid; + ctx->cruid_specified = true; break; case Opt_backupgid: - ctx->backupgid.val = result.uint_32; + gid = make_kgid(current_user_ns(), result.uint_32); + if (!gid_valid(gid)) + goto cifs_parse_mount_err; + ctx->backupgid = gid; ctx->backupgid_specified = true; break; case Opt_gid: - ctx->linux_gid.val = result.uint_32; + gid = make_kgid(current_user_ns(), result.uint_32); + if (!gid_valid(gid)) + goto cifs_parse_mount_err; + ctx->linux_gid = gid; ctx->gid_specified = true; break; case Opt_port: diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 2a71c8e411ac..b6243972edf3 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -155,6 +155,7 @@ enum cifs_param { struct smb3_fs_context { bool uid_specified; + bool cruid_specified; bool gid_specified; bool sloppy; bool got_ip; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 962826dc3316..781d14e5f2af 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -433,6 +433,29 @@ build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt) pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1; } +static unsigned int +build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt) +{ + unsigned int ctxt_len = sizeof(struct smb2_signing_capabilities); + unsigned short num_algs = 1; /* number of signing algorithms sent */ + + pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES; + /* + * Context Data length must be rounded to multiple of 8 for some servers + */ + pneg_ctxt->DataLength = cpu_to_le16(DIV_ROUND_UP( + sizeof(struct smb2_signing_capabilities) - + sizeof(struct smb2_neg_context) + + (num_algs * 2 /* sizeof u16 */), 8) * 8); + pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs); + pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC); + + ctxt_len += 2 /* sizeof le16 */ * num_algs; + ctxt_len = DIV_ROUND_UP(ctxt_len, 8) * 8; + return ctxt_len; + /* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */ +} + static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) { @@ -498,7 +521,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, struct TCP_Server_Info *server, unsigned int *total_len) { char *pneg_ctxt; - unsigned int ctxt_len; + unsigned int ctxt_len, neg_context_count; if (*total_len > 200) { /* In case length corrupted don't want to overrun smb buffer */ @@ -525,6 +548,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, *total_len += ctxt_len; pneg_ctxt += ctxt_len; + ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, + server->hostname); + *total_len += ctxt_len; + pneg_ctxt += ctxt_len; + + build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); + *total_len += sizeof(struct smb2_posix_neg_context); + pneg_ctxt += sizeof(struct smb2_posix_neg_context); + + neg_context_count = 4; + if (server->compress_algorithm) { build_compression_ctxt((struct smb2_compression_capabilities_context *) pneg_ctxt); @@ -533,17 +567,20 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, 8) * 8; *total_len += ctxt_len; pneg_ctxt += ctxt_len; - req->NegotiateContextCount = cpu_to_le16(5); - } else - req->NegotiateContextCount = cpu_to_le16(4); + neg_context_count++; + } - ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, - server->hostname); - *total_len += ctxt_len; - pneg_ctxt += ctxt_len; + if (enable_negotiate_signing) { + ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *) + pneg_ctxt); + *total_len += ctxt_len; + pneg_ctxt += ctxt_len; + neg_context_count++; + } + + /* check for and add transport_capabilities and signing capabilities */ + req->NegotiateContextCount = cpu_to_le16(neg_context_count); - build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); - *total_len += sizeof(struct smb2_posix_neg_context); } static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) @@ -632,6 +669,31 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server, return 0; } +static void decode_signing_ctx(struct TCP_Server_Info *server, + struct smb2_signing_capabilities *pctxt) +{ + unsigned int len = le16_to_cpu(pctxt->DataLength); + + if ((len < 4) || (len > 16)) { + pr_warn_once("server sent bad signing negcontext\n"); + return; + } + if (le16_to_cpu(pctxt->SigningAlgorithmCount) != 1) { + pr_warn_once("Invalid signing algorithm count\n"); + return; + } + if (le16_to_cpu(pctxt->SigningAlgorithms[0]) > 2) { + pr_warn_once("unknown signing algorithm\n"); + return; + } + + server->signing_negotiated = true; + server->signing_algorithm = le16_to_cpu(pctxt->SigningAlgorithms[0]); + cifs_dbg(FYI, "signing algorithm %d chosen\n", + server->signing_algorithm); +} + + static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, struct TCP_Server_Info *server, unsigned int len_of_smb) @@ -675,6 +737,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, (struct smb2_compression_capabilities_context *)pctx); else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) server->posix_ext_supported = true; + else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) + decode_signing_ctx(server, + (struct smb2_signing_capabilities *)pctx); else cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n", le16_to_cpu(pctx->ContextType)); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index a5c48b85549a..4b27cb9105fd 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -13,7 +13,7 @@ #define _SMB2PDU_H #include -#include +#include "cifsacl.h" /* * Note that, due to trying to use names similar to the protocol specifications, @@ -329,7 +329,7 @@ struct smb2_neg_context { __le16 ContextType; __le16 DataLength; __le32 Reserved; - /* Followed by array of data */ + /* Followed by array of data. NOTE: some servers require padding to 8 byte boundary */ } __packed; #define SMB311_LINUX_CLIENT_SALT_SIZE 32 @@ -394,6 +394,7 @@ struct smb2_compression_capabilities_context { __u16 Padding; __u32 Flags; __le16 CompressionAlgorithms[3]; + /* Check if pad needed */ } __packed; /* @@ -420,6 +421,7 @@ struct smb2_transport_capabilities_context { __le16 DataLength; __u32 Reserved; __le32 Flags; + __u32 Pad; } __packed; /* @@ -458,6 +460,7 @@ struct smb2_signing_capabilities { __u32 Reserved; __le16 SigningAlgorithmCount; __le16 SigningAlgorithms[]; + /* Followed by padding to 8 byte boundary (required by some servers) */ } __packed; #define POSIX_CTXT_DATA_LEN 16 diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index f65f9a692ca2..75a95de320cf 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -431,7 +431,9 @@ unmask: * be taken as the remainder of this one. We need to kill the * socket so the server throws away the partial SMB */ + spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); trace_smb3_partial_send_reconnect(server->CurrentMid, server->conn_id, server->hostname); } diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index be799040a415..b96ecba91899 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -327,6 +327,7 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, set_buffer_meta(bh); set_buffer_prio(bh); + set_buffer_uptodate(bh); if (ext4_handle_valid(handle)) { err = jbd2_journal_dirty_metadata(handle, bh); /* Errors can only happen due to aborted journal or a nasty bug */ @@ -355,7 +356,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, err); } } else { - set_buffer_uptodate(bh); if (inode) mark_buffer_dirty_inode(bh, inode); else diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index e27f34bceb8d..6eed6170aded 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -692,6 +692,13 @@ static long ext4_ioctl_group_add(struct file *file, if (err) return err; + if (ext4_has_feature_bigalloc(sb)) { + ext4_msg(sb, KERN_ERR, + "Online resizing not supported with bigalloc"); + err = -EOPNOTSUPP; + goto group_add_out; + } + err = mnt_want_write_file(file); if (err) goto group_add_out; @@ -816,7 +823,7 @@ static int ext4_ioctl_checkpoint(struct file *filp, unsigned long arg) if (!EXT4_SB(sb)->s_journal) return -ENODEV; - if (flags & ~JBD2_JOURNAL_FLUSH_VALID) + if (flags & ~EXT4_IOC_CHECKPOINT_FLAG_VALID) return -EINVAL; q = bdev_get_queue(EXT4_SB(sb)->s_journal->j_dev); @@ -914,6 +921,13 @@ setversion_out: goto group_extend_out; } + if (ext4_has_feature_bigalloc(sb)) { + ext4_msg(sb, KERN_ERR, + "Online resizing not supported with bigalloc"); + err = -EOPNOTSUPP; + goto group_extend_out; + } + err = mnt_want_write_file(filp); if (err) goto group_extend_out; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index c2c22c2baac0..089c958aa2c3 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1909,10 +1909,11 @@ static int mb_find_extent(struct ext4_buddy *e4b, int block, if (ex->fe_start + ex->fe_len > EXT4_CLUSTERS_PER_GROUP(e4b->bd_sb)) { /* Should never happen! (but apparently sometimes does?!?) */ WARN_ON(1); - ext4_error(e4b->bd_sb, "corruption or bug in mb_find_extent " - "block=%d, order=%d needed=%d ex=%u/%d/%d@%u", - block, order, needed, ex->fe_group, ex->fe_start, - ex->fe_len, ex->fe_logical); + ext4_grp_locked_error(e4b->bd_sb, e4b->bd_group, 0, 0, + "corruption or bug in mb_find_extent " + "block=%d, order=%d needed=%d ex=%u/%d/%d@%u", + block, order, needed, ex->fe_group, ex->fe_start, + ex->fe_len, ex->fe_logical); ex->fe_len = 0; ex->fe_start = 0; ex->fe_group = 0; diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index 6cb598b549ca..bc364c119af6 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c @@ -156,7 +156,12 @@ static int kmmpd(void *data) memcpy(mmp->mmp_nodename, init_utsname()->nodename, sizeof(mmp->mmp_nodename)); - while (!kthread_should_stop()) { + while (!kthread_should_stop() && !sb_rdonly(sb)) { + if (!ext4_has_feature_mmp(sb)) { + ext4_warning(sb, "kmmpd being stopped since MMP feature" + " has been disabled."); + goto wait_to_exit; + } if (++seq > EXT4_MMP_SEQ_MAX) seq = 1; @@ -177,16 +182,6 @@ static int kmmpd(void *data) failed_writes++; } - if (!(le32_to_cpu(es->s_feature_incompat) & - EXT4_FEATURE_INCOMPAT_MMP)) { - ext4_warning(sb, "kmmpd being stopped since MMP feature" - " has been disabled."); - goto exit_thread; - } - - if (sb_rdonly(sb)) - break; - diff = jiffies - last_update_time; if (diff < mmp_update_interval * HZ) schedule_timeout_interruptible(mmp_update_interval * @@ -207,7 +202,7 @@ static int kmmpd(void *data) ext4_error_err(sb, -retval, "error reading MMP data: %d", retval); - goto exit_thread; + goto wait_to_exit; } mmp_check = (struct mmp_struct *)(bh_check->b_data); @@ -221,7 +216,7 @@ static int kmmpd(void *data) ext4_error_err(sb, EBUSY, "abort"); put_bh(bh_check); retval = -EBUSY; - goto exit_thread; + goto wait_to_exit; } put_bh(bh_check); } @@ -244,7 +239,13 @@ static int kmmpd(void *data) retval = write_mmp_block(sb, bh); -exit_thread: +wait_to_exit: + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + if (!kthread_should_stop()) + schedule(); + } + set_current_state(TASK_RUNNING); return retval; } @@ -391,5 +392,3 @@ failed: brelse(bh); return 1; } - - diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index fc885914c88a..7a9f1adef679 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -74,10 +74,6 @@ int ext4_resize_begin(struct super_block *sb) return -EPERM; } - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, "Online resizing not supported with bigalloc"); - return -EOPNOTSUPP; - } if (ext4_has_feature_sparse_super2(sb)) { ext4_msg(sb, KERN_ERR, "Online resizing not supported with sparse_super2"); return -EOPNOTSUPP; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 20344633bdd9..dfa09a277b56 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -705,15 +705,23 @@ static void flush_stashed_error_work(struct work_struct *work) * ext4 error handling code during handling of previous errors. */ if (!sb_rdonly(sbi->s_sb) && journal) { + struct buffer_head *sbh = sbi->s_sbh; handle = jbd2_journal_start(journal, 1); if (IS_ERR(handle)) goto write_directly; - if (jbd2_journal_get_write_access(handle, sbi->s_sbh)) { + if (jbd2_journal_get_write_access(handle, sbh)) { jbd2_journal_stop(handle); goto write_directly; } ext4_update_super(sbi->s_sb); - if (jbd2_journal_dirty_metadata(handle, sbi->s_sbh)) { + if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { + ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to " + "superblock detected"); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } + + if (jbd2_journal_dirty_metadata(handle, sbh)) { jbd2_journal_stop(handle); goto write_directly; } @@ -1176,7 +1184,6 @@ static void ext4_put_super(struct super_block *sb) ext4_unregister_sysfs(sb); if (sbi->s_journal) { - jbd2_journal_unregister_shrinker(sbi->s_journal); aborted = is_journal_aborted(sbi->s_journal); err = jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; @@ -5168,7 +5175,6 @@ failed_mount_wq: sbi->s_ea_block_cache = NULL; if (sbi->s_journal) { - jbd2_journal_unregister_shrinker(sbi->s_journal); jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; } @@ -5494,12 +5500,6 @@ static int ext4_load_journal(struct super_block *sb, ext4_commit_super(sb); } - err = jbd2_journal_register_shrinker(journal); - if (err) { - EXT4_SB(sb)->s_journal = NULL; - goto err_out; - } - return 0; err_out: @@ -5985,7 +5985,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) */ ext4_mark_recovery_complete(sb, es); } - ext4_stop_mmpd(sbi); } else { /* Make sure we can mount this feature set readwrite */ if (ext4_has_feature_readonly(sb) || @@ -6099,6 +6098,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks) ext4_release_system_zone(sb); + if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb)) + ext4_stop_mmpd(sbi); + /* * Some options can be enabled by ext4 and/or by VFS mount flag * either way we need to make sure it matches in both *flags and @@ -6132,6 +6134,8 @@ restore_opts: for (i = 0; i < EXT4_MAXQUOTAS; i++) kfree(to_free[i]); #endif + if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb)) + ext4_stop_mmpd(sbi); kfree(orig_data); return err; } diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index f795049e63d5..6c208108d69c 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -444,7 +444,7 @@ static int f2fs_set_meta_page_dirty(struct page *page) if (!PageDirty(page)) { __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); - f2fs_set_page_private(page, 0); + set_page_private_reference(page); return 1; } return 0; @@ -1018,7 +1018,7 @@ void f2fs_update_dirty_page(struct inode *inode, struct page *page) inode_inc_dirty_pages(inode); spin_unlock(&sbi->inode_lock[type]); - f2fs_set_page_private(page, 0); + set_page_private_reference(page); } void f2fs_remove_dirty_inode(struct inode *inode) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 925a5ca3744a..455561826c7d 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -12,9 +12,11 @@ #include #include #include +#include #include "f2fs.h" #include "node.h" +#include "segment.h" #include static struct kmem_cache *cic_entry_slab; @@ -74,7 +76,7 @@ bool f2fs_is_compressed_page(struct page *page) return false; if (!page_private(page)) return false; - if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page)) + if (page_private_nonpointer(page)) return false; f2fs_bug_on(F2FS_M_SB(page->mapping), @@ -85,8 +87,7 @@ bool f2fs_is_compressed_page(struct page *page) static void f2fs_set_compressed_page(struct page *page, struct inode *inode, pgoff_t index, void *data) { - SetPagePrivate(page); - set_page_private(page, (unsigned long)data); + attach_page_private(page, (void *)data); /* i_crypto_info and iv index */ page->index = index; @@ -589,8 +590,7 @@ static void f2fs_compress_free_page(struct page *page) { if (!page) return; - set_page_private(page, (unsigned long)NULL); - ClearPagePrivate(page); + detach_page_private(page); page->mapping = NULL; unlock_page(page); mempool_free(page, compress_page_pool); @@ -738,7 +738,7 @@ out: return ret; } -static void f2fs_decompress_cluster(struct decompress_io_ctx *dic) +void f2fs_decompress_cluster(struct decompress_io_ctx *dic) { struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); struct f2fs_inode_info *fi = F2FS_I(dic->inode); @@ -837,7 +837,8 @@ out_end_io: * page being waited on in the cluster, and if so, it decompresses the cluster * (or in the case of a failure, cleans up without actually decompressing). */ -void f2fs_end_read_compressed_page(struct page *page, bool failed) +void f2fs_end_read_compressed_page(struct page *page, bool failed, + block_t blkaddr) { struct decompress_io_ctx *dic = (struct decompress_io_ctx *)page_private(page); @@ -847,6 +848,9 @@ void f2fs_end_read_compressed_page(struct page *page, bool failed) if (failed) WRITE_ONCE(dic->failed, true); + else if (blkaddr) + f2fs_cache_compressed_page(sbi, page, + dic->inode->i_ino, blkaddr); if (atomic_dec_and_test(&dic->remaining_pages)) f2fs_decompress_cluster(dic); @@ -876,7 +880,7 @@ bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index) return is_page_in_cluster(cc, index); } -static bool __cluster_may_compress(struct compress_ctx *cc) +static bool cluster_has_invalid_data(struct compress_ctx *cc) { loff_t i_size = i_size_read(cc->inode); unsigned nr_pages = DIV_ROUND_UP(i_size, PAGE_SIZE); @@ -889,19 +893,22 @@ static bool __cluster_may_compress(struct compress_ctx *cc) /* beyond EOF */ if (page->index >= nr_pages) - return false; + return true; } - return true; + return false; } -static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) +static int __f2fs_cluster_blocks(struct inode *inode, + unsigned int cluster_idx, bool compr) { struct dnode_of_data dn; + unsigned int cluster_size = F2FS_I(inode)->i_cluster_size; + unsigned int start_idx = cluster_idx << + F2FS_I(inode)->i_log_cluster_size; int ret; - set_new_dnode(&dn, cc->inode, NULL, NULL, 0); - ret = f2fs_get_dnode_of_data(&dn, start_idx_of_cluster(cc), - LOOKUP_NODE); + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); if (ret) { if (ret == -ENOENT) ret = 0; @@ -912,7 +919,7 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) int i; ret = 1; - for (i = 1; i < cc->cluster_size; i++) { + for (i = 1; i < cluster_size; i++) { block_t blkaddr; blkaddr = data_blkaddr(dn.inode, @@ -925,6 +932,10 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) ret++; } } + + f2fs_bug_on(F2FS_I_SB(inode), + !compr && ret != cluster_size && + !is_inode_flag_set(inode, FI_COMPRESS_RELEASED)); } fail: f2fs_put_dnode(&dn); @@ -934,25 +945,15 @@ fail: /* return # of compressed blocks in compressed cluster */ static int f2fs_compressed_blocks(struct compress_ctx *cc) { - return __f2fs_cluster_blocks(cc, true); + return __f2fs_cluster_blocks(cc->inode, cc->cluster_idx, true); } /* return # of valid blocks in compressed cluster */ -static int f2fs_cluster_blocks(struct compress_ctx *cc) -{ - return __f2fs_cluster_blocks(cc, false); -} - int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index) { - struct compress_ctx cc = { - .inode = inode, - .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, - .cluster_size = F2FS_I(inode)->i_cluster_size, - .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, - }; - - return f2fs_cluster_blocks(&cc); + return __f2fs_cluster_blocks(inode, + index >> F2FS_I(inode)->i_log_cluster_size, + false); } static bool cluster_may_compress(struct compress_ctx *cc) @@ -961,13 +962,11 @@ static bool cluster_may_compress(struct compress_ctx *cc) return false; if (f2fs_is_atomic_file(cc->inode)) return false; - if (f2fs_is_mmap_file(cc->inode)) - return false; if (!f2fs_cluster_is_full(cc)) return false; if (unlikely(f2fs_cp_error(F2FS_I_SB(cc->inode)))) return false; - return __cluster_may_compress(cc); + return !cluster_has_invalid_data(cc); } static void set_cluster_writeback(struct compress_ctx *cc) @@ -995,21 +994,16 @@ static int prepare_compress_overwrite(struct compress_ctx *cc, struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); struct address_space *mapping = cc->inode->i_mapping; struct page *page; - struct dnode_of_data dn; sector_t last_block_in_bio; unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT; pgoff_t start_idx = start_idx_of_cluster(cc); int i, ret; - bool prealloc; retry: - ret = f2fs_cluster_blocks(cc); + ret = f2fs_is_compressed_cluster(cc->inode, start_idx); if (ret <= 0) return ret; - /* compressed case */ - prealloc = (ret < cc->cluster_size); - ret = f2fs_init_compress_ctx(cc); if (ret) return ret; @@ -1067,25 +1061,6 @@ release_and_retry: } } - if (prealloc) { - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); - - set_new_dnode(&dn, cc->inode, NULL, NULL, 0); - - for (i = cc->cluster_size - 1; i > 0; i--) { - ret = f2fs_get_block(&dn, start_idx + i); - if (ret) { - i = cc->cluster_size; - break; - } - - if (dn.data_blkaddr != NEW_ADDR) - break; - } - - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); - } - if (likely(!ret)) { *fsdata = cc->rpages; *pagep = cc->rpages[offset_in_cluster(cc, index)]; @@ -1216,6 +1191,12 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, loff_t psize; int i, err; + /* we should bypass data pages to proceed the kworkder jobs */ + if (unlikely(f2fs_cp_error(sbi))) { + mapping_set_error(cc->rpages[0]->mapping, -EIO); + goto out_free; + } + if (IS_NOQUOTA(inode)) { /* * We need to wait for node_write to avoid block allocation during @@ -1399,7 +1380,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page) for (i = 0; i < cic->nr_rpages; i++) { WARN_ON(!cic->rpages[i]); - clear_cold_data(cic->rpages[i]); + clear_page_private_gcing(cic->rpages[i]); end_page_writeback(cic->rpages[i]); } @@ -1685,6 +1666,164 @@ void f2fs_put_page_dic(struct page *page) f2fs_put_dic(dic); } +const struct address_space_operations f2fs_compress_aops = { + .releasepage = f2fs_release_page, + .invalidatepage = f2fs_invalidate_page, +}; + +struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi) +{ + return sbi->compress_inode->i_mapping; +} + +void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr) +{ + if (!sbi->compress_inode) + return; + invalidate_mapping_pages(COMPRESS_MAPPING(sbi), blkaddr, blkaddr); +} + +void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, + nid_t ino, block_t blkaddr) +{ + struct page *cpage; + int ret; + + if (!test_opt(sbi, COMPRESS_CACHE)) + return; + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ)) + return; + + if (!f2fs_available_free_memory(sbi, COMPRESS_PAGE)) + return; + + cpage = find_get_page(COMPRESS_MAPPING(sbi), blkaddr); + if (cpage) { + f2fs_put_page(cpage, 0); + return; + } + + cpage = alloc_page(__GFP_NOWARN | __GFP_IO); + if (!cpage) + return; + + ret = add_to_page_cache_lru(cpage, COMPRESS_MAPPING(sbi), + blkaddr, GFP_NOFS); + if (ret) { + f2fs_put_page(cpage, 0); + return; + } + + set_page_private_data(cpage, ino); + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ)) + goto out; + + memcpy(page_address(cpage), page_address(page), PAGE_SIZE); + SetPageUptodate(cpage); +out: + f2fs_put_page(cpage, 1); +} + +bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, struct page *page, + block_t blkaddr) +{ + struct page *cpage; + bool hitted = false; + + if (!test_opt(sbi, COMPRESS_CACHE)) + return false; + + cpage = f2fs_pagecache_get_page(COMPRESS_MAPPING(sbi), + blkaddr, FGP_LOCK | FGP_NOWAIT, GFP_NOFS); + if (cpage) { + if (PageUptodate(cpage)) { + atomic_inc(&sbi->compress_page_hit); + memcpy(page_address(page), + page_address(cpage), PAGE_SIZE); + hitted = true; + } + f2fs_put_page(cpage, 1); + } + + return hitted; +} + +void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct address_space *mapping = sbi->compress_inode->i_mapping; + struct pagevec pvec; + pgoff_t index = 0; + pgoff_t end = MAX_BLKADDR(sbi); + + if (!mapping->nrpages) + return; + + pagevec_init(&pvec); + + do { + unsigned int nr_pages; + int i; + + nr_pages = pagevec_lookup_range(&pvec, mapping, + &index, end - 1); + if (!nr_pages) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + if (page->index > end) + break; + + lock_page(page); + if (page->mapping != mapping) { + unlock_page(page); + continue; + } + + if (ino != get_page_private_data(page)) { + unlock_page(page); + continue; + } + + generic_error_remove_page(mapping, page); + unlock_page(page); + } + pagevec_release(&pvec); + cond_resched(); + } while (index < end); +} + +int f2fs_init_compress_inode(struct f2fs_sb_info *sbi) +{ + struct inode *inode; + + if (!test_opt(sbi, COMPRESS_CACHE)) + return 0; + + inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi)); + if (IS_ERR(inode)) + return PTR_ERR(inode); + sbi->compress_inode = inode; + + sbi->compress_percent = COMPRESS_PERCENT; + sbi->compress_watermark = COMPRESS_WATERMARK; + + atomic_set(&sbi->compress_page_hit, 0); + + return 0; +} + +void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) +{ + if (!sbi->compress_inode) + return; + iput(sbi->compress_inode); + sbi->compress_inode = NULL; +} + int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) { dev_t dev = sbi->sb->s_bdev->bd_dev; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e2ccdb751392..484357f9c62a 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -59,18 +59,19 @@ static bool __is_cp_guaranteed(struct page *page) if (!mapping) return false; - if (f2fs_is_compressed_page(page)) - return false; - inode = mapping->host; sbi = F2FS_I_SB(inode); if (inode->i_ino == F2FS_META_INO(sbi) || inode->i_ino == F2FS_NODE_INO(sbi) || - S_ISDIR(inode->i_mode) || - (S_ISREG(inode->i_mode) && + S_ISDIR(inode->i_mode)) + return true; + + if (f2fs_is_compressed_page(page)) + return false; + if ((S_ISREG(inode->i_mode) && (f2fs_is_atomic_file(inode) || IS_NOQUOTA(inode))) || - is_cold_data(page)) + page_private_gcing(page)) return true; return false; } @@ -132,7 +133,7 @@ static void f2fs_finish_read_bio(struct bio *bio) if (f2fs_is_compressed_page(page)) { if (bio->bi_status) - f2fs_end_read_compressed_page(page, true); + f2fs_end_read_compressed_page(page, true, 0); f2fs_put_page_dic(page); continue; } @@ -228,15 +229,19 @@ static void f2fs_handle_step_decompress(struct bio_post_read_ctx *ctx) struct bio_vec *bv; struct bvec_iter_all iter_all; bool all_compressed = true; + block_t blkaddr = SECTOR_TO_BLOCK(ctx->bio->bi_iter.bi_sector); bio_for_each_segment_all(bv, ctx->bio, iter_all) { struct page *page = bv->bv_page; /* PG_error was set if decryption failed. */ if (f2fs_is_compressed_page(page)) - f2fs_end_read_compressed_page(page, PageError(page)); + f2fs_end_read_compressed_page(page, PageError(page), + blkaddr); else all_compressed = false; + + blkaddr++; } /* @@ -300,9 +305,8 @@ static void f2fs_write_end_io(struct bio *bio) struct page *page = bvec->bv_page; enum count_type type = WB_DATA_TYPE(page); - if (IS_DUMMY_WRITTEN_PAGE(page)) { - set_page_private(page, (unsigned long)NULL); - ClearPagePrivate(page); + if (page_private_dummy(page)) { + clear_page_private_dummy(page); unlock_page(page); mempool_free(page, sbi->write_io_dummy); @@ -332,7 +336,7 @@ static void f2fs_write_end_io(struct bio *bio) dec_page_count(sbi, type); if (f2fs_in_warm_node_list(sbi, page)) f2fs_del_fsync_node_entry(sbi, page); - clear_cold_data(page); + clear_page_private_gcing(page); end_page_writeback(page); } if (!get_pages(sbi, F2FS_WB_CP_DATA) && @@ -460,10 +464,11 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi, GFP_NOIO | __GFP_NOFAIL); f2fs_bug_on(sbi, !page); - zero_user_segment(page, 0, PAGE_SIZE); - SetPagePrivate(page); - set_page_private(page, DUMMY_WRITTEN_PAGE); lock_page(page); + + zero_user_segment(page, 0, PAGE_SIZE); + set_page_private_dummy(page); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) f2fs_bug_on(sbi, 1); } @@ -1356,9 +1361,11 @@ alloc: old_blkaddr = dn->data_blkaddr; f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, &sum, seg_type, NULL); - if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) + if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { invalidate_mapping_pages(META_MAPPING(sbi), old_blkaddr, old_blkaddr); + f2fs_invalidate_compress_page(sbi, old_blkaddr); + } f2fs_update_data_blkaddr(dn, dn->data_blkaddr); /* @@ -2178,7 +2185,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, goto out_put_dnode; } - for (i = 0; i < dic->nr_cpages; i++) { + for (i = 0; i < cc->nr_cpages; i++) { struct page *page = dic->cpages[i]; block_t blkaddr; struct bio_post_read_ctx *ctx; @@ -2186,6 +2193,14 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, blkaddr = data_blkaddr(dn.inode, dn.node_page, dn.ofs_in_node + i + 1); + f2fs_wait_on_block_writeback(inode, blkaddr); + + if (f2fs_load_compressed_page(sbi, page, blkaddr)) { + if (atomic_dec_and_test(&dic->remaining_pages)) + f2fs_decompress_cluster(dic); + continue; + } + if (bio && (!page_is_mergeable(sbi, bio, *last_block_in_bio, blkaddr) || !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) { @@ -2207,8 +2222,6 @@ submit_and_realloc: } } - f2fs_wait_on_block_writeback(inode, blkaddr); - if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -2464,6 +2477,10 @@ static inline bool check_inplace_update_policy(struct inode *inode, bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio) { + /* swap file is migrating in aligned write mode */ + if (is_inode_flag_set(inode, FI_ALIGNED_WRITE)) + return false; + if (f2fs_is_pinned_file(inode)) return true; @@ -2486,10 +2503,15 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) return true; if (f2fs_is_atomic_file(inode)) return true; + + /* swap file is migrating in aligned write mode */ + if (is_inode_flag_set(inode, FI_ALIGNED_WRITE)) + return true; + if (fio) { - if (is_cold_data(fio->page)) + if (page_private_gcing(fio->page)) return true; - if (IS_ATOMIC_WRITTEN_PAGE(fio->page)) + if (page_private_dummy(fio->page)) return true; if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && f2fs_is_checkpointed_data(sbi, fio->old_blkaddr))) @@ -2545,7 +2567,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) /* This page is already truncated */ if (fio->old_blkaddr == NULL_ADDR) { ClearPageUptodate(page); - clear_cold_data(page); + clear_page_private_gcing(page); goto out_writepage; } got_it: @@ -2755,7 +2777,7 @@ out: inode_dec_dirty_pages(inode); if (err) { ClearPageUptodate(page); - clear_cold_data(page); + clear_page_private_gcing(page); } if (wbc->for_reclaim) { @@ -3229,7 +3251,7 @@ restart: f2fs_do_read_inline_data(page, ipage); set_inode_flag(inode, FI_DATA_EXIST); if (inode->i_nlink) - set_inline_node(ipage); + set_page_private_inline(ipage); } else { err = f2fs_convert_inline_page(&dn, page); if (err) @@ -3661,12 +3683,20 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset, } } - clear_cold_data(page); + clear_page_private_gcing(page); - if (IS_ATOMIC_WRITTEN_PAGE(page)) + if (test_opt(sbi, COMPRESS_CACHE)) { + if (f2fs_compressed_file(inode)) + f2fs_invalidate_compress_pages(sbi, inode->i_ino); + if (inode->i_ino == F2FS_COMPRESS_INO(sbi)) + clear_page_private_data(page); + } + + if (page_private_atomic(page)) return f2fs_drop_inmem_page(inode, page); - f2fs_clear_page_private(page); + detach_page_private(page); + set_page_private(page, 0); } int f2fs_release_page(struct page *page, gfp_t wait) @@ -3676,11 +3706,23 @@ int f2fs_release_page(struct page *page, gfp_t wait) return 0; /* This is atomic written page, keep Private */ - if (IS_ATOMIC_WRITTEN_PAGE(page)) + if (page_private_atomic(page)) return 0; - clear_cold_data(page); - f2fs_clear_page_private(page); + if (test_opt(F2FS_P_SB(page), COMPRESS_CACHE)) { + struct f2fs_sb_info *sbi = F2FS_P_SB(page); + struct inode *inode = page->mapping->host; + + if (f2fs_compressed_file(inode)) + f2fs_invalidate_compress_pages(sbi, inode->i_ino); + if (inode->i_ino == F2FS_COMPRESS_INO(sbi)) + clear_page_private_data(page); + } + + clear_page_private_gcing(page); + + detach_page_private(page); + set_page_private(page, 0); return 1; } @@ -3696,7 +3738,7 @@ static int f2fs_set_data_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) { - if (!IS_ATOMIC_WRITTEN_PAGE(page)) { + if (!page_private_atomic(page)) { f2fs_register_inmem_page(inode, page); return 1; } @@ -3788,7 +3830,7 @@ int f2fs_migrate_page(struct address_space *mapping, { int rc, extra_count; struct f2fs_inode_info *fi = F2FS_I(mapping->host); - bool atomic_written = IS_ATOMIC_WRITTEN_PAGE(page); + bool atomic_written = page_private_atomic(page); BUG_ON(PageWriteback(page)); @@ -3823,9 +3865,16 @@ int f2fs_migrate_page(struct address_space *mapping, get_page(newpage); } + /* guarantee to start from no stale private field */ + set_page_private(newpage, 0); if (PagePrivate(page)) { - f2fs_set_page_private(newpage, page_private(page)); - f2fs_clear_page_private(page); + set_page_private(newpage, page_private(page)); + SetPagePrivate(newpage); + get_page(newpage); + + set_page_private(page, 0); + ClearPagePrivate(page); + put_page(page); } if (mode != MIGRATE_SYNC_NO_COPY) @@ -3838,67 +3887,66 @@ int f2fs_migrate_page(struct address_space *mapping, #endif #ifdef CONFIG_SWAP -static int f2fs_is_file_aligned(struct inode *inode) +static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, + unsigned int blkcnt) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - block_t main_blkaddr = SM_I(sbi)->main_blkaddr; - block_t cur_lblock; - block_t last_lblock; - block_t pblock; - unsigned long nr_pblocks; - unsigned int blocks_per_sec = BLKS_PER_SEC(sbi); - unsigned int not_aligned = 0; + unsigned int blkofs; + unsigned int blk_per_sec = BLKS_PER_SEC(sbi); + unsigned int secidx = start_blk / blk_per_sec; + unsigned int end_sec = secidx + blkcnt / blk_per_sec; int ret = 0; - cur_lblock = 0; - last_lblock = bytes_to_blks(inode, i_size_read(inode)); + down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + down_write(&F2FS_I(inode)->i_mmap_sem); - while (cur_lblock < last_lblock) { - struct f2fs_map_blocks map; + set_inode_flag(inode, FI_ALIGNED_WRITE); - memset(&map, 0, sizeof(map)); - map.m_lblk = cur_lblock; - map.m_len = last_lblock - cur_lblock; - map.m_next_pgofs = NULL; - map.m_next_extent = NULL; - map.m_seg_type = NO_CHECK_TYPE; - map.m_may_create = false; + for (; secidx < end_sec; secidx++) { + down_write(&sbi->pin_sem); - ret = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_FIEMAP); - if (ret) - goto out; + f2fs_lock_op(sbi); + f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); + f2fs_unlock_op(sbi); - /* hole */ - if (!(map.m_flags & F2FS_MAP_FLAGS)) { - f2fs_err(sbi, "Swapfile has holes\n"); - ret = -ENOENT; - goto out; - } + set_inode_flag(inode, FI_DO_DEFRAG); - pblock = map.m_pblk; - nr_pblocks = map.m_len; + for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { + struct page *page; + unsigned int blkidx = secidx * blk_per_sec + blkofs; - if ((pblock - main_blkaddr) & (blocks_per_sec - 1) || - nr_pblocks & (blocks_per_sec - 1)) { - if (f2fs_is_pinned_file(inode)) { - f2fs_err(sbi, "Swapfile does not align to section"); - ret = -EINVAL; - goto out; + page = f2fs_get_lock_data_page(inode, blkidx, true); + if (IS_ERR(page)) { + up_write(&sbi->pin_sem); + ret = PTR_ERR(page); + goto done; } - not_aligned++; + + set_page_dirty(page); + f2fs_put_page(page, 1); } - cur_lblock += nr_pblocks; + clear_inode_flag(inode, FI_DO_DEFRAG); + + ret = filemap_fdatawrite(inode->i_mapping); + + up_write(&sbi->pin_sem); + + if (ret) + break; } - if (not_aligned) - f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n" - "\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()", - not_aligned); -out: + +done: + clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_ALIGNED_WRITE); + + up_write(&F2FS_I(inode)->i_mmap_sem); + up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + return ret; } -static int check_swap_activate_fast(struct swap_info_struct *sis, +static int check_swap_activate(struct swap_info_struct *sis, struct file *swap_file, sector_t *span) { struct address_space *mapping = swap_file->f_mapping; @@ -3911,7 +3959,8 @@ static int check_swap_activate_fast(struct swap_info_struct *sis, sector_t highest_pblock = 0; int nr_extents = 0; unsigned long nr_pblocks; - unsigned int blocks_per_sec = BLKS_PER_SEC(sbi); + unsigned int blks_per_sec = BLKS_PER_SEC(sbi); + unsigned int sec_blks_mask = BLKS_PER_SEC(sbi) - 1; unsigned int not_aligned = 0; int ret = 0; @@ -3924,7 +3973,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis, while (cur_lblock < last_lblock && cur_lblock < sis->max) { struct f2fs_map_blocks map; - +retry: cond_resched(); memset(&map, 0, sizeof(map)); @@ -3941,7 +3990,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis, /* hole */ if (!(map.m_flags & F2FS_MAP_FLAGS)) { - f2fs_err(sbi, "Swapfile has holes\n"); + f2fs_err(sbi, "Swapfile has holes"); ret = -EINVAL; goto out; } @@ -3949,16 +3998,28 @@ static int check_swap_activate_fast(struct swap_info_struct *sis, pblock = map.m_pblk; nr_pblocks = map.m_len; - if ((pblock - SM_I(sbi)->main_blkaddr) & (blocks_per_sec - 1) || - nr_pblocks & (blocks_per_sec - 1)) { - if (f2fs_is_pinned_file(inode)) { - f2fs_err(sbi, "Swapfile does not align to section"); - ret = -EINVAL; - goto out; - } + if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask || + nr_pblocks & sec_blks_mask) { not_aligned++; - } + nr_pblocks = roundup(nr_pblocks, blks_per_sec); + if (cur_lblock + nr_pblocks > sis->max) + nr_pblocks -= blks_per_sec; + + if (!nr_pblocks) { + /* this extent is last one */ + nr_pblocks = map.m_len; + f2fs_warn(sbi, "Swapfile: last extent is not aligned to section"); + goto next; + } + + ret = f2fs_migrate_blocks(inode, cur_lblock, + nr_pblocks); + if (ret) + goto out; + goto retry; + } +next: if (cur_lblock + nr_pblocks >= sis->max) nr_pblocks = sis->max - cur_lblock; @@ -3985,122 +4046,13 @@ static int check_swap_activate_fast(struct swap_info_struct *sis, sis->max = cur_lblock; sis->pages = cur_lblock - 1; sis->highest_bit = cur_lblock - 1; - +out: if (not_aligned) - f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n" - "\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()", - not_aligned); -out: + f2fs_warn(sbi, "Swapfile (%u) is not align to section: 1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate(%u * N)", + not_aligned, blks_per_sec * F2FS_BLKSIZE); return ret; } -/* Copied from generic_swapfile_activate() to check any holes */ -static int check_swap_activate(struct swap_info_struct *sis, - struct file *swap_file, sector_t *span) -{ - struct address_space *mapping = swap_file->f_mapping; - struct inode *inode = mapping->host; - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - unsigned blocks_per_page; - unsigned long page_no; - sector_t probe_block; - sector_t last_block; - sector_t lowest_block = -1; - sector_t highest_block = 0; - int nr_extents = 0; - int ret = 0; - - if (PAGE_SIZE == F2FS_BLKSIZE) - return check_swap_activate_fast(sis, swap_file, span); - - ret = f2fs_is_file_aligned(inode); - if (ret) - goto out; - - blocks_per_page = bytes_to_blks(inode, PAGE_SIZE); - - /* - * Map all the blocks into the extent list. This code doesn't try - * to be very smart. - */ - probe_block = 0; - page_no = 0; - last_block = bytes_to_blks(inode, i_size_read(inode)); - while ((probe_block + blocks_per_page) <= last_block && - page_no < sis->max) { - unsigned block_in_page; - sector_t first_block; - sector_t block = 0; - - cond_resched(); - - block = probe_block; - ret = bmap(inode, &block); - if (ret) - goto out; - if (!block) - goto bad_bmap; - first_block = block; - - /* - * It must be PAGE_SIZE aligned on-disk - */ - if (first_block & (blocks_per_page - 1)) { - probe_block++; - goto reprobe; - } - - for (block_in_page = 1; block_in_page < blocks_per_page; - block_in_page++) { - - block = probe_block + block_in_page; - ret = bmap(inode, &block); - if (ret) - goto out; - if (!block) - goto bad_bmap; - - if (block != first_block + block_in_page) { - /* Discontiguity */ - probe_block++; - goto reprobe; - } - } - - first_block >>= (PAGE_SHIFT - inode->i_blkbits); - if (page_no) { /* exclude the header page */ - if (first_block < lowest_block) - lowest_block = first_block; - if (first_block > highest_block) - highest_block = first_block; - } - - /* - * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks - */ - ret = add_swap_extent(sis, page_no, 1, first_block); - if (ret < 0) - goto out; - nr_extents += ret; - page_no++; - probe_block += blocks_per_page; -reprobe: - continue; - } - ret = nr_extents; - *span = 1 + highest_block - lowest_block; - if (page_no == 0) - page_no = 1; /* force Empty message */ - sis->max = page_no; - sis->pages = page_no - 1; - sis->highest_bit = page_no - 1; -out: - return ret; -bad_bmap: - f2fs_err(sbi, "Swapfile has holes\n"); - return -EINVAL; -} - static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, sector_t *span) { @@ -4113,6 +4065,12 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, if (f2fs_readonly(F2FS_I_SB(inode)->sb)) return -EROFS; + if (f2fs_lfs_mode(F2FS_I_SB(inode))) { + f2fs_err(F2FS_I_SB(inode), + "Swapfile not supported in LFS mode"); + return -EINVAL; + } + ret = f2fs_convert_inline_inode(inode); if (ret) return ret; diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index c03949a7ccff..833325038ef3 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -152,6 +152,12 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->node_pages = NODE_MAPPING(sbi)->nrpages; if (sbi->meta_inode) si->meta_pages = META_MAPPING(sbi)->nrpages; +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (sbi->compress_inode) { + si->compress_pages = COMPRESS_MAPPING(sbi)->nrpages; + si->compress_page_hit = atomic_read(&sbi->compress_page_hit); + } +#endif si->nats = NM_I(sbi)->nat_cnt[TOTAL_NAT]; si->dirty_nats = NM_I(sbi)->nat_cnt[DIRTY_NAT]; si->sits = MAIN_SEGS(sbi); @@ -309,6 +315,12 @@ get_cache: si->page_mem += (unsigned long long)npages << PAGE_SHIFT; } +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (sbi->compress_inode) { + unsigned npages = COMPRESS_MAPPING(sbi)->nrpages; + si->page_mem += (unsigned long long)npages << PAGE_SHIFT; + } +#endif } static int stat_show(struct seq_file *s, void *v) @@ -476,6 +488,7 @@ static int stat_show(struct seq_file *s, void *v) "volatile IO: %4d (Max. %4d)\n", si->inmem_pages, si->aw_cnt, si->max_aw_cnt, si->vw_cnt, si->max_vw_cnt); + seq_printf(s, " - compress: %4d, hit:%8d\n", si->compress_pages, si->compress_page_hit); seq_printf(s, " - nodes: %4d in %4d\n", si->ndirty_node, si->node_pages); seq_printf(s, " - dents: %4d in dirs:%4d (%4d)\n", diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index dc7ce79672b8..456651682daf 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -16,6 +16,10 @@ #include "xattr.h" #include +#ifdef CONFIG_UNICODE +extern struct kmem_cache *f2fs_cf_name_slab; +#endif + static unsigned long dir_blocks(struct inode *inode) { return ((unsigned long long) (i_size_read(inode) + PAGE_SIZE - 1)) @@ -77,11 +81,10 @@ int f2fs_init_casefolded_name(const struct inode *dir, { #ifdef CONFIG_UNICODE struct super_block *sb = dir->i_sb; - struct f2fs_sb_info *sbi = F2FS_SB(sb); if (IS_CASEFOLDED(dir)) { - fname->cf_name.name = f2fs_kmalloc(sbi, F2FS_NAME_LEN, - GFP_NOFS); + fname->cf_name.name = kmem_cache_alloc(f2fs_cf_name_slab, + GFP_NOFS); if (!fname->cf_name.name) return -ENOMEM; fname->cf_name.len = utf8_casefold(sb->s_encoding, @@ -89,7 +92,7 @@ int f2fs_init_casefolded_name(const struct inode *dir, fname->cf_name.name, F2FS_NAME_LEN); if ((int)fname->cf_name.len <= 0) { - kfree(fname->cf_name.name); + kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name); fname->cf_name.name = NULL; if (sb_has_strict_encoding(sb)) return -EINVAL; @@ -172,8 +175,10 @@ void f2fs_free_filename(struct f2fs_filename *fname) fname->crypto_buf.name = NULL; #endif #ifdef CONFIG_UNICODE - kfree(fname->cf_name.name); - fname->cf_name.name = NULL; + if (fname->cf_name.name) { + kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name); + fname->cf_name.name = NULL; + } #endif } @@ -929,11 +934,15 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, !f2fs_truncate_hole(dir, page->index, page->index + 1)) { f2fs_clear_page_cache_dirty_tag(page); clear_page_dirty_for_io(page); - f2fs_clear_page_private(page); ClearPageUptodate(page); - clear_cold_data(page); + + clear_page_private_gcing(page); + inode_dec_dirty_pages(dir); f2fs_remove_dirty_inode(dir); + + detach_page_private(page); + set_page_private(page, 0); } f2fs_put_page(page, 1); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a416ea3a1a04..1acb2f2505cc 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -98,6 +98,7 @@ extern const char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_ATGC 0x08000000 #define F2FS_MOUNT_MERGE_CHECKPOINT 0x10000000 #define F2FS_MOUNT_GC_MERGE 0x20000000 +#define F2FS_MOUNT_COMPRESS_CACHE 0x40000000 #define F2FS_OPTION(sbi) ((sbi)->mount_opt) #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) @@ -150,8 +151,10 @@ struct f2fs_mount_info { unsigned char compress_level; /* compress level */ bool compress_chksum; /* compressed data chksum */ unsigned char compress_ext_cnt; /* extension count */ + unsigned char nocompress_ext_cnt; /* nocompress extension count */ int compress_mode; /* compression mode */ unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ + unsigned char noextensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* extensions */ }; #define F2FS_FEATURE_ENCRYPT 0x0001 @@ -168,6 +171,7 @@ struct f2fs_mount_info { #define F2FS_FEATURE_SB_CHKSUM 0x0800 #define F2FS_FEATURE_CASEFOLD 0x1000 #define F2FS_FEATURE_COMPRESSION 0x2000 +#define F2FS_FEATURE_RO 0x4000 #define __F2FS_HAS_FEATURE(raw_super, mask) \ ((raw_super->feature & cpu_to_le32(mask)) != 0) @@ -706,6 +710,8 @@ enum { FI_COMPRESS_CORRUPT, /* indicate compressed cluster is corrupted */ FI_MMAP_FILE, /* indicate file was mmapped */ FI_ENABLE_COMPRESS, /* enable compression in "user" compression mode */ + FI_COMPRESS_RELEASED, /* compressed blocks were released */ + FI_ALIGNED_WRITE, /* enable aligned write */ FI_MAX, /* max flag, never be used */ }; @@ -939,6 +945,7 @@ static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode, #define NR_CURSEG_DATA_TYPE (3) #define NR_CURSEG_NODE_TYPE (3) #define NR_CURSEG_INMEM_TYPE (2) +#define NR_CURSEG_RO_TYPE (2) #define NR_CURSEG_PERSIST_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) #define NR_CURSEG_TYPE (NR_CURSEG_INMEM_TYPE + NR_CURSEG_PERSIST_TYPE) @@ -1291,17 +1298,119 @@ enum { */ }; -/* - * this value is set in page as a private data which indicate that - * the page is atomically written, and it is in inmem_pages list. - */ -#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1) -#define DUMMY_WRITTEN_PAGE ((unsigned long)-2) +static inline int f2fs_test_bit(unsigned int nr, char *addr); +static inline void f2fs_set_bit(unsigned int nr, char *addr); +static inline void f2fs_clear_bit(unsigned int nr, char *addr); -#define IS_ATOMIC_WRITTEN_PAGE(page) \ - (page_private(page) == ATOMIC_WRITTEN_PAGE) -#define IS_DUMMY_WRITTEN_PAGE(page) \ - (page_private(page) == DUMMY_WRITTEN_PAGE) +/* + * Layout of f2fs page.private: + * + * Layout A: lowest bit should be 1 + * | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... | + * bit 0 PAGE_PRIVATE_NOT_POINTER + * bit 1 PAGE_PRIVATE_ATOMIC_WRITE + * bit 2 PAGE_PRIVATE_DUMMY_WRITE + * bit 3 PAGE_PRIVATE_ONGOING_MIGRATION + * bit 4 PAGE_PRIVATE_INLINE_INODE + * bit 5 PAGE_PRIVATE_REF_RESOURCE + * bit 6- f2fs private data + * + * Layout B: lowest bit should be 0 + * page.private is a wrapped pointer. + */ +enum { + PAGE_PRIVATE_NOT_POINTER, /* private contains non-pointer data */ + PAGE_PRIVATE_ATOMIC_WRITE, /* data page from atomic write path */ + PAGE_PRIVATE_DUMMY_WRITE, /* data page for padding aligned IO */ + PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */ + PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */ + PAGE_PRIVATE_REF_RESOURCE, /* dirty page has referenced resources */ + PAGE_PRIVATE_MAX +}; + +#define PAGE_PRIVATE_GET_FUNC(name, flagname) \ +static inline bool page_private_##name(struct page *page) \ +{ \ + return PagePrivate(page) && \ + test_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)) && \ + test_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ +} + +#define PAGE_PRIVATE_SET_FUNC(name, flagname) \ +static inline void set_page_private_##name(struct page *page) \ +{ \ + if (!PagePrivate(page)) { \ + get_page(page); \ + SetPagePrivate(page); \ + set_page_private(page, 0); \ + } \ + set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); \ + set_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ +} + +#define PAGE_PRIVATE_CLEAR_FUNC(name, flagname) \ +static inline void clear_page_private_##name(struct page *page) \ +{ \ + clear_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ + if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) { \ + set_page_private(page, 0); \ + if (PagePrivate(page)) { \ + ClearPagePrivate(page); \ + put_page(page); \ + }\ + } \ +} + +PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER); +PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE); +PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE); +PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION); +PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE); +PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE); + +PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE); +PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE); +PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION); +PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE); +PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE); + +PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE); +PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE); +PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION); +PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE); +PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE); + +static inline unsigned long get_page_private_data(struct page *page) +{ + unsigned long data = page_private(page); + + if (!test_bit(PAGE_PRIVATE_NOT_POINTER, &data)) + return 0; + return data >> PAGE_PRIVATE_MAX; +} + +static inline void set_page_private_data(struct page *page, unsigned long data) +{ + if (!PagePrivate(page)) { + get_page(page); + SetPagePrivate(page); + set_page_private(page, 0); + } + set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); + page_private(page) |= data << PAGE_PRIVATE_MAX; +} + +static inline void clear_page_private_data(struct page *page) +{ + page_private(page) &= (1 << PAGE_PRIVATE_MAX) - 1; + if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) { + set_page_private(page, 0); + if (PagePrivate(page)) { + ClearPagePrivate(page); + put_page(page); + } + } +} /* For compression */ enum compress_algorithm_type { @@ -1317,6 +1426,9 @@ enum compress_flag { COMPRESS_MAX_FLAG, }; +#define COMPRESS_WATERMARK 20 +#define COMPRESS_PERCENT 20 + #define COMPRESS_DATA_RESERVED_SIZE 4 struct compress_data { __le32 clen; /* compressed data size */ @@ -1594,6 +1706,9 @@ struct f2fs_sb_info { struct kobject s_stat_kobj; /* /sys/fs/f2fs//stat */ struct completion s_stat_kobj_unregister; + struct kobject s_feature_list_kobj; /* /sys/fs/f2fs//feature_list */ + struct completion s_feature_list_kobj_unregister; + /* For shrinker support */ struct list_head s_list; int s_ndevs; /* number of devices */ @@ -1626,6 +1741,12 @@ struct f2fs_sb_info { u64 compr_written_block; u64 compr_saved_block; u32 compr_new_inode; + + /* For compressed block cache */ + struct inode *compress_inode; /* cache compressed blocks */ + unsigned int compress_percent; /* cache page percentage */ + unsigned int compress_watermark; /* cache page watermark */ + atomic_t compress_page_hit; /* cache hit count */ #endif }; @@ -2678,6 +2799,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode, case FI_DATA_EXIST: case FI_INLINE_DOTS: case FI_PIN_FILE: + case FI_COMPRESS_RELEASED: f2fs_mark_inode_dirty_sync(inode, true); } } @@ -2799,6 +2921,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri) set_bit(FI_EXTRA_ATTR, fi->flags); if (ri->i_inline & F2FS_PIN_FILE) set_bit(FI_PIN_FILE, fi->flags); + if (ri->i_inline & F2FS_COMPRESS_RELEASED) + set_bit(FI_COMPRESS_RELEASED, fi->flags); } static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) @@ -2819,6 +2943,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri) ri->i_inline |= F2FS_EXTRA_ATTR; if (is_inode_flag_set(inode, FI_PIN_FILE)) ri->i_inline |= F2FS_PIN_FILE; + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) + ri->i_inline |= F2FS_COMPRESS_RELEASED; } static inline int f2fs_has_extra_attr(struct inode *inode) @@ -3027,25 +3153,6 @@ static inline bool is_dot_dotdot(const u8 *name, size_t len) return false; } -static inline bool f2fs_may_extent_tree(struct inode *inode) -{ - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - - if (!test_opt(sbi, EXTENT_CACHE) || - is_inode_flag_set(inode, FI_NO_EXTENT) || - is_inode_flag_set(inode, FI_COMPRESSED_FILE)) - return false; - - /* - * for recovered files during mount do not create extents - * if shrinker is not registered. - */ - if (list_empty(&sbi->s_list)) - return false; - - return S_ISREG(inode->i_mode); -} - static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi, size_t size, gfp_t flags) { @@ -3169,20 +3276,6 @@ static inline bool __is_valid_data_blkaddr(block_t blkaddr) return true; } -static inline void f2fs_set_page_private(struct page *page, - unsigned long data) -{ - if (PagePrivate(page)) - return; - - attach_page_private(page, (void *)data); -} - -static inline void f2fs_clear_page_private(struct page *page) -{ - detach_page_private(page); -} - /* * file.c */ @@ -3566,6 +3659,8 @@ void f2fs_destroy_garbage_collection_cache(void); */ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only); bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi); +int __init f2fs_create_recovery_cache(void); +void f2fs_destroy_recovery_cache(void); /* * debug.c @@ -3604,7 +3699,8 @@ struct f2fs_stat_info { unsigned int bimodal, avg_vblocks; int util_free, util_valid, util_invalid; int rsvd_segs, overp_segs; - int dirty_count, node_pages, meta_pages; + int dirty_count, node_pages, meta_pages, compress_pages; + int compress_page_hit; int prefree_count, call_count, cp_count, bg_cp_count; int tot_segs, node_segs, data_segs, free_segs, free_secs; int bg_node_segs, bg_data_segs; @@ -3940,7 +4036,9 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page); bool f2fs_is_compress_backend_ready(struct inode *inode); int f2fs_init_compress_mempool(void); void f2fs_destroy_compress_mempool(void); -void f2fs_end_read_compressed_page(struct page *page, bool failed); +void f2fs_decompress_cluster(struct decompress_io_ctx *dic); +void f2fs_end_read_compressed_page(struct page *page, bool failed, + block_t blkaddr); bool f2fs_cluster_is_empty(struct compress_ctx *cc); bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index); void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page); @@ -3958,10 +4056,19 @@ void f2fs_put_page_dic(struct page *page); int f2fs_init_compress_ctx(struct compress_ctx *cc); void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse); void f2fs_init_compress_info(struct f2fs_sb_info *sbi); +int f2fs_init_compress_inode(struct f2fs_sb_info *sbi); +void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi); int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi); void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi); int __init f2fs_init_compress_cache(void); void f2fs_destroy_compress_cache(void); +struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi); +void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr); +void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, + nid_t ino, block_t blkaddr); +bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, struct page *page, + block_t blkaddr); +void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, nid_t ino); #define inc_compr_inode_stat(inode) \ do { \ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); \ @@ -3990,7 +4097,9 @@ static inline struct page *f2fs_compress_control_page(struct page *page) } static inline int f2fs_init_compress_mempool(void) { return 0; } static inline void f2fs_destroy_compress_mempool(void) { } -static inline void f2fs_end_read_compressed_page(struct page *page, bool failed) +static inline void f2fs_decompress_cluster(struct decompress_io_ctx *dic) { } +static inline void f2fs_end_read_compressed_page(struct page *page, + bool failed, block_t blkaddr) { WARN_ON_ONCE(1); } @@ -3998,10 +4107,20 @@ static inline void f2fs_put_page_dic(struct page *page) { WARN_ON_ONCE(1); } +static inline int f2fs_init_compress_inode(struct f2fs_sb_info *sbi) { return 0; } +static inline void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) { } static inline int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) { return 0; } static inline void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi) { } static inline int __init f2fs_init_compress_cache(void) { return 0; } static inline void f2fs_destroy_compress_cache(void) { } +static inline void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, + block_t blkaddr) { } +static inline void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, + struct page *page, nid_t ino, block_t blkaddr) { } +static inline bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, + struct page *page, block_t blkaddr) { return false; } +static inline void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, + nid_t ino) { } #define inc_compr_inode_stat(inode) do { } while (0) #endif @@ -4066,6 +4185,27 @@ F2FS_FEATURE_FUNCS(verity, VERITY); F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); F2FS_FEATURE_FUNCS(casefold, CASEFOLD); F2FS_FEATURE_FUNCS(compression, COMPRESSION); +F2FS_FEATURE_FUNCS(readonly, RO); + +static inline bool f2fs_may_extent_tree(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + if (!test_opt(sbi, EXTENT_CACHE) || + is_inode_flag_set(inode, FI_NO_EXTENT) || + (is_inode_flag_set(inode, FI_COMPRESSED_FILE) && + !f2fs_sb_has_readonly(sbi))) + return false; + + /* + * for recovered files during mount do not create extents + * if shrinker is not registered. + */ + if (list_empty(&sbi->s_list)) + return false; + + return S_ISREG(inode->i_mode); +} #ifdef CONFIG_BLK_DEV_ZONED static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ceb575f99048..6afd4562335f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -63,6 +63,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) if (unlikely(IS_IMMUTABLE(inode))) return VM_FAULT_SIGBUS; + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) + return VM_FAULT_SIGBUS; + if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; goto err; @@ -85,10 +88,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) err = ret; goto err; } else if (ret) { - if (ret < F2FS_I(inode)->i_cluster_size) { - err = -EAGAIN; - goto err; - } need_alloc = false; } } @@ -117,7 +116,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); set_new_dnode(&dn, inode, NULL, NULL, 0); err = f2fs_get_block(&dn, page->index); - f2fs_put_dnode(&dn); f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); } @@ -3203,7 +3201,7 @@ int f2fs_precache_extents(struct inode *inode) map.m_lblk = m_next_extent; } - return err; + return 0; } static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg) @@ -3237,7 +3235,7 @@ static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg) if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) { f2fs_warn(F2FS_I_SB(inode), - "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem.\n", + "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem", inode->i_ino); return -EOPNOTSUPP; } @@ -3425,7 +3423,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) goto out; } - if (IS_IMMUTABLE(inode)) { + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ret = -EINVAL; goto out; } @@ -3434,8 +3432,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) if (ret) goto out; - F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + set_inode_flag(inode, FI_COMPRESS_RELEASED); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); @@ -3590,7 +3587,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) inode_lock(inode); - if (!IS_IMMUTABLE(inode)) { + if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { ret = -EINVAL; goto unlock_inode; } @@ -3635,8 +3632,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) up_write(&F2FS_I(inode)->i_mmap_sem); if (ret >= 0) { - F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL; - f2fs_set_inode_flags(inode); + clear_inode_flag(inode, FI_COMPRESS_RELEASED); inode->i_ctime = current_time(inode); f2fs_mark_inode_dirty_sync(inode, true); } @@ -4023,9 +4019,8 @@ static int f2fs_ioc_decompress_file(struct file *filp, unsigned long arg) LLONG_MAX); if (ret) - f2fs_warn(sbi, "%s: The file might be partially decompressed " - "(errno=%d). Please delete the file.\n", - __func__, ret); + f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.", + __func__, ret); out: inode_unlock(inode); file_end_write(filp); @@ -4097,9 +4092,8 @@ static int f2fs_ioc_compress_file(struct file *filp, unsigned long arg) clear_inode_flag(inode, FI_ENABLE_COMPRESS); if (ret) - f2fs_warn(sbi, "%s: The file might be partially compressed " - "(errno=%d). Please delete the file.\n", - __func__, ret); + f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.", + __func__, ret); out: inode_unlock(inode); file_end_write(filp); @@ -4254,6 +4248,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) goto unlock; } + if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) { + ret = -EPERM; + goto unlock; + } + ret = generic_write_checks(iocb, from); if (ret > 0) { bool preallocated = false; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 8d1f17ab94d8..0e42ee5f7770 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1031,8 +1031,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (unlikely(check_valid_map(sbi, segno, offset))) { if (!test_and_set_bit(segno, SIT_I(sbi)->invalid_segmap)) { - f2fs_err(sbi, "mismatched blkaddr %u (source_blkaddr %u) in seg %u\n", - blkaddr, source_blkaddr, segno); + f2fs_err(sbi, "mismatched blkaddr %u (source_blkaddr %u) in seg %u", + blkaddr, source_blkaddr, segno); f2fs_bug_on(sbi, 1); } } @@ -1261,6 +1261,7 @@ static int move_data_block(struct inode *inode, block_t bidx, f2fs_put_page(mpage, 1); invalidate_mapping_pages(META_MAPPING(fio.sbi), fio.old_blkaddr, fio.old_blkaddr); + f2fs_invalidate_compress_page(fio.sbi, fio.old_blkaddr); set_page_dirty(fio.encrypted_page); if (clear_page_dirty_for_io(fio.encrypted_page)) @@ -1336,7 +1337,7 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type, goto out; } set_page_dirty(page); - set_cold_data(page); + set_page_private_gcing(page); } else { struct f2fs_io_info fio = { .sbi = F2FS_I_SB(inode), @@ -1362,11 +1363,11 @@ retry: f2fs_remove_dirty_inode(inode); } - set_cold_data(page); + set_page_private_gcing(page); err = f2fs_do_write_data_page(&fio); if (err) { - clear_cold_data(page); + clear_page_private_gcing(page); if (err == -ENOMEM) { congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); @@ -1450,10 +1451,8 @@ next_step: if (phase == 3) { inode = f2fs_iget(sb, dni.ino); - if (IS_ERR(inode) || is_bad_inode(inode)) { - set_sbi_flag(sbi, SBI_NEED_FSCK); + if (IS_ERR(inode) || is_bad_inode(inode)) continue; - } if (!down_write_trylock( &F2FS_I(inode)->i_gc_rwsem[WRITE])) { @@ -1822,6 +1821,7 @@ static void init_atgc_management(struct f2fs_sb_info *sbi) am->candidate_ratio = DEF_GC_THREAD_CANDIDATE_RATIO; am->max_candidate_count = DEF_GC_THREAD_MAX_CANDIDATE_COUNT; am->age_weight = DEF_GC_THREAD_AGE_WEIGHT; + am->age_threshold = DEF_GC_THREAD_AGE_THRESHOLD; } void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 9b98bab3db02..2311c76ffc37 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -191,7 +191,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) /* clear inline data and flag after data writeback */ f2fs_truncate_inline_inode(dn->inode, dn->inode_page, 0); - clear_inline_node(dn->inode_page); + clear_page_private_inline(dn->inode_page); clear_out: stat_dec_inline_inode(dn->inode); clear_inode_flag(dn->inode, FI_INLINE_DATA); @@ -273,7 +273,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page) set_inode_flag(inode, FI_APPEND_WRITE); set_inode_flag(inode, FI_DATA_EXIST); - clear_inline_node(dn.inode_page); + clear_page_private_inline(dn.inode_page); f2fs_put_dnode(&dn); return 0; } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index b401f08569f7..9141147b5bb0 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -18,6 +18,10 @@ #include +#ifdef CONFIG_F2FS_FS_COMPRESSION +extern const struct address_space_operations f2fs_compress_aops; +#endif + void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) { if (is_inode_flag_set(inode, FI_NEW_INODE)) @@ -494,6 +498,11 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) goto make_now; +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (ino == F2FS_COMPRESS_INO(sbi)) + goto make_now; +#endif + ret = do_read_inode(inode); if (ret) goto bad_inode; @@ -504,6 +513,12 @@ make_now: } else if (ino == F2FS_META_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_meta_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); + } else if (ino == F2FS_COMPRESS_INO(sbi)) { +#ifdef CONFIG_F2FS_FS_COMPRESSION + inode->i_mapping->a_ops = &f2fs_compress_aops; +#endif + mapping_set_gfp_mask(inode->i_mapping, + GFP_NOFS | __GFP_HIGHMEM | __GFP_MOVABLE); } else if (S_ISREG(inode->i_mode)) { inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; @@ -646,7 +661,7 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page) /* deleted inode */ if (inode->i_nlink == 0) - clear_inline_node(node_page); + clear_page_private_inline(node_page); F2FS_I(inode)->i_disk_time[0] = inode->i_atime; F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; @@ -723,8 +738,12 @@ void f2fs_evict_inode(struct inode *inode) trace_f2fs_evict_inode(inode); truncate_inode_pages_final(&inode->i_data); + if (test_opt(sbi, COMPRESS_CACHE) && f2fs_compressed_file(inode)) + f2fs_invalidate_compress_pages(sbi, inode->i_ino); + if (inode->i_ino == F2FS_NODE_INO(sbi) || - inode->i_ino == F2FS_META_INO(sbi)) + inode->i_ino == F2FS_META_INO(sbi) || + inode->i_ino == F2FS_COMPRESS_INO(sbi)) goto out_clear; f2fs_bug_on(sbi, get_dirty_pages(inode)); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a9cd9cf97229..e149c8c66a71 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -153,7 +153,8 @@ fail_drop: return ERR_PTR(err); } -static inline int is_extension_exist(const unsigned char *s, const char *sub) +static inline int is_extension_exist(const unsigned char *s, const char *sub, + bool tmp_ext) { size_t slen = strlen(s); size_t sublen = strlen(sub); @@ -169,6 +170,13 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub) if (slen < sublen + 2) return 0; + if (!tmp_ext) { + /* file has no temp extension */ + if (s[slen - sublen - 1] != '.') + return 0; + return !strncasecmp(s + slen - sublen, sub, sublen); + } + for (i = 1; i < slen - sublen; i++) { if (s[i] != '.') continue; @@ -194,7 +202,7 @@ static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode * hot_count = sbi->raw_super->hot_ext_count; for (i = 0; i < cold_count + hot_count; i++) { - if (is_extension_exist(name, extlist[i])) + if (is_extension_exist(name, extlist[i], true)) break; } @@ -279,14 +287,16 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode, const unsigned char *name) { __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; - unsigned char (*ext)[F2FS_EXTENSION_LEN]; - unsigned int ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; + unsigned char (*noext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).noextensions; + unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions; + unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; + unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; int i, cold_count, hot_count; if (!f2fs_sb_has_compression(sbi) || - is_inode_flag_set(inode, FI_COMPRESSED_FILE) || F2FS_I(inode)->i_flags & F2FS_NOCOMP_FL || - !f2fs_may_compress(inode)) + !f2fs_may_compress(inode) || + (!ext_cnt && !noext_cnt)) return; down_read(&sbi->sb_lock); @@ -295,7 +305,7 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode, hot_count = sbi->raw_super->hot_ext_count; for (i = cold_count; i < cold_count + hot_count; i++) { - if (is_extension_exist(name, extlist[i])) { + if (is_extension_exist(name, extlist[i], false)) { up_read(&sbi->sb_lock); return; } @@ -303,10 +313,18 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode, up_read(&sbi->sb_lock); - ext = F2FS_OPTION(sbi).extensions; + for (i = 0; i < noext_cnt; i++) { + if (is_extension_exist(name, noext[i], false)) { + f2fs_disable_compressed_file(inode); + return; + } + } + + if (is_inode_flag_set(inode, FI_COMPRESSED_FILE)) + return; for (i = 0; i < ext_cnt; i++) { - if (!is_extension_exist(name, ext[i])) + if (!is_extension_exist(name, ext[i], false)) continue; set_compress_context(inode); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index e67ce5f13b98..0be9e2d7120e 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -97,6 +97,20 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type) mem_size = (atomic_read(&dcc->discard_cmd_cnt) * sizeof(struct discard_cmd)) >> PAGE_SHIFT; res = mem_size < (avail_ram * nm_i->ram_thresh / 100); + } else if (type == COMPRESS_PAGE) { +#ifdef CONFIG_F2FS_FS_COMPRESSION + unsigned long free_ram = val.freeram; + + /* + * free memory is lower than watermark or cached page count + * exceed threshold, deny caching compress page. + */ + res = (free_ram > avail_ram * sbi->compress_watermark / 100) && + (COMPRESS_MAPPING(sbi)->nrpages < + free_ram * sbi->compress_percent / 100); +#else + res = false; +#endif } else { if (!sbi->sb->s_bdi->wb.dirty_exceeded) return true; @@ -1535,13 +1549,10 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, trace_f2fs_writepage(page, NODE); if (unlikely(f2fs_cp_error(sbi))) { - if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) { - ClearPageUptodate(page); - dec_page_count(sbi, F2FS_DIRTY_NODES); - unlock_page(page); - return 0; - } - goto redirty_out; + ClearPageUptodate(page); + dec_page_count(sbi, F2FS_DIRTY_NODES); + unlock_page(page); + return 0; } if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) @@ -1860,8 +1871,8 @@ continue_unlock: } /* flush inline_data, if it's async context. */ - if (is_inline_node(page)) { - clear_inline_node(page); + if (page_private_inline(page)) { + clear_page_private_inline(page); unlock_page(page); flush_inline_data(sbi, ino_of_node(page)); continue; @@ -1941,8 +1952,8 @@ continue_unlock: goto write_node; /* flush inline_data */ - if (is_inline_node(page)) { - clear_inline_node(page); + if (page_private_inline(page)) { + clear_page_private_inline(page); unlock_page(page); flush_inline_data(sbi, ino_of_node(page)); goto lock_node; @@ -2096,7 +2107,7 @@ static int f2fs_set_node_page_dirty(struct page *page) if (!PageDirty(page)) { __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); - f2fs_set_page_private(page, 0); + set_page_private_reference(page); return 1; } return 0; diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 7a45c0f10629..ff14a6e5ac1c 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -38,6 +38,9 @@ /* return value for read_node_page */ #define LOCKED_PAGE 1 +/* check pinned file's alignment status of physical blocks */ +#define FILE_NOT_ALIGNED 1 + /* For flag in struct node_info */ enum { IS_CHECKPOINTED, /* is it checkpointed before? */ @@ -148,6 +151,7 @@ enum mem_type { EXTENT_CACHE, /* indicates extent cache */ INMEM_PAGES, /* indicates inmemory pages */ DISCARD_CACHE, /* indicates memory of cached discard cmds */ + COMPRESS_PAGE, /* indicates memory of cached compressed pages */ BASE_CHECK, /* check kernel status */ }; @@ -389,20 +393,6 @@ static inline nid_t get_nid(struct page *p, int off, bool i) * - Mark cold node blocks in their node footer * - Mark cold data pages in page cache */ -static inline int is_cold_data(struct page *page) -{ - return PageChecked(page); -} - -static inline void set_cold_data(struct page *page) -{ - SetPageChecked(page); -} - -static inline void clear_cold_data(struct page *page) -{ - ClearPageChecked(page); -} static inline int is_node(struct page *page, int type) { @@ -414,21 +404,6 @@ static inline int is_node(struct page *page, int type) #define is_fsync_dnode(page) is_node(page, FSYNC_BIT_SHIFT) #define is_dent_dnode(page) is_node(page, DENT_BIT_SHIFT) -static inline int is_inline_node(struct page *page) -{ - return PageChecked(page); -} - -static inline void set_inline_node(struct page *page) -{ - SetPageChecked(page); -} - -static inline void clear_inline_node(struct page *page) -{ - ClearPageChecked(page); -} - static inline void set_cold_node(struct page *page, bool is_dir) { struct f2fs_node *rn = F2FS_NODE(page); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 422146c6d866..695eacfe776c 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -45,6 +45,10 @@ static struct kmem_cache *fsync_entry_slab; +#ifdef CONFIG_UNICODE +extern struct kmem_cache *f2fs_cf_name_slab; +#endif + bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi) { s64 nalloc = percpu_counter_sum_positive(&sbi->alloc_valid_block_count); @@ -145,7 +149,7 @@ static int init_recovered_filename(const struct inode *dir, f2fs_hash_filename(dir, fname); #ifdef CONFIG_UNICODE /* Case-sensitive match is fine for recovery */ - kfree(fname->cf_name.name); + kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name); fname->cf_name.name = NULL; #endif } else { @@ -788,13 +792,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY); #endif - fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", - sizeof(struct fsync_inode_entry)); - if (!fsync_entry_slab) { - err = -ENOMEM; - goto out; - } - INIT_LIST_HEAD(&inode_list); INIT_LIST_HEAD(&tmp_inode_list); INIT_LIST_HEAD(&dir_list); @@ -867,8 +864,6 @@ skip: } } - kmem_cache_destroy(fsync_entry_slab); -out: #ifdef CONFIG_QUOTA /* Turn quotas off */ if (quota_enabled) @@ -878,3 +873,17 @@ out: return ret ? ret : err; } + +int __init f2fs_create_recovery_cache(void) +{ + fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", + sizeof(struct fsync_inode_entry)); + if (!fsync_entry_slab) + return -ENOMEM; + return 0; +} + +void f2fs_destroy_recovery_cache(void) +{ + kmem_cache_destroy(fsync_entry_slab); +} diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 51dc79fad4fe..15cc89eef28d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -186,10 +186,7 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page) { struct inmem_pages *new; - if (PagePrivate(page)) - set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE); - else - f2fs_set_page_private(page, ATOMIC_WRITTEN_PAGE); + set_page_private_atomic(page); new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); @@ -272,9 +269,10 @@ next: /* we don't need to invalidate this in the sccessful status */ if (drop || recover) { ClearPageUptodate(page); - clear_cold_data(page); + clear_page_private_gcing(page); } - f2fs_clear_page_private(page); + detach_page_private(page); + set_page_private(page, 0); f2fs_put_page(page, 1); list_del(&cur->list); @@ -357,7 +355,7 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page) struct list_head *head = &fi->inmem_pages; struct inmem_pages *cur = NULL; - f2fs_bug_on(sbi, !IS_ATOMIC_WRITTEN_PAGE(page)); + f2fs_bug_on(sbi, !page_private_atomic(page)); mutex_lock(&fi->inmem_lock); list_for_each_entry(cur, head, list) { @@ -373,9 +371,12 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page) kmem_cache_free(inmem_entry_slab, cur); ClearPageUptodate(page); - f2fs_clear_page_private(page); + clear_page_private_atomic(page); f2fs_put_page(page, 0); + detach_page_private(page); + set_page_private(page, 0); + trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE); } @@ -2321,6 +2322,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) return; invalidate_mapping_pages(META_MAPPING(sbi), addr, addr); + f2fs_invalidate_compress_page(sbi, addr); /* add it into sit main buffer */ down_write(&sit_i->sentry_lock); @@ -3289,7 +3291,10 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) if (fio->type == DATA) { struct inode *inode = fio->page->mapping->host; - if (is_cold_data(fio->page)) { + if (is_inode_flag_set(inode, FI_ALIGNED_WRITE)) + return CURSEG_COLD_DATA_PINNED; + + if (page_private_gcing(fio->page)) { if (fio->sbi->am.atgc_enabled && (fio->io_type == FS_DATA_IO) && (fio->sbi->gc_mode != GC_URGENT_HIGH)) @@ -3468,9 +3473,11 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) reallocate: f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, &fio->new_blkaddr, sum, type, fio); - if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) + if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) { invalidate_mapping_pages(META_MAPPING(fio->sbi), fio->old_blkaddr, fio->old_blkaddr); + f2fs_invalidate_compress_page(fio->sbi, fio->old_blkaddr); + } /* writeout dirty page into bdev */ f2fs_submit_page_write(fio); @@ -3660,6 +3667,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { invalidate_mapping_pages(META_MAPPING(sbi), old_blkaddr, old_blkaddr); + f2fs_invalidate_compress_page(sbi, old_blkaddr); if (!from_gc) update_segment_mtime(sbi, old_blkaddr, 0); update_sit_entry(sbi, old_blkaddr, -1); @@ -3919,7 +3927,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) /* sanity check for summary blocks */ if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) { - f2fs_err(sbi, "invalid journal entries nats %u sits %u\n", + f2fs_err(sbi, "invalid journal entries nats %u sits %u", nats_in_cursum(nat_j), sits_in_cursum(sit_j)); return -EINVAL; } @@ -4682,6 +4690,10 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi) struct seg_entry *se = get_seg_entry(sbi, curseg->segno); unsigned int blkofs = curseg->next_blkoff; + if (f2fs_sb_has_readonly(sbi) && + i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE) + continue; + sanity_check_seg_type(sbi, curseg->seg_type); if (f2fs_test_bit(blkofs, se->cur_valid_map)) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 7d325bfaf65a..8fecd3050ccd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -148,8 +148,10 @@ enum { Opt_compress_algorithm, Opt_compress_log_size, Opt_compress_extension, + Opt_nocompress_extension, Opt_compress_chksum, Opt_compress_mode, + Opt_compress_cache, Opt_atgc, Opt_gc_merge, Opt_nogc_merge, @@ -222,8 +224,10 @@ static match_table_t f2fs_tokens = { {Opt_compress_algorithm, "compress_algorithm=%s"}, {Opt_compress_log_size, "compress_log_size=%u"}, {Opt_compress_extension, "compress_extension=%s"}, + {Opt_nocompress_extension, "nocompress_extension=%s"}, {Opt_compress_chksum, "compress_chksum"}, {Opt_compress_mode, "compress_mode=%s"}, + {Opt_compress_cache, "compress_cache"}, {Opt_atgc, "atgc"}, {Opt_gc_merge, "gc_merge"}, {Opt_nogc_merge, "nogc_merge"}, @@ -275,6 +279,24 @@ static int f2fs_sb_read_encoding(const struct f2fs_super_block *sb, return 0; } + +struct kmem_cache *f2fs_cf_name_slab; +static int __init f2fs_create_casefold_cache(void) +{ + f2fs_cf_name_slab = f2fs_kmem_cache_create("f2fs_casefolded_name", + F2FS_NAME_LEN); + if (!f2fs_cf_name_slab) + return -ENOMEM; + return 0; +} + +static void f2fs_destroy_casefold_cache(void) +{ + kmem_cache_destroy(f2fs_cf_name_slab); +} +#else +static int __init f2fs_create_casefold_cache(void) { return 0; } +static void f2fs_destroy_casefold_cache(void) { } #endif static inline void limit_reserve_root(struct f2fs_sb_info *sbi) @@ -473,6 +495,43 @@ static int f2fs_set_test_dummy_encryption(struct super_block *sb, } #ifdef CONFIG_F2FS_FS_COMPRESSION +/* + * 1. The same extension name cannot not appear in both compress and non-compress extension + * at the same time. + * 2. If the compress extension specifies all files, the types specified by the non-compress + * extension will be treated as special cases and will not be compressed. + * 3. Don't allow the non-compress extension specifies all files. + */ +static int f2fs_test_compress_extension(struct f2fs_sb_info *sbi) +{ + unsigned char (*ext)[F2FS_EXTENSION_LEN]; + unsigned char (*noext)[F2FS_EXTENSION_LEN]; + int ext_cnt, noext_cnt, index = 0, no_index = 0; + + ext = F2FS_OPTION(sbi).extensions; + ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; + noext = F2FS_OPTION(sbi).noextensions; + noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; + + if (!noext_cnt) + return 0; + + for (no_index = 0; no_index < noext_cnt; no_index++) { + if (!strcasecmp("*", noext[no_index])) { + f2fs_info(sbi, "Don't allow the nocompress extension specifies all files"); + return -EINVAL; + } + for (index = 0; index < ext_cnt; index++) { + if (!strcasecmp(ext[index], noext[no_index])) { + f2fs_info(sbi, "Don't allow the same extension %s appear in both compress and nocompress extension", + ext[index]); + return -EINVAL; + } + } + } + return 0; +} + #ifdef CONFIG_F2FS_FS_LZ4 static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str) { @@ -546,7 +605,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) substring_t args[MAX_OPT_ARGS]; #ifdef CONFIG_F2FS_FS_COMPRESSION unsigned char (*ext)[F2FS_EXTENSION_LEN]; - int ext_cnt; + unsigned char (*noext)[F2FS_EXTENSION_LEN]; + int ext_cnt, noext_cnt; #endif char *p, *name; int arg = 0; @@ -555,7 +615,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) int ret; if (!options) - return 0; + goto default_check; while ((p = strsep(&options, ",")) != NULL) { int token; @@ -1049,6 +1109,30 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) F2FS_OPTION(sbi).compress_ext_cnt++; kfree(name); break; + case Opt_nocompress_extension: + if (!f2fs_sb_has_compression(sbi)) { + f2fs_info(sbi, "Image doesn't support compression"); + break; + } + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + + noext = F2FS_OPTION(sbi).noextensions; + noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; + + if (strlen(name) >= F2FS_EXTENSION_LEN || + noext_cnt >= COMPRESS_EXT_NUM) { + f2fs_err(sbi, + "invalid extension length/number"); + kfree(name); + return -EINVAL; + } + + strcpy(noext[noext_cnt], name); + F2FS_OPTION(sbi).nocompress_ext_cnt++; + kfree(name); + break; case Opt_compress_chksum: F2FS_OPTION(sbi).compress_chksum = true; break; @@ -1066,12 +1150,17 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) } kfree(name); break; + case Opt_compress_cache: + set_opt(sbi, COMPRESS_CACHE); + break; #else case Opt_compress_algorithm: case Opt_compress_log_size: case Opt_compress_extension: + case Opt_nocompress_extension: case Opt_compress_chksum: case Opt_compress_mode: + case Opt_compress_cache: f2fs_info(sbi, "compression options not supported"); break; #endif @@ -1090,6 +1179,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) return -EINVAL; } } +default_check: #ifdef CONFIG_QUOTA if (f2fs_check_quota_options(sbi)) return -EINVAL; @@ -1122,6 +1212,13 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) } #endif +#ifdef CONFIG_F2FS_FS_COMPRESSION + if (f2fs_test_compress_extension(sbi)) { + f2fs_err(sbi, "invalid compress or nocompress extension"); + return -EINVAL; + } +#endif + if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) { f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO", F2FS_IO_SIZE_KB(sbi)); @@ -1153,7 +1250,7 @@ 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 not compatible with checkpoint=disable\n"); + f2fs_err(sbi, "LFS not compatible with checkpoint=disable"); return -EINVAL; } @@ -1162,6 +1259,11 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) */ if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE) F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; + + if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) { + f2fs_err(sbi, "Allow to mount readonly mode only"); + return -EROFS; + } return 0; } @@ -1403,6 +1505,8 @@ static void f2fs_put_super(struct super_block *sb) f2fs_bug_on(sbi, sbi->fsync_node_num); + f2fs_destroy_compress_inode(sbi); + iput(sbi->node_inode); sbi->node_inode = NULL; @@ -1665,6 +1769,11 @@ static inline void f2fs_show_compress_options(struct seq_file *seq, F2FS_OPTION(sbi).extensions[i]); } + for (i = 0; i < F2FS_OPTION(sbi).nocompress_ext_cnt; i++) { + seq_printf(seq, ",nocompress_extension=%s", + F2FS_OPTION(sbi).noextensions[i]); + } + if (F2FS_OPTION(sbi).compress_chksum) seq_puts(seq, ",compress_chksum"); @@ -1672,6 +1781,9 @@ static inline void f2fs_show_compress_options(struct seq_file *seq, seq_printf(seq, ",compress_mode=%s", "fs"); else if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_USER) seq_printf(seq, ",compress_mode=%s", "user"); + + if (test_opt(sbi, COMPRESS_CACHE)) + seq_puts(seq, ",compress_cache"); } #endif @@ -1819,7 +1931,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) static void default_options(struct f2fs_sb_info *sbi) { /* init some FS parameters */ - F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE; + if (f2fs_sb_has_readonly(sbi)) + F2FS_OPTION(sbi).active_logs = NR_CURSEG_RO_TYPE; + else + F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE; + F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; @@ -1949,6 +2065,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) bool disable_checkpoint = test_opt(sbi, DISABLE_CHECKPOINT); bool no_io_align = !F2FS_IO_ALIGNED(sbi); bool no_atgc = !test_opt(sbi, ATGC); + bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE); bool checkpoint_changed; #ifdef CONFIG_QUOTA int i, j; @@ -2004,6 +2121,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) if (f2fs_readonly(sb) && (*flags & SB_RDONLY)) goto skip; + if (f2fs_sb_has_readonly(sbi) && !(*flags & SB_RDONLY)) { + err = -EROFS; + goto restore_opts; + } + #ifdef CONFIG_QUOTA if (!f2fs_readonly(sb) && (*flags & SB_RDONLY)) { err = dquot_suspend(sb, -1); @@ -2041,6 +2163,12 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) goto restore_opts; } + if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) { + err = -EINVAL; + f2fs_warn(sbi, "switch compress_cache option is not allowed"); + goto restore_opts; + } + if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) { err = -EINVAL; f2fs_warn(sbi, "disabling checkpoint not compatible with read-only"); @@ -3137,14 +3265,15 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); - if (unlikely(fsmeta < F2FS_MIN_META_SEGMENTS || + if (!f2fs_sb_has_readonly(sbi) && + unlikely(fsmeta < F2FS_MIN_META_SEGMENTS || ovp_segments == 0 || reserved_segments == 0)) { f2fs_err(sbi, "Wrong layout: check mkfs.f2fs version"); return 1; } - user_block_count = le64_to_cpu(ckpt->user_block_count); - segment_count_main = le32_to_cpu(raw_super->segment_count_main); + segment_count_main = le32_to_cpu(raw_super->segment_count_main) + + (f2fs_sb_has_readonly(sbi) ? 1 : 0); log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); if (!user_block_count || user_block_count >= segment_count_main << log_blocks_per_seg) { @@ -3175,6 +3304,10 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) return 1; + + if (f2fs_sb_has_readonly(sbi)) + goto check_data; + for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) == le32_to_cpu(ckpt->cur_node_segno[j])) { @@ -3185,10 +3318,15 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) } } } +check_data: for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) return 1; + + if (f2fs_sb_has_readonly(sbi)) + goto skip_cross; + for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) == le32_to_cpu(ckpt->cur_data_segno[j])) { @@ -3210,7 +3348,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) } } } - +skip_cross: sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); @@ -3555,7 +3693,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) #ifdef CONFIG_BLK_DEV_ZONED if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && !f2fs_sb_has_blkzoned(sbi)) { - f2fs_err(sbi, "Zoned block device feature not enabled\n"); + f2fs_err(sbi, "Zoned block device feature not enabled"); return -EINVAL; } if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) { @@ -3940,10 +4078,14 @@ try_onemore: goto free_node_inode; } - err = f2fs_register_sysfs(sbi); + err = f2fs_init_compress_inode(sbi); if (err) goto free_root_inode; + err = f2fs_register_sysfs(sbi); + if (err) + goto free_compress_inode; + #ifdef CONFIG_QUOTA /* Enable quota usage during mount */ if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) { @@ -4084,6 +4226,8 @@ free_meta: /* evict some inodes being cached by GC */ evict_inodes(sb); f2fs_unregister_sysfs(sbi); +free_compress_inode: + f2fs_destroy_compress_inode(sbi); free_root_inode: dput(sb->s_root); sb->s_root = NULL; @@ -4162,6 +4306,15 @@ static void kill_f2fs_super(struct super_block *sb) f2fs_stop_gc_thread(sbi); f2fs_stop_discard_thread(sbi); +#ifdef CONFIG_F2FS_FS_COMPRESSION + /* + * latter evict_inode() can bypass checking and invalidating + * compress inode cache. + */ + if (test_opt(sbi, COMPRESS_CACHE)) + truncate_inode_pages_final(COMPRESS_MAPPING(sbi)); +#endif + if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { struct cp_control cpc = { @@ -4227,9 +4380,12 @@ static int __init init_f2fs_fs(void) err = f2fs_create_checkpoint_caches(); if (err) goto free_segment_manager_caches; - err = f2fs_create_extent_cache(); + err = f2fs_create_recovery_cache(); if (err) goto free_checkpoint_caches; + err = f2fs_create_extent_cache(); + if (err) + goto free_recovery_cache; err = f2fs_create_garbage_collection_cache(); if (err) goto free_extent_cache; @@ -4258,7 +4414,12 @@ static int __init init_f2fs_fs(void) err = f2fs_init_compress_cache(); if (err) goto free_compress_mempool; + err = f2fs_create_casefold_cache(); + if (err) + goto free_compress_cache; return 0; +free_compress_cache: + f2fs_destroy_compress_cache(); free_compress_mempool: f2fs_destroy_compress_mempool(); free_bioset: @@ -4278,6 +4439,8 @@ free_garbage_collection_cache: f2fs_destroy_garbage_collection_cache(); free_extent_cache: f2fs_destroy_extent_cache(); +free_recovery_cache: + f2fs_destroy_recovery_cache(); free_checkpoint_caches: f2fs_destroy_checkpoint_caches(); free_segment_manager_caches: @@ -4292,6 +4455,7 @@ fail: static void __exit exit_f2fs_fs(void) { + f2fs_destroy_casefold_cache(); f2fs_destroy_compress_cache(); f2fs_destroy_compress_mempool(); f2fs_destroy_bioset(); @@ -4303,6 +4467,7 @@ static void __exit exit_f2fs_fs(void) f2fs_exit_sysfs(); f2fs_destroy_garbage_collection_cache(); f2fs_destroy_extent_cache(); + f2fs_destroy_recovery_cache(); f2fs_destroy_checkpoint_caches(); f2fs_destroy_segment_manager_caches(); f2fs_destroy_node_manager_caches(); @@ -4315,4 +4480,5 @@ module_exit(exit_f2fs_fs) MODULE_AUTHOR("Samsung Electronics's Praesto Team"); MODULE_DESCRIPTION("Flash Friendly File System"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: crc32"); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 39b522ec73e7..6642246206bd 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -37,6 +37,7 @@ enum { #endif RESERVED_BLOCKS, /* struct f2fs_sb_info */ CPRC_INFO, /* struct ckpt_req_control */ + ATGC_INFO, /* struct atgc_management */ }; struct f2fs_attr { @@ -75,6 +76,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) #endif else if (struct_type == CPRC_INFO) return (unsigned char *)&sbi->cprc_info; + else if (struct_type == ATGC_INFO) + return (unsigned char *)&sbi->am; return NULL; } @@ -155,6 +158,9 @@ static ssize_t features_show(struct f2fs_attr *a, if (f2fs_sb_has_casefold(sbi)) len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "casefold"); + if (f2fs_sb_has_readonly(sbi)) + len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len ? ", " : "", "readonly"); if (f2fs_sb_has_compression(sbi)) len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "compression"); @@ -495,6 +501,20 @@ out: } #endif + if (!strcmp(a->attr.name, "atgc_candidate_ratio")) { + if (t > 100) + return -EINVAL; + sbi->am.candidate_ratio = t; + return count; + } + + if (!strcmp(a->attr.name, "atgc_age_weight")) { + if (t > 100) + return -EINVAL; + sbi->am.age_weight = t; + return count; + } + *ui = (unsigned int)t; return count; @@ -546,46 +566,49 @@ static void f2fs_sb_release(struct kobject *kobj) complete(&sbi->s_kobj_unregister); } -enum feat_id { - FEAT_CRYPTO = 0, - FEAT_BLKZONED, - FEAT_ATOMIC_WRITE, - FEAT_EXTRA_ATTR, - FEAT_PROJECT_QUOTA, - FEAT_INODE_CHECKSUM, - FEAT_FLEXIBLE_INLINE_XATTR, - FEAT_QUOTA_INO, - FEAT_INODE_CRTIME, - FEAT_LOST_FOUND, - FEAT_VERITY, - FEAT_SB_CHECKSUM, - FEAT_CASEFOLD, - FEAT_COMPRESSION, - FEAT_TEST_DUMMY_ENCRYPTION_V2, -}; - +/* + * Note that there are three feature list entries: + * 1) /sys/fs/f2fs/features + * : shows runtime features supported by in-kernel f2fs along with Kconfig. + * - ref. F2FS_FEATURE_RO_ATTR() + * + * 2) /sys/fs/f2fs/$s_id/features + * : shows on-disk features enabled by mkfs.f2fs, used for old kernels. This + * won't add new feature anymore, and thus, users should check entries in 3) + * instead of this 2). + * + * 3) /sys/fs/f2fs/$s_id/feature_list + * : shows on-disk features enabled by mkfs.f2fs per instance, which follows + * sysfs entry rule where each entry should expose single value. + * This list covers old feature list provided by 2) and beyond. Therefore, + * please add new on-disk feature in this list only. + * - ref. F2FS_SB_FEATURE_RO_ATTR() + */ static ssize_t f2fs_feature_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { - switch (a->id) { - case FEAT_CRYPTO: - case FEAT_BLKZONED: - case FEAT_ATOMIC_WRITE: - case FEAT_EXTRA_ATTR: - case FEAT_PROJECT_QUOTA: - case FEAT_INODE_CHECKSUM: - case FEAT_FLEXIBLE_INLINE_XATTR: - case FEAT_QUOTA_INO: - case FEAT_INODE_CRTIME: - case FEAT_LOST_FOUND: - case FEAT_VERITY: - case FEAT_SB_CHECKSUM: - case FEAT_CASEFOLD: - case FEAT_COMPRESSION: - case FEAT_TEST_DUMMY_ENCRYPTION_V2: + return sprintf(buf, "supported\n"); +} + +#define F2FS_FEATURE_RO_ATTR(_name) \ +static struct f2fs_attr f2fs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = 0444 }, \ + .show = f2fs_feature_show, \ +} + +static ssize_t f2fs_sb_feature_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) +{ + if (F2FS_HAS_FEATURE(sbi, a->id)) return sprintf(buf, "supported\n"); - } - return 0; + return sprintf(buf, "unsupported\n"); +} + +#define F2FS_SB_FEATURE_RO_ATTR(_name, _feat) \ +static struct f2fs_attr f2fs_attr_sb_##_name = { \ + .attr = {.name = __stringify(_name), .mode = 0444 }, \ + .show = f2fs_sb_feature_show, \ + .id = F2FS_FEATURE_##_feat, \ } #define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ @@ -605,13 +628,6 @@ static struct f2fs_attr f2fs_attr_##_name = { \ #define F2FS_GENERAL_RO_ATTR(name) \ static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) -#define F2FS_FEATURE_RO_ATTR(_name, _id) \ -static struct f2fs_attr f2fs_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = 0444 }, \ - .show = f2fs_feature_show, \ - .id = _id, \ -} - #define F2FS_STAT_ATTR(_struct_type, _struct_name, _name, _elname) \ static struct f2fs_attr f2fs_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = 0444 }, \ @@ -685,31 +701,44 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks); #endif #ifdef CONFIG_FS_ENCRYPTION -F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); -F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2, FEAT_TEST_DUMMY_ENCRYPTION_V2); +F2FS_FEATURE_RO_ATTR(encryption); +F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2); +#ifdef CONFIG_UNICODE +F2FS_FEATURE_RO_ATTR(encrypted_casefold); #endif +#endif /* CONFIG_FS_ENCRYPTION */ #ifdef CONFIG_BLK_DEV_ZONED -F2FS_FEATURE_RO_ATTR(block_zoned, FEAT_BLKZONED); +F2FS_FEATURE_RO_ATTR(block_zoned); #endif -F2FS_FEATURE_RO_ATTR(atomic_write, FEAT_ATOMIC_WRITE); -F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR); -F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA); -F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM); -F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); -F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); -F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); -F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); +F2FS_FEATURE_RO_ATTR(atomic_write); +F2FS_FEATURE_RO_ATTR(extra_attr); +F2FS_FEATURE_RO_ATTR(project_quota); +F2FS_FEATURE_RO_ATTR(inode_checksum); +F2FS_FEATURE_RO_ATTR(flexible_inline_xattr); +F2FS_FEATURE_RO_ATTR(quota_ino); +F2FS_FEATURE_RO_ATTR(inode_crtime); +F2FS_FEATURE_RO_ATTR(lost_found); #ifdef CONFIG_FS_VERITY -F2FS_FEATURE_RO_ATTR(verity, FEAT_VERITY); +F2FS_FEATURE_RO_ATTR(verity); #endif -F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); -F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD); +F2FS_FEATURE_RO_ATTR(sb_checksum); +#ifdef CONFIG_UNICODE +F2FS_FEATURE_RO_ATTR(casefold); +#endif +F2FS_FEATURE_RO_ATTR(readonly); #ifdef CONFIG_F2FS_FS_COMPRESSION -F2FS_FEATURE_RO_ATTR(compression, FEAT_COMPRESSION); +F2FS_FEATURE_RO_ATTR(compression); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_written_block, compr_written_block); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_saved_block, compr_saved_block); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_new_inode, compr_new_inode); #endif +F2FS_FEATURE_RO_ATTR(pin_file); + +/* For ATGC */ +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_ratio, candidate_ratio); +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_count, max_candidate_count); +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_weight, age_weight); +F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -778,6 +807,11 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(compr_saved_block), ATTR_LIST(compr_new_inode), #endif + /* For ATGC */ + ATTR_LIST(atgc_candidate_ratio), + ATTR_LIST(atgc_candidate_count), + ATTR_LIST(atgc_age_weight), + ATTR_LIST(atgc_age_threshold), NULL, }; ATTRIBUTE_GROUPS(f2fs); @@ -786,7 +820,10 @@ static struct attribute *f2fs_feat_attrs[] = { #ifdef CONFIG_FS_ENCRYPTION ATTR_LIST(encryption), ATTR_LIST(test_dummy_encryption_v2), +#ifdef CONFIG_UNICODE + ATTR_LIST(encrypted_casefold), #endif +#endif /* CONFIG_FS_ENCRYPTION */ #ifdef CONFIG_BLK_DEV_ZONED ATTR_LIST(block_zoned), #endif @@ -802,10 +839,14 @@ static struct attribute *f2fs_feat_attrs[] = { ATTR_LIST(verity), #endif ATTR_LIST(sb_checksum), +#ifdef CONFIG_UNICODE ATTR_LIST(casefold), +#endif + ATTR_LIST(readonly), #ifdef CONFIG_F2FS_FS_COMPRESSION ATTR_LIST(compression), #endif + ATTR_LIST(pin_file), NULL, }; ATTRIBUTE_GROUPS(f2fs_feat); @@ -817,6 +858,40 @@ static struct attribute *f2fs_stat_attrs[] = { }; ATTRIBUTE_GROUPS(f2fs_stat); +F2FS_SB_FEATURE_RO_ATTR(encryption, ENCRYPT); +F2FS_SB_FEATURE_RO_ATTR(block_zoned, BLKZONED); +F2FS_SB_FEATURE_RO_ATTR(extra_attr, EXTRA_ATTR); +F2FS_SB_FEATURE_RO_ATTR(project_quota, PRJQUOTA); +F2FS_SB_FEATURE_RO_ATTR(inode_checksum, INODE_CHKSUM); +F2FS_SB_FEATURE_RO_ATTR(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); +F2FS_SB_FEATURE_RO_ATTR(quota_ino, QUOTA_INO); +F2FS_SB_FEATURE_RO_ATTR(inode_crtime, INODE_CRTIME); +F2FS_SB_FEATURE_RO_ATTR(lost_found, LOST_FOUND); +F2FS_SB_FEATURE_RO_ATTR(verity, VERITY); +F2FS_SB_FEATURE_RO_ATTR(sb_checksum, SB_CHKSUM); +F2FS_SB_FEATURE_RO_ATTR(casefold, CASEFOLD); +F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION); +F2FS_SB_FEATURE_RO_ATTR(readonly, RO); + +static struct attribute *f2fs_sb_feat_attrs[] = { + ATTR_LIST(sb_encryption), + ATTR_LIST(sb_block_zoned), + ATTR_LIST(sb_extra_attr), + ATTR_LIST(sb_project_quota), + ATTR_LIST(sb_inode_checksum), + ATTR_LIST(sb_flexible_inline_xattr), + ATTR_LIST(sb_quota_ino), + ATTR_LIST(sb_inode_crtime), + ATTR_LIST(sb_lost_found), + ATTR_LIST(sb_verity), + ATTR_LIST(sb_sb_checksum), + ATTR_LIST(sb_casefold), + ATTR_LIST(sb_compression), + ATTR_LIST(sb_readonly), + NULL, +}; +ATTRIBUTE_GROUPS(f2fs_sb_feat); + static const struct sysfs_ops f2fs_attr_ops = { .show = f2fs_attr_show, .store = f2fs_attr_store, @@ -883,6 +958,33 @@ static struct kobj_type f2fs_stat_ktype = { .release = f2fs_stat_kobj_release, }; +static ssize_t f2fs_sb_feat_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, + s_feature_list_kobj); + struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr); + + return a->show ? a->show(a, sbi, buf) : 0; +} + +static void f2fs_feature_list_kobj_release(struct kobject *kobj) +{ + struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info, + s_feature_list_kobj); + complete(&sbi->s_feature_list_kobj_unregister); +} + +static const struct sysfs_ops f2fs_feature_list_attr_ops = { + .show = f2fs_sb_feat_attr_show, +}; + +static struct kobj_type f2fs_feature_list_ktype = { + .default_groups = f2fs_sb_feat_groups, + .sysfs_ops = &f2fs_feature_list_attr_ops, + .release = f2fs_feature_list_kobj_release, +}; + static int __maybe_unused segment_info_seq_show(struct seq_file *seq, void *offset) { @@ -1099,6 +1201,14 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) if (err) goto put_stat_kobj; + sbi->s_feature_list_kobj.kset = &f2fs_kset; + init_completion(&sbi->s_feature_list_kobj_unregister); + err = kobject_init_and_add(&sbi->s_feature_list_kobj, + &f2fs_feature_list_ktype, + &sbi->s_kobj, "feature_list"); + if (err) + goto put_feature_list_kobj; + if (f2fs_proc_root) sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); @@ -1113,6 +1223,9 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) victim_bits_seq_show, sb); } return 0; +put_feature_list_kobj: + kobject_put(&sbi->s_feature_list_kobj); + wait_for_completion(&sbi->s_feature_list_kobj_unregister); put_stat_kobj: kobject_put(&sbi->s_stat_kobj); wait_for_completion(&sbi->s_stat_kobj_unregister); @@ -1135,6 +1248,9 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) kobject_del(&sbi->s_stat_kobj); kobject_put(&sbi->s_stat_kobj); wait_for_completion(&sbi->s_stat_kobj_unregister); + kobject_del(&sbi->s_feature_list_kobj); + kobject_put(&sbi->s_feature_list_kobj); + wait_for_completion(&sbi->s_feature_list_kobj_unregister); kobject_del(&sbi->s_kobj); kobject_put(&sbi->s_kobj); diff --git a/fs/io_uring.c b/fs/io_uring.c index e55b21fc0ab2..d94fb5835a20 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -465,7 +465,8 @@ struct io_ring_ctx { struct mm_struct *mm_account; /* ctx exit and cancelation */ - struct callback_head *exit_task_work; + struct llist_head fallback_llist; + struct delayed_work fallback_work; struct work_struct exit_work; struct list_head tctx_list; struct completion ref_comp; @@ -784,9 +785,14 @@ struct async_poll { struct io_poll_iocb *double_poll; }; +typedef void (*io_req_tw_func_t)(struct io_kiocb *req); + struct io_task_work { - struct io_wq_work_node node; - task_work_func_t func; + union { + struct io_wq_work_node node; + struct llist_node fallback_node; + }; + io_req_tw_func_t func; }; enum { @@ -849,10 +855,7 @@ struct io_kiocb { /* used with ctx->iopoll_list with reads/writes */ struct list_head inflight_entry; - union { - struct io_task_work io_task_work; - struct callback_head task_work; - }; + struct io_task_work io_task_work; /* for polled requests, i.e. IORING_OP_POLL_ADD and async armed poll */ struct hlist_node hash_node; struct async_poll *apoll; @@ -1071,6 +1074,8 @@ static void io_submit_flush_completions(struct io_ring_ctx *ctx); static bool io_poll_remove_waitqs(struct io_kiocb *req); static int io_req_prep_async(struct io_kiocb *req); +static void io_fallback_req_func(struct work_struct *unused); + static struct kmem_cache *req_cachep; static const struct file_operations io_uring_fops; @@ -1202,6 +1207,7 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p) INIT_LIST_HEAD(&ctx->tctx_list); INIT_LIST_HEAD(&ctx->submit_state.comp.free_list); INIT_LIST_HEAD(&ctx->locked_free_list); + INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func); return ctx; err: kfree(ctx->dummy_ubuf); @@ -1929,7 +1935,7 @@ static void tctx_task_work(struct callback_head *cb) ctx = req->ctx; percpu_ref_get(&ctx->refs); } - req->task_work.func(&req->task_work); + req->io_task_work.func(req); node = next; } if (wq_list_empty(&tctx->task_list)) { @@ -1946,17 +1952,13 @@ static void tctx_task_work(struct callback_head *cb) ctx_flush_and_put(ctx); } -static int io_req_task_work_add(struct io_kiocb *req) +static void io_req_task_work_add(struct io_kiocb *req) { struct task_struct *tsk = req->task; struct io_uring_task *tctx = tsk->io_uring; enum task_work_notify_mode notify; - struct io_wq_work_node *node, *prev; + struct io_wq_work_node *node; unsigned long flags; - int ret = 0; - - if (unlikely(tsk->flags & PF_EXITING)) - return -ESRCH; WARN_ON_ONCE(!tctx); @@ -1967,7 +1969,9 @@ static int io_req_task_work_add(struct io_kiocb *req) /* task_work already pending, we're done */ if (test_bit(0, &tctx->task_state) || test_and_set_bit(0, &tctx->task_state)) - return 0; + return; + if (unlikely(tsk->flags & PF_EXITING)) + goto fail; /* * SQPOLL kernel thread doesn't need notification, just a wakeup. For @@ -1976,72 +1980,28 @@ static int io_req_task_work_add(struct io_kiocb *req) * will do the job. */ notify = (req->ctx->flags & IORING_SETUP_SQPOLL) ? TWA_NONE : TWA_SIGNAL; - if (!task_work_add(tsk, &tctx->task_work, notify)) { wake_up_process(tsk); - return 0; + return; } - - /* - * Slow path - we failed, find and delete work. if the work is not - * in the list, it got run and we're fine. - */ - spin_lock_irqsave(&tctx->task_lock, flags); - wq_list_for_each(node, prev, &tctx->task_list) { - if (&req->io_task_work.node == node) { - wq_list_del(&tctx->task_list, node, prev); - ret = 1; - break; - } - } - spin_unlock_irqrestore(&tctx->task_lock, flags); +fail: clear_bit(0, &tctx->task_state); - return ret; + spin_lock_irqsave(&tctx->task_lock, flags); + node = tctx->task_list.first; + INIT_WQ_LIST(&tctx->task_list); + spin_unlock_irqrestore(&tctx->task_lock, flags); + + while (node) { + req = container_of(node, struct io_kiocb, io_task_work.node); + node = node->next; + if (llist_add(&req->io_task_work.fallback_node, + &req->ctx->fallback_llist)) + schedule_delayed_work(&req->ctx->fallback_work, 1); + } } -static bool io_run_task_work_head(struct callback_head **work_head) +static void io_req_task_cancel(struct io_kiocb *req) { - struct callback_head *work, *next; - bool executed = false; - - do { - work = xchg(work_head, NULL); - if (!work) - break; - - do { - next = work->next; - work->func(work); - work = next; - cond_resched(); - } while (work); - executed = true; - } while (1); - - return executed; -} - -static void io_task_work_add_head(struct callback_head **work_head, - struct callback_head *task_work) -{ - struct callback_head *head; - - do { - head = READ_ONCE(*work_head); - task_work->next = head; - } while (cmpxchg(work_head, head, task_work) != head); -} - -static void io_req_task_work_add_fallback(struct io_kiocb *req, - task_work_func_t cb) -{ - init_task_work(&req->task_work, cb); - io_task_work_add_head(&req->ctx->exit_task_work, &req->task_work); -} - -static void io_req_task_cancel(struct callback_head *cb) -{ - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); struct io_ring_ctx *ctx = req->ctx; /* ctx is guaranteed to stay alive while we hold uring_lock */ @@ -2050,7 +2010,7 @@ static void io_req_task_cancel(struct callback_head *cb) mutex_unlock(&ctx->uring_lock); } -static void __io_req_task_submit(struct io_kiocb *req) +static void io_req_task_submit(struct io_kiocb *req) { struct io_ring_ctx *ctx = req->ctx; @@ -2063,28 +2023,17 @@ static void __io_req_task_submit(struct io_kiocb *req) mutex_unlock(&ctx->uring_lock); } -static void io_req_task_submit(struct callback_head *cb) -{ - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); - - __io_req_task_submit(req); -} - static void io_req_task_queue_fail(struct io_kiocb *req, int ret) { req->result = ret; - req->task_work.func = io_req_task_cancel; - - if (unlikely(io_req_task_work_add(req))) - io_req_task_work_add_fallback(req, io_req_task_cancel); + req->io_task_work.func = io_req_task_cancel; + io_req_task_work_add(req); } static void io_req_task_queue(struct io_kiocb *req) { - req->task_work.func = io_req_task_submit; - - if (unlikely(io_req_task_work_add(req))) - io_req_task_queue_fail(req, -ECANCELED); + req->io_task_work.func = io_req_task_submit; + io_req_task_work_add(req); } static inline void io_queue_next(struct io_kiocb *req) @@ -2195,18 +2144,10 @@ static inline void io_put_req(struct io_kiocb *req) io_free_req(req); } -static void io_put_req_deferred_cb(struct callback_head *cb) -{ - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); - - io_free_req(req); -} - static void io_free_req_deferred(struct io_kiocb *req) { - req->task_work.func = io_put_req_deferred_cb; - if (unlikely(io_req_task_work_add(req))) - io_req_task_work_add_fallback(req, io_put_req_deferred_cb); + req->io_task_work.func = io_free_req; + io_req_task_work_add(req); } static inline void io_put_req_deferred(struct io_kiocb *req, int refs) @@ -2415,11 +2356,15 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min) * very same mutex. */ if (list_empty(&ctx->iopoll_list)) { + u32 tail = ctx->cached_cq_tail; + mutex_unlock(&ctx->uring_lock); io_run_task_work(); mutex_lock(&ctx->uring_lock); - if (list_empty(&ctx->iopoll_list)) + /* some requests don't go through iopoll_list */ + if (tail != ctx->cached_cq_tail || + list_empty(&ctx->iopoll_list)) break; } ret = io_do_iopoll(ctx, &nr_events, min); @@ -2485,6 +2430,17 @@ static bool io_rw_should_reissue(struct io_kiocb *req) } #endif +static void io_fallback_req_func(struct work_struct *work) +{ + struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, + fallback_work.work); + struct llist_node *node = llist_del_all(&ctx->fallback_llist); + struct io_kiocb *req, *tmp; + + llist_for_each_entry_safe(req, tmp, node, io_task_work.fallback_node) + req->io_task_work.func(req); +} + static void __io_complete_rw(struct io_kiocb *req, long res, long res2, unsigned int issue_flags) { @@ -4850,10 +4806,8 @@ struct io_poll_table { }; static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll, - __poll_t mask, task_work_func_t func) + __poll_t mask, io_req_tw_func_t func) { - int ret; - /* for instances that support it check for an event match first: */ if (mask && !(mask & poll->events)) return 0; @@ -4863,7 +4817,7 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll, list_del_init(&poll->wait.entry); req->result = mask; - req->task_work.func = func; + req->io_task_work.func = func; /* * If this fails, then the task is exiting. When a task exits, the @@ -4871,11 +4825,7 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll, * of executing it. We can't safely execute it anyway, as we may not * have the needed state needed for it anyway. */ - ret = io_req_task_work_add(req); - if (unlikely(ret)) { - WRITE_ONCE(poll->canceled, true); - io_req_task_work_add_fallback(req, func); - } + io_req_task_work_add(req); return 1; } @@ -4884,6 +4834,9 @@ static bool io_poll_rewait(struct io_kiocb *req, struct io_poll_iocb *poll) { struct io_ring_ctx *ctx = req->ctx; + if (unlikely(req->task->flags & PF_EXITING)) + WRITE_ONCE(poll->canceled, true); + if (!req->result && !READ_ONCE(poll->canceled)) { struct poll_table_struct pt = { ._key = poll->events }; @@ -4960,9 +4913,8 @@ static bool io_poll_complete(struct io_kiocb *req, __poll_t mask) return !(flags & IORING_CQE_F_MORE); } -static void io_poll_task_func(struct callback_head *cb) +static void io_poll_task_func(struct io_kiocb *req) { - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); struct io_ring_ctx *ctx = req->ctx; struct io_kiocb *nxt; @@ -4984,7 +4936,7 @@ static void io_poll_task_func(struct callback_head *cb) if (done) { nxt = io_put_req_find_next(req); if (nxt) - __io_req_task_submit(nxt); + io_req_task_submit(nxt); } } } @@ -5004,7 +4956,7 @@ static int io_poll_double_wake(struct wait_queue_entry *wait, unsigned mode, list_del_init(&wait->entry); - if (poll && poll->head) { + if (poll->head) { bool done; spin_lock(&poll->head->lock); @@ -5093,9 +5045,8 @@ static void io_async_queue_proc(struct file *file, struct wait_queue_head *head, __io_queue_proc(&apoll->poll, pt, head, &apoll->double_poll); } -static void io_async_task_func(struct callback_head *cb) +static void io_async_task_func(struct io_kiocb *req) { - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); struct async_poll *apoll = req->apoll; struct io_ring_ctx *ctx = req->ctx; @@ -5111,7 +5062,7 @@ static void io_async_task_func(struct callback_head *cb) spin_unlock_irq(&ctx->completion_lock); if (!READ_ONCE(apoll->poll.canceled)) - __io_req_task_submit(req); + io_req_task_submit(req); else io_req_complete_failed(req, -ECANCELED); } @@ -6072,7 +6023,7 @@ static bool io_drain_req(struct io_kiocb *req) io_prep_async_link(req); de = kmalloc(sizeof(*de), GFP_KERNEL); if (!de) { - io_req_complete_failed(req, ret); + io_req_complete_failed(req, -ENOMEM); return true; } @@ -8767,11 +8718,6 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id) return -EINVAL; } -static inline bool io_run_ctx_fallback(struct io_ring_ctx *ctx) -{ - return io_run_task_work_head(&ctx->exit_task_work); -} - struct io_tctx_exit { struct callback_head task_work; struct completion completion; @@ -8837,7 +8783,7 @@ static void io_ring_exit_work(struct work_struct *work) /* * Some may use context even when all refs and requests have been put, * and they are free to do so while still holding uring_lock or - * completion_lock, see __io_req_task_submit(). Apart from other work, + * completion_lock, see io_req_task_submit(). Apart from other work, * this lock/unlock section also waits them to finish. */ mutex_lock(&ctx->uring_lock); @@ -9036,7 +8982,6 @@ static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx, ret |= io_kill_timeouts(ctx, task, cancel_all); if (task) ret |= io_run_task_work(); - ret |= io_run_ctx_fallback(ctx); if (!ret) break; cond_resched(); diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 51d1eb2ffeb9..746132998c57 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -701,7 +701,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh) __buffer_unlink(jh); jh->b_cp_transaction = NULL; - percpu_counter_dec(&journal->j_jh_shrink_count); + percpu_counter_dec(&journal->j_checkpoint_jh_count); jbd2_journal_put_journal_head(jh); /* Is this transaction empty? */ @@ -764,7 +764,7 @@ void __jbd2_journal_insert_checkpoint(struct journal_head *jh, jh->b_cpnext->b_cpprev = jh; } transaction->t_checkpoint_list = jh; - percpu_counter_inc(&transaction->t_journal->j_jh_shrink_count); + percpu_counter_inc(&transaction->t_journal->j_checkpoint_jh_count); } /* diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 152880c298ca..35302bc192eb 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1283,6 +1283,48 @@ static int jbd2_min_tag_size(void) return sizeof(journal_block_tag_t) - 4; } +/** + * jbd2_journal_shrink_scan() + * + * Scan the checkpointed buffer on the checkpoint list and release the + * journal_head. + */ +static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink, + struct shrink_control *sc) +{ + journal_t *journal = container_of(shrink, journal_t, j_shrinker); + unsigned long nr_to_scan = sc->nr_to_scan; + unsigned long nr_shrunk; + unsigned long count; + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count); + + nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan); + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count); + + return nr_shrunk; +} + +/** + * jbd2_journal_shrink_count() + * + * Count the number of checkpoint buffers on the checkpoint list. + */ +static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) +{ + journal_t *journal = container_of(shrink, journal_t, j_shrinker); + unsigned long count; + + count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count); + trace_jbd2_shrink_count(journal, sc->nr_to_scan, count); + + return count; +} + /* * Management for journal control blocks: functions to create and * destroy journal_t structures, and to initialise and read existing @@ -1361,9 +1403,23 @@ static journal_t *journal_init_common(struct block_device *bdev, journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; + journal->j_shrink_transaction = NULL; + journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan; + journal->j_shrinker.count_objects = jbd2_journal_shrink_count; + journal->j_shrinker.seeks = DEFAULT_SEEKS; + journal->j_shrinker.batch = journal->j_max_transaction_buffers; + + if (percpu_counter_init(&journal->j_checkpoint_jh_count, 0, GFP_KERNEL)) + goto err_cleanup; + + if (register_shrinker(&journal->j_shrinker)) { + percpu_counter_destroy(&journal->j_checkpoint_jh_count); + goto err_cleanup; + } return journal; err_cleanup: + brelse(journal->j_sb_buffer); kfree(journal->j_wbuf); jbd2_journal_destroy_revoke(journal); kfree(journal); @@ -2050,93 +2106,6 @@ recovery_error: return -EIO; } -/** - * jbd2_journal_shrink_scan() - * - * Scan the checkpointed buffer on the checkpoint list and release the - * journal_head. - */ -static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - journal_t *journal = container_of(shrink, journal_t, j_shrinker); - unsigned long nr_to_scan = sc->nr_to_scan; - unsigned long nr_shrunk; - unsigned long count; - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_scan_enter(journal, sc->nr_to_scan, count); - - nr_shrunk = jbd2_journal_shrink_checkpoint_list(journal, &nr_to_scan); - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_scan_exit(journal, nr_to_scan, nr_shrunk, count); - - return nr_shrunk; -} - -/** - * jbd2_journal_shrink_count() - * - * Count the number of checkpoint buffers on the checkpoint list. - */ -static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - journal_t *journal = container_of(shrink, journal_t, j_shrinker); - unsigned long count; - - count = percpu_counter_read_positive(&journal->j_jh_shrink_count); - trace_jbd2_shrink_count(journal, sc->nr_to_scan, count); - - return count; -} - -/** - * jbd2_journal_register_shrinker() - * @journal: Journal to act on. - * - * Init a percpu counter to record the checkpointed buffers on the checkpoint - * list and register a shrinker to release their journal_head. - */ -int jbd2_journal_register_shrinker(journal_t *journal) -{ - int err; - - journal->j_shrink_transaction = NULL; - - err = percpu_counter_init(&journal->j_jh_shrink_count, 0, GFP_KERNEL); - if (err) - return err; - - journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan; - journal->j_shrinker.count_objects = jbd2_journal_shrink_count; - journal->j_shrinker.seeks = DEFAULT_SEEKS; - journal->j_shrinker.batch = journal->j_max_transaction_buffers; - - err = register_shrinker(&journal->j_shrinker); - if (err) { - percpu_counter_destroy(&journal->j_jh_shrink_count); - return err; - } - - return 0; -} -EXPORT_SYMBOL(jbd2_journal_register_shrinker); - -/** - * jbd2_journal_unregister_shrinker() - * @journal: Journal to act on. - * - * Unregister the checkpointed buffer shrinker and destroy the percpu counter. - */ -void jbd2_journal_unregister_shrinker(journal_t *journal) -{ - percpu_counter_destroy(&journal->j_jh_shrink_count); - unregister_shrinker(&journal->j_shrinker); -} -EXPORT_SYMBOL(jbd2_journal_unregister_shrinker); - /** * jbd2_journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. @@ -2209,8 +2178,10 @@ int jbd2_journal_destroy(journal_t *journal) brelse(journal->j_sb_buffer); } - jbd2_journal_unregister_shrinker(journal); - + if (journal->j_shrinker.flags & SHRINKER_REGISTERED) { + percpu_counter_destroy(&journal->j_checkpoint_jh_count); + unregister_shrinker(&journal->j_shrinker); + } if (journal->j_proc_entry) jbd2_stats_proc_exit(journal); iput(journal->j_inode); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1a639e34847d..2de048f80eb8 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -766,6 +766,46 @@ static void __exit exit_nlm(void) module_init(init_nlm); module_exit(exit_nlm); +/** + * nlmsvc_dispatch - Process an NLM Request + * @rqstp: incoming request + * @statp: pointer to location of accept_stat field in RPC Reply buffer + * + * Return values: + * %0: Processing complete; do not send a Reply + * %1: Processing complete; send Reply in rqstp->rq_res + */ +static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) +{ + const struct svc_procedure *procp = rqstp->rq_procinfo; + struct kvec *argv = rqstp->rq_arg.head; + struct kvec *resv = rqstp->rq_res.head; + + svcxdr_init_decode(rqstp); + if (!procp->pc_decode(rqstp, argv->iov_base)) + goto out_decode_err; + + *statp = procp->pc_func(rqstp); + if (*statp == rpc_drop_reply) + return 0; + if (*statp != rpc_success) + return 1; + + svcxdr_init_encode(rqstp); + if (!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) + goto out_encode_err; + + return 1; + +out_decode_err: + *statp = rpc_garbage_args; + return 1; + +out_encode_err: + *statp = rpc_system_err; + return 1; +} + /* * Define NLM program and procedures */ @@ -775,6 +815,7 @@ static const struct svc_version nlmsvc_version1 = { .vs_nproc = 17, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version1_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; static unsigned int nlmsvc_version3_count[24]; @@ -783,6 +824,7 @@ static const struct svc_version nlmsvc_version3 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version3_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #ifdef CONFIG_LOCKD_V4 @@ -792,6 +834,7 @@ static const struct svc_version nlmsvc_version4 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures4, .vs_count = nlmsvc_version4_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #endif diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h new file mode 100644 index 000000000000..c69a0bb76c94 --- /dev/null +++ b/fs/lockd/svcxdr.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Encode/decode NLM basic data types + * + * Basic NLMv3 XDR data types are not defined in an IETF standards + * document. X/Open has a description of these data types that + * is useful. See Chapter 10 of "Protocols for Interworking: + * XNFS, Version 3W". + * + * Basic NLMv4 XDR data types are defined in Appendix II.1.4 of + * RFC 1813: "NFS Version 3 Protocol Specification". + * + * Author: Chuck Lever + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#ifndef _LOCKD_SVCXDR_H_ +#define _LOCKD_SVCXDR_H_ + +static inline bool +svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status) +{ + __be32 *p; + + p = xdr_inline_decode(xdr, XDR_UNIT); + if (!p) + return false; + *status = *p; + + return true; +} + +static inline bool +svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT); + if (!p) + return false; + *p = status; + + return true; +} + +static inline bool +svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXSTRLEN) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + *data_len = len; + *data = (char *)p; + + return true; +} + +/* + * NLM cookies are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to 32 bytes, and treats zero-length cookies + * specially. + */ +static inline bool +svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXCOOKIELEN) + return false; + if (!len) + goto out_hpux; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + cookie->len = len; + memcpy(cookie->data, p, len); + + return true; + + /* apparently HPUX can return empty cookies */ +out_hpux: + cookie->len = 4; + memset(cookie->data, 0, 4); + return true; +} + +static inline bool +svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) +{ + __be32 *p; + + if (xdr_stream_encode_u32(xdr, cookie->len) < 0) + return false; + p = xdr_reserve_space(xdr, cookie->len); + if (!p) + return false; + memcpy(p, cookie->data, cookie->len); + + return true; +} + +static inline bool +svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > XDR_MAX_NETOBJ) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + obj->len = len; + obj->data = (u8 *)p; + + return true; +} + +static inline bool +svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) +{ + unsigned int quadlen = XDR_QUADLEN(obj->len); + __be32 *p; + + if (xdr_stream_encode_u32(xdr, obj->len) < 0) + return false; + p = xdr_reserve_space(xdr, obj->len); + if (!p) + return false; + p[quadlen - 1] = 0; /* XDR pad */ + memcpy(p, obj->data, obj->len); + + return true; +} + +#endif /* _LOCKD_SVCXDR_H_ */ diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 982629f7b120..9235e60b1769 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -19,7 +19,7 @@ #include -#define NLMDBG_FACILITY NLMDBG_XDR +#include "svcxdr.h" static inline loff_t @@ -42,311 +42,323 @@ loff_t_to_s32(loff_t offset) } /* - * XDR functions for basic NLM types + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * constrains their length to exactly the length of an NFSv2 file + * handle. */ -static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) { - unsigned int len; + __be32 *p; + u32 len; - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len != NFS2_FHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = NFS2_FHSIZE; + memcpy(fh->data, p, len); + memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE); + + return true; } -static inline __be32 * -nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} + struct file_lock *fl = &lock->fl; + s32 start, len, end; -static __be32 * -nlm_decode_fh(__be32 *p, struct nfs_fh *f) -{ - unsigned int len; - - if ((len = ntohl(*p++)) != NFS2_FHSIZE) { - dprintk("lockd: bad fhandle size %d (should be %d)\n", - len, NFS2_FHSIZE); - return NULL; - } - f->size = NFS2_FHSIZE; - memset(f->data, 0, sizeof(f->data)); - memcpy(f->data, p, NFS2_FHSIZE); - return p + XDR_QUADLEN(NFS2_FHSIZE); -} - -/* - * Encode and decode owner handle - */ -static inline __be32 * -nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_decode_netobj(p, oh); -} - -static inline __be32 * -nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_encode_netobj(p, oh); -} - -static __be32 * -nlm_decode_lock(__be32 *p, struct nlm_lock *lock) -{ - struct file_lock *fl = &lock->fl; - s32 start, len, end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, - NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &start) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; locks_init_lock(fl); fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - start = ntohl(*p++); - len = ntohl(*p++); + fl->fl_type = F_RDLCK; end = start + len - 1; - fl->fl_start = s32_to_loff_t(start); - if (len == 0 || end < 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = s32_to_loff_t(end); - return p; + + return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) { - s32 start, len; + const struct file_lock *fl = &lock->fl; + s32 start, len; - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s32(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; + else + len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u32(xdr, start) < 0) + return false; + if (xdr_stream_encode_u32(xdr, len) < 0) + return false; - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; + return true; +} - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; - - start = loff_t_to_s32(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); - - *p++ = htonl(start); - *p++ = htonl(len); +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) +{ + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - return p; + return true; } /* - * First, the server side XDR functions + * Decode Call arguments */ + +int +nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); -} - -int -nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return 1; } int nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; argp->monitor = 1; /* monitor client by default */ - return xdr_argsize_check(rqstp, p); + return 1; } int nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + + return 1; } int nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = nlm_decode_lock(p, &argp->lock))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); -} -int -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - -int -nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); -} - -int -nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); -} - -int -nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - -int -nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); + return 1; } int nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_res *resp = rqstp->rq_argp; - if (!(p = nlm_decode_cookie(p, &resp->cookie))) + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_stats(xdr, &resp->status)) + return 0; + + return 1; } int -nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) { - return xdr_argsize_check(rqstp, p); + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return 0; + if (len > SM_MAXSTRLEN) + return 0; + p = xdr_inline_decode(xdr, len); + if (!p) + return 0; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return 0; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + + return 1; } +int +nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return 0; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return 0; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return 0; + + return 1; +} + +int +nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + + return 1; +} + + +/* + * Encode Reply results + */ + int nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) { - return xdr_ressize_check(rqstp, p); + return 1; +} + +int +nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); +} + +int +nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); +} + +int +nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return 0; + if (!svcxdr_encode_stats(xdr, resp->status)) + return 0; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return 0; + + return 1; } diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 5fa9f48a9dba..98e957e4566c 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -18,7 +18,7 @@ #include #include -#define NLMDBG_FACILITY NLMDBG_XDR +#include "svcxdr.h" static inline loff_t s64_to_loff_t(__s64 offset) @@ -41,309 +41,322 @@ loff_t_to_s64(loff_t offset) } /* - * XDR functions for basic NLM types + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to the size of an NFSv3 file handle. */ -static __be32 * -nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) { - unsigned int len; + __be32 *p; + u32 len; - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NFS_MAXFHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = len; + memcpy(fh->data, p, len); + memset(fh->data + len, 0, sizeof(fh->data) - len); + + return true; } -static __be32 * -nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} + struct file_lock *fl = &lock->fl; + u64 len, start; + s64 end; -static __be32 * -nlm4_decode_fh(__be32 *p, struct nfs_fh *f) -{ - memset(f->data, 0, sizeof(f->data)); - f->size = ntohl(*p++); - if (f->size > NFS_MAXFHSIZE) { - dprintk("lockd: bad fhandle size %d (should be <=%d)\n", - f->size, NFS_MAXFHSIZE); - return NULL; - } - memcpy(f->data, p, f->size); - return p + XDR_QUADLEN(f->size); -} - -/* - * Encode and decode owner handle - */ -static __be32 * -nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_decode_netobj(p, oh); -} - -static __be32 * -nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) -{ - struct file_lock *fl = &lock->fl; - __u64 len, start; - __s64 end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &start) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &len) < 0) + return false; locks_init_lock(fl); fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - p = xdr_decode_hyper(p, &start); - p = xdr_decode_hyper(p, &len); + fl->fl_type = F_RDLCK; end = start + len - 1; - fl->fl_start = s64_to_loff_t(start); - if (len == 0 || end < 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = s64_to_loff_t(end); - return p; + + return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm4_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) { - s64 start, len; + const struct file_lock *fl = &lock->fl; + s64 start, len; - dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s64(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; + else + len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u64(xdr, start) < 0) + return false; + if (xdr_stream_encode_u64(xdr, len) < 0) + return false; - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; + return true; +} - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; - - start = loff_t_to_s64(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); - - p = xdr_encode_hyper(p, start); - p = xdr_encode_hyper(p, len); - dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n", - resp->status, (int)resp->lock.svid, fl->fl_type, - (long long)fl->fl_start, (long long)fl->fl_end); +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) +{ + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); - return p; + return true; } /* - * First, the server side XDR functions + * Decode Call arguments */ + +int +nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); -} - -int -nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm4_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return 1; } int nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; argp->monitor = 1; /* monitor client by default */ - return xdr_argsize_check(rqstp, p); + return 1; } int nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + return 1; } int nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = nlm4_decode_lock(p, &argp->lock))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); -} -int -nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - -int -nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); -} - -int -nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); -} - -int -nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - -int -nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); + return 1; } int nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_res *resp = rqstp->rq_argp; - if (!(p = nlm4_decode_cookie(p, &resp->cookie))) + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_stats(xdr, &resp->status)) + return 0; + + return 1; } int -nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) +nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) { - return xdr_argsize_check(rqstp, p); + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return 0; + if (len > SM_MAXSTRLEN) + return 0; + p = xdr_inline_decode(xdr, len); + if (!p) + return 0; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return 0; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + + return 1; } +int +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return 0; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return 0; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return 0; + + return 1; +} + +int +nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + + return 1; +} + + +/* + * Encode Reply results + */ + int nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) { - return xdr_ressize_check(rqstp, p); + return 1; +} + +int +nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); +} + +int +nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); +} + +int +nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return 0; + if (!svcxdr_encode_stats(xdr, resp->status)) + return 0; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return 0; + + return 1; } diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index e6ec6f09ac6e..11118398f495 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -75,6 +75,13 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); } +static void nfs_mark_return_delegation(struct nfs_server *server, + struct nfs_delegation *delegation) +{ + set_bit(NFS_DELEGATION_RETURN, &delegation->flags); + set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); +} + static bool nfs4_is_valid_delegation(const struct nfs_delegation *delegation, fmode_t flags) @@ -293,6 +300,7 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi) goto out; spin_lock(&delegation->lock); if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { + clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags); /* Refcount matched in nfs_end_delegation_return() */ ret = nfs_get_delegation(delegation); } @@ -314,16 +322,17 @@ nfs_start_delegation_return(struct nfs_inode *nfsi) return delegation; } -static void -nfs_abort_delegation_return(struct nfs_delegation *delegation, - struct nfs_client *clp) +static void nfs_abort_delegation_return(struct nfs_delegation *delegation, + struct nfs_client *clp, int err) { spin_lock(&delegation->lock); clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags); - set_bit(NFS_DELEGATION_RETURN, &delegation->flags); + if (err == -EAGAIN) { + set_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags); + set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state); + } spin_unlock(&delegation->lock); - set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); } static struct nfs_delegation * @@ -521,11 +530,18 @@ out: static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync) { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; + unsigned int mode = O_WRONLY | O_RDWR; int err = 0; if (delegation == NULL) return 0; - do { + + if (!issync) + mode |= O_NONBLOCK; + /* Recall of any remaining application leases */ + err = break_lease(inode, mode); + + while (err == 0) { if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) break; err = nfs_delegation_claim_opens(inode, &delegation->stateid, @@ -536,10 +552,10 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation * Guard against state recovery */ err = nfs4_wait_clnt_recover(clp); - } while (err == 0); + } if (err) { - nfs_abort_delegation_return(delegation, clp); + nfs_abort_delegation_return(delegation, clp, err); goto out; } @@ -568,6 +584,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation) if (ret) clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags); if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) || + test_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags) || test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) ret = false; @@ -647,6 +664,38 @@ out: return err; } +static bool nfs_server_clear_delayed_delegations(struct nfs_server *server) +{ + struct nfs_delegation *d; + bool ret = false; + + list_for_each_entry_rcu (d, &server->delegations, super_list) { + if (!test_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags)) + continue; + nfs_mark_return_delegation(server, d); + clear_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags); + ret = true; + } + return ret; +} + +static bool nfs_client_clear_delayed_delegations(struct nfs_client *clp) +{ + struct nfs_server *server; + bool ret = false; + + if (!test_and_clear_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state)) + goto out; + rcu_read_lock(); + list_for_each_entry_rcu (server, &clp->cl_superblocks, client_link) { + if (nfs_server_clear_delayed_delegations(server)) + ret = true; + } + rcu_read_unlock(); +out: + return ret; +} + /** * nfs_client_return_marked_delegations - return previously marked delegations * @clp: nfs_client to process @@ -659,8 +708,14 @@ out: */ int nfs_client_return_marked_delegations(struct nfs_client *clp) { - return nfs_client_for_each_server(clp, - nfs_server_return_marked_delegations, NULL); + int err = nfs_client_for_each_server( + clp, nfs_server_return_marked_delegations, NULL); + if (err) + return err; + /* If a return was delayed, sleep to prevent hard looping */ + if (nfs_client_clear_delayed_delegations(clp)) + ssleep(1); + return 0; } /** @@ -698,13 +753,14 @@ int nfs4_inode_return_delegation(struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; - int err = 0; - nfs_wb_all(inode); delegation = nfs_start_delegation_return(nfsi); + /* Synchronous recall of any application leases */ + break_lease(inode, O_WRONLY | O_RDWR); + nfs_wb_all(inode); if (delegation != NULL) - err = nfs_end_delegation_return(inode, delegation, 1); - return err; + return nfs_end_delegation_return(inode, delegation, 1); + return 0; } /** @@ -775,13 +831,6 @@ static void nfs_mark_return_if_closed_delegation(struct nfs_server *server, set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); } -static void nfs_mark_return_delegation(struct nfs_server *server, - struct nfs_delegation *delegation) -{ - set_bit(NFS_DELEGATION_RETURN, &delegation->flags); - set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); -} - static bool nfs_server_mark_return_all_delegations(struct nfs_server *server) { struct nfs_delegation *delegation; @@ -1010,6 +1059,9 @@ int nfs_async_inode_return_delegation(struct inode *inode, nfs_mark_return_delegation(server, delegation); rcu_read_unlock(); + /* If there are any application leases or delegations, recall them */ + break_lease(inode, O_WRONLY | O_RDWR | O_NONBLOCK); + nfs_delegation_run_state_manager(clp); return 0; out_enoent: diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index c19b4fd20781..1c378992b7c0 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -36,6 +36,7 @@ enum { NFS_DELEGATION_REVOKED, NFS_DELEGATION_TEST_EXPIRED, NFS_DELEGATION_INODE_FREEING, + NFS_DELEGATION_RETURN_DELAYED, }; int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 2d30a4da49fa..2e894fec036b 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -700,8 +700,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) { struct nfs_direct_req *dreq = hdr->dreq; struct nfs_commit_info cinfo; - bool request_commit = false; struct nfs_page *req = nfs_list_entry(hdr->pages.next); + int flags = NFS_ODIRECT_DONE; nfs_init_cinfo_from_dreq(&cinfo, dreq); @@ -713,15 +713,9 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) nfs_direct_count_bytes(dreq, hdr); if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) { - switch (dreq->flags) { - case 0: + if (!dreq->flags) dreq->flags = NFS_ODIRECT_DO_COMMIT; - request_commit = true; - break; - case NFS_ODIRECT_RESCHED_WRITES: - case NFS_ODIRECT_DO_COMMIT: - request_commit = true; - } + flags = dreq->flags; } spin_unlock(&dreq->lock); @@ -729,12 +723,15 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) req = nfs_list_entry(hdr->pages.next); nfs_list_remove_request(req); - if (request_commit) { + if (flags == NFS_ODIRECT_DO_COMMIT) { kref_get(&req->wb_kref); memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); nfs_mark_request_commit(req, hdr->lseg, &cinfo, hdr->ds_commit_idx); + } else if (flags == NFS_ODIRECT_RESCHED_WRITES) { + kref_get(&req->wb_kref); + nfs_mark_request_commit(req, NULL, &cinfo, 0); } nfs_unlock_and_release_request(req); } diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index c4c021c6ebbd..d743629e05e1 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c @@ -385,12 +385,15 @@ static void nfs_readpage_from_fscache_complete(struct page *page, "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n", page, context, error); - /* if the read completes with an error, we just unlock the page and let - * the VM reissue the readpage */ - if (!error) { + /* + * If the read completes with an error, mark the page with PG_checked, + * unlock the page, and let the VM reissue the readpage. + */ + if (!error) SetPageUptodate(page); - unlock_page(page); - } + else + SetPageChecked(page); + unlock_page(page); } /* @@ -405,6 +408,11 @@ int __nfs_readpage_from_fscache(struct nfs_open_context *ctx, "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n", nfs_i_fscache(inode), page, page->index, page->flags, inode); + if (PageChecked(page)) { + ClearPageChecked(page); + return 1; + } + ret = fscache_read_or_alloc_page(nfs_i_fscache(inode), page, nfs_readpage_from_fscache_complete, diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index aaeeb4659bff..59355c106ece 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -67,7 +67,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i int nfs_get_root(struct super_block *s, struct fs_context *fc) { struct nfs_fs_context *ctx = nfs_fc2context(fc); - struct nfs_server *server = NFS_SB(s); + struct nfs_server *server = NFS_SB(s), *clone_server; struct nfs_fsinfo fsinfo; struct dentry *root; struct inode *inode; @@ -127,7 +127,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc) } spin_unlock(&root->d_lock); fc->root = root; - if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) + if (server->caps & NFS_CAP_SECURITY_LABEL) kflags |= SECURITY_LSM_NATIVE_LABELS; if (ctx->clone_data.sb) { if (d_inode(fc->root)->i_fop != &nfs_dir_operations) { @@ -137,15 +137,19 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc) /* clone lsm security options from the parent to the new sb */ error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags, &kflags_out); + if (error) + goto error_splat_root; + clone_server = NFS_SB(ctx->clone_data.sb); + server->has_sec_mnt_opts = clone_server->has_sec_mnt_opts; } else { error = security_sb_set_mnt_opts(s, fc->security, kflags, &kflags_out); } if (error) goto error_splat_root; - if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && + if (server->caps & NFS_CAP_SECURITY_LABEL && !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) - NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; + server->caps &= ~NFS_CAP_SECURITY_LABEL; nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label); error = 0; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 529c4099f482..853213b3a209 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1101,6 +1101,7 @@ EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) { filp->private_data = get_nfs_open_context(ctx); + set_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); if (list_empty(&ctx->list)) nfs_inode_attach_open_context(ctx); } @@ -1120,6 +1121,8 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct continue; if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) continue; + if (!test_bit(NFS_CONTEXT_FILE_OPEN, &pos->flags)) + continue; ctx = get_nfs_open_context(pos); if (ctx) break; @@ -1135,6 +1138,7 @@ void nfs_file_clear_open_context(struct file *filp) if (ctx) { struct inode *inode = d_inode(ctx->dentry); + clear_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); /* * We fatal error on write before. Try to writeback * every page again. @@ -2055,35 +2059,33 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | NFS_INO_INVALID_OTHER; if (S_ISDIR(inode->i_mode)) nfs_force_lookup_revalidate(inode); + attr_changed = true; dprintk("NFS: change_attr change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } else if (!have_delegation) nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER; inode_set_iversion_raw(inode, fattr->change_attr); - attr_changed = true; } } else { nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_CHANGE; - cache_revalidated = false; + if (!have_delegation || + (nfsi->cache_validity & NFS_INO_INVALID_CHANGE) != 0) + cache_revalidated = false; } - if (fattr->valid & NFS_ATTR_FATTR_MTIME) { + if (fattr->valid & NFS_ATTR_FATTR_MTIME) inode->i_mtime = fattr->mtime; - } else if (fattr_supported & NFS_ATTR_FATTR_MTIME) { + else if (fattr_supported & NFS_ATTR_FATTR_MTIME) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_MTIME; - cache_revalidated = false; - } - if (fattr->valid & NFS_ATTR_FATTR_CTIME) { + if (fattr->valid & NFS_ATTR_FATTR_CTIME) inode->i_ctime = fattr->ctime; - } else if (fattr_supported & NFS_ATTR_FATTR_CTIME) { + else if (fattr_supported & NFS_ATTR_FATTR_CTIME) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_CTIME; - cache_revalidated = false; - } /* Check if our cached file size is stale */ if (fattr->valid & NFS_ATTR_FATTR_SIZE) { @@ -2096,7 +2098,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) i_size_write(inode, new_isize); if (!have_writers) invalid |= NFS_INO_INVALID_DATA; - attr_changed = true; } dprintk("NFS: isize change on server for file %s/%ld " "(%Ld to %Ld)\n", @@ -2111,19 +2112,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) fattr->du.nfs3.used = 0; fattr->valid |= NFS_ATTR_FATTR_SPACE_USED; } - } else { + } else nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_SIZE; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_ATIME) inode->i_atime = fattr->atime; - else if (fattr_supported & NFS_ATTR_FATTR_ATIME) { + else if (fattr_supported & NFS_ATTR_FATTR_ATIME) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_ATIME; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_MODE) { if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { @@ -2132,71 +2129,55 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_mode = newmode; invalid |= NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; - attr_changed = true; } - } else if (fattr_supported & NFS_ATTR_FATTR_MODE) { + } else if (fattr_supported & NFS_ATTR_FATTR_MODE) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_MODE; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_OWNER) { if (!uid_eq(inode->i_uid, fattr->uid)) { invalid |= NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; inode->i_uid = fattr->uid; - attr_changed = true; } - } else if (fattr_supported & NFS_ATTR_FATTR_OWNER) { + } else if (fattr_supported & NFS_ATTR_FATTR_OWNER) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_OTHER; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_GROUP) { if (!gid_eq(inode->i_gid, fattr->gid)) { invalid |= NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; inode->i_gid = fattr->gid; - attr_changed = true; } - } else if (fattr_supported & NFS_ATTR_FATTR_GROUP) { + } else if (fattr_supported & NFS_ATTR_FATTR_GROUP) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_OTHER; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_NLINK) { if (inode->i_nlink != fattr->nlink) { if (S_ISDIR(inode->i_mode)) invalid |= NFS_INO_INVALID_DATA; set_nlink(inode, fattr->nlink); - attr_changed = true; } - } else if (fattr_supported & NFS_ATTR_FATTR_NLINK) { + } else if (fattr_supported & NFS_ATTR_FATTR_NLINK) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_NLINK; - cache_revalidated = false; - } if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { /* * report the blocks in 512byte units */ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); - } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED) { + } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_BLOCKS; - cache_revalidated = false; - } - if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) { + if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) inode->i_blocks = fattr->du.nfs2.blocks; - } else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED) { + else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_BLOCKS; - cache_revalidated = false; - } /* Update attrtimeo value if we're out of the unstable period */ if (attr_changed) { diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 5c4e23abc345..2299446b3b89 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -385,7 +385,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, break; case NFS3_CREATE_UNCHECKED: - goto out; + goto out_release_acls; } nfs_fattr_init(data->res.dir_attr); nfs_fattr_init(data->res.fattr); @@ -751,7 +751,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, break; default: status = -EINVAL; - goto out; + goto out_release_acls; } d_alias = nfs3_do_create(dir, dentry, data); diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 543d916f79ab..ba78df4b13d9 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -45,6 +45,7 @@ enum nfs4_client_state { NFS4CLNT_RECALL_RUNNING, NFS4CLNT_RECALL_ANY_LAYOUT_READ, NFS4CLNT_RECALL_ANY_LAYOUT_RW, + NFS4CLNT_DELEGRETURN_DELAYED, }; #define NFS4_RENEW_TIMEOUT 0x01 @@ -322,7 +323,8 @@ extern int update_open_stateid(struct nfs4_state *state, const nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode); - +extern int nfs4_proc_setlease(struct file *file, long arg, + struct file_lock **lease, void **priv); extern int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo); extern void nfs4_update_changeattr(struct inode *dir, diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 42719384e25f..28431acd1230 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -197,8 +197,11 @@ void nfs40_shutdown_client(struct nfs_client *clp) struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) { - int err; + char buf[INET6_ADDRSTRLEN + 1]; + const char *ip_addr = cl_init->ip_addr; struct nfs_client *clp = nfs_alloc_client(cl_init); + int err; + if (IS_ERR(clp)) return clp; @@ -222,6 +225,44 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) init_waitqueue_head(&clp->cl_lock_waitq); #endif INIT_LIST_HEAD(&clp->pending_cb_stateids); + + if (cl_init->minorversion != 0) + __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); + __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); + __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); + + /* + * Set up the connection to the server before we add add to the + * global list. + */ + err = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_GSS_KRB5I); + if (err == -EINVAL) + err = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX); + if (err < 0) + goto error; + + /* If no clientaddr= option was specified, find a usable cb address */ + if (ip_addr == NULL) { + struct sockaddr_storage cb_addr; + struct sockaddr *sap = (struct sockaddr *)&cb_addr; + + err = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); + if (err < 0) + goto error; + err = rpc_ntop(sap, buf, sizeof(buf)); + if (err < 0) + goto error; + ip_addr = (const char *)buf; + } + strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); + + err = nfs_idmap_new(clp); + if (err < 0) { + dprintk("%s: failed to create idmapper. Error = %d\n", + __func__, err); + goto error; + } + __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); return clp; error: @@ -372,8 +413,6 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) struct nfs_client *nfs4_init_client(struct nfs_client *clp, const struct nfs_client_initdata *cl_init) { - char buf[INET6_ADDRSTRLEN + 1]; - const char *ip_addr = cl_init->ip_addr; struct nfs_client *old; int error; @@ -381,43 +420,6 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, /* the client is initialised already */ return clp; - /* Check NFS protocol revision and initialize RPC op vector */ - clp->rpc_ops = &nfs_v4_clientops; - - if (clp->cl_minorversion != 0) - __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); - __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); - __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); - - error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_GSS_KRB5I); - if (error == -EINVAL) - error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX); - if (error < 0) - goto error; - - /* If no clientaddr= option was specified, find a usable cb address */ - if (ip_addr == NULL) { - struct sockaddr_storage cb_addr; - struct sockaddr *sap = (struct sockaddr *)&cb_addr; - - error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); - if (error < 0) - goto error; - error = rpc_ntop(sap, buf, sizeof(buf)); - if (error < 0) - goto error; - ip_addr = (const char *)buf; - } - strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); - - error = nfs_idmap_new(clp); - if (error < 0) { - dprintk("%s: failed to create idmapper. Error = %d\n", - __func__, error); - goto error; - } - __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); - error = nfs4_init_client_minor_version(clp); if (error < 0) goto error; diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index a1e5c6b85ded..c820de58a661 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -435,6 +435,12 @@ void nfs42_ssc_unregister_ops(void) } #endif /* CONFIG_NFS_V4_2 */ +static int nfs4_setlease(struct file *file, long arg, struct file_lock **lease, + void **priv) +{ + return nfs4_proc_setlease(file, arg, lease, priv); +} + const struct file_operations nfs4_file_operations = { .read_iter = nfs_file_read, .write_iter = nfs_file_write, @@ -448,7 +454,7 @@ const struct file_operations nfs4_file_operations = { .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .check_flags = nfs_check_flags, - .setlease = simple_nosetlease, + .setlease = nfs4_setlease, #ifdef CONFIG_NFS_V4_2 .copy_file_range = nfs4_copy_file_range, .llseek = nfs4_file_llseek, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e653654c10bc..e1214bb6b7ee 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1155,7 +1155,11 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res) { - return nfs4_do_call_sync(clnt, server, msg, args, res, 0); + unsigned short task_flags = 0; + + if (server->nfs_client->cl_minorversion) + task_flags = RPC_TASK_MOVEABLE; + return nfs4_do_call_sync(clnt, server, msg, args, res, task_flags); } @@ -1205,12 +1209,12 @@ nfs4_update_changeattr_locked(struct inode *inode, u64 change_attr = inode_peek_iversion_raw(inode); cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME; + if (S_ISDIR(inode->i_mode)) + cache_validity |= NFS_INO_INVALID_DATA; switch (NFS_SERVER(inode)->change_attr_type) { case NFS4_CHANGE_TYPE_IS_UNDEFINED: - break; - case NFS4_CHANGE_TYPE_IS_TIME_METADATA: - if ((s64)(change_attr - cinfo->after) > 0) + if (cinfo->after == change_attr) goto out; break; default: @@ -1218,24 +1222,21 @@ nfs4_update_changeattr_locked(struct inode *inode, goto out; } - if (cinfo->atomic && cinfo->before == change_attr) { - nfsi->attrtimeo_timestamp = jiffies; - } else { - if (S_ISDIR(inode->i_mode)) { - cache_validity |= NFS_INO_INVALID_DATA; - nfs_force_lookup_revalidate(inode); - } else { - if (!NFS_PROTO(inode)->have_delegation(inode, - FMODE_READ)) - cache_validity |= NFS_INO_REVAL_PAGECACHE; - } - - if (cinfo->before != change_attr) - cache_validity |= NFS_INO_INVALID_ACCESS | - NFS_INO_INVALID_ACL | - NFS_INO_INVALID_XATTR; - } inode_set_iversion_raw(inode, cinfo->after); + if (!cinfo->atomic || cinfo->before != change_attr) { + if (S_ISDIR(inode->i_mode)) + nfs_force_lookup_revalidate(inode); + + if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) + cache_validity |= + NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | + NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER | + NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK | + NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR | + NFS_INO_REVAL_PAGECACHE; + nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); + } + nfsi->attrtimeo_timestamp = jiffies; nfsi->read_cache_jiffies = timestamp; nfsi->attr_gencount = nfs_inc_attr_generation_counter(); nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE; @@ -2569,6 +2570,9 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, }; int status; + if (server->nfs_client->cl_minorversion) + task_setup_data.flags |= RPC_TASK_MOVEABLE; + kref_get(&data->kref); data->rpc_done = false; data->rpc_status = 0; @@ -3749,6 +3753,9 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) }; int status = -ENOMEM; + if (server->nfs_client->cl_minorversion) + task_setup_data.flags |= RPC_TASK_MOVEABLE; + nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg); @@ -4188,6 +4195,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, }; unsigned short task_flags = 0; + if (nfs4_has_session(server->nfs_client)) + task_flags = RPC_TASK_MOVEABLE; + /* Is this is an attribute revalidation, subject to softreval? */ if (inode && (server->flags & NFS_MOUNT_SOFTREVAL)) task_flags |= RPC_TASK_TIMEOUT; @@ -4307,6 +4317,9 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, }; unsigned short task_flags = 0; + if (server->nfs_client->cl_minorversion) + task_flags = RPC_TASK_MOVEABLE; + /* Is this is an attribute revalidation, subject to softreval? */ if (nfs_lookup_is_soft_revalidate(dentry)) task_flags |= RPC_TASK_TIMEOUT; @@ -6538,7 +6551,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, .rpc_client = server->client, .rpc_message = &msg, .callback_ops = &nfs4_delegreturn_ops, - .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, + .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT | RPC_TASK_MOVEABLE, }; int status = 0; @@ -6856,6 +6869,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, .workqueue = nfsiod_workqueue, .flags = RPC_TASK_ASYNC, }; + struct nfs_client *client = + NFS_SERVER(lsp->ls_state->inode)->nfs_client; + + if (client->cl_minorversion) + task_setup_data.flags |= RPC_TASK_MOVEABLE; nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client, NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg); @@ -7130,6 +7148,10 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, }; int ret; + struct nfs_client *client = NFS_SERVER(state->inode)->nfs_client; + + if (client->cl_minorversion) + task_setup_data.flags |= RPC_TASK_MOVEABLE; dprintk("%s: begin!\n", __func__); data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), @@ -7438,6 +7460,43 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) return nfs4_retry_setlk(state, cmd, request); } +static int nfs4_delete_lease(struct file *file, void **priv) +{ + return generic_setlease(file, F_UNLCK, NULL, priv); +} + +static int nfs4_add_lease(struct file *file, long arg, struct file_lock **lease, + void **priv) +{ + struct inode *inode = file_inode(file); + fmode_t type = arg == F_RDLCK ? FMODE_READ : FMODE_WRITE; + int ret; + + /* No delegation, no lease */ + if (!nfs4_have_delegation(inode, type)) + return -EAGAIN; + ret = generic_setlease(file, arg, lease, priv); + if (ret || nfs4_have_delegation(inode, type)) + return ret; + /* We raced with a delegation return */ + nfs4_delete_lease(file, priv); + return -EAGAIN; +} + +int nfs4_proc_setlease(struct file *file, long arg, struct file_lock **lease, + void **priv) +{ + switch (arg) { + case F_RDLCK: + case F_WRLCK: + return nfs4_add_lease(file, arg, lease, priv); + case F_UNLCK: + return nfs4_delete_lease(file, priv); + default: + return -EINVAL; + } +} + int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid) { struct nfs_server *server = NFS_SERVER(state->inode); @@ -9186,7 +9245,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, .rpc_client = clp->cl_rpcclient, .rpc_message = &msg, .callback_ops = &nfs41_sequence_ops, - .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, + .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT | RPC_TASK_MOVEABLE, }; struct rpc_task *ret; @@ -9385,7 +9444,7 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, { struct inode *inode = lgp->args.inode; struct nfs_server *server = NFS_SERVER(inode); - struct pnfs_layout_hdr *lo; + struct pnfs_layout_hdr *lo = lgp->lo; int nfs4err = task->tk_status; int err, status = 0; LIST_HEAD(head); @@ -9437,7 +9496,6 @@ nfs4_layoutget_handle_exception(struct rpc_task *task, case -NFS4ERR_BAD_STATEID: exception->timeout = 0; spin_lock(&inode->i_lock); - lo = NFS_I(inode)->layout; /* If the open stateid was bad, then recover it. */ if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) || !nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) { @@ -9509,7 +9567,8 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout) .rpc_message = &msg, .callback_ops = &nfs4_layoutget_call_ops, .callback_data = lgp, - .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, + .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF | + RPC_TASK_MOVEABLE, }; struct pnfs_layout_segment *lseg = NULL; struct nfs4_exception exception = { @@ -9520,9 +9579,6 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout) dprintk("--> %s\n", __func__); - /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ - pnfs_get_layout_hdr(NFS_I(inode)->layout); - nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0); task = rpc_run_task(&task_setup_data); @@ -9650,6 +9706,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync) .rpc_message = &msg, .callback_ops = &nfs4_layoutreturn_call_ops, .callback_data = lrp, + .flags = RPC_TASK_MOVEABLE, }; int status = 0; @@ -9804,6 +9861,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) .rpc_message = &msg, .callback_ops = &nfs4_layoutcommit_ops, .callback_data = data, + .flags = RPC_TASK_MOVEABLE, }; struct rpc_task *task; int status = 0; @@ -10131,7 +10189,7 @@ static int nfs41_free_stateid(struct nfs_server *server, .rpc_client = server->client, .rpc_message = &msg, .callback_ops = &nfs41_free_stateid_ops, - .flags = RPC_TASK_ASYNC, + .flags = RPC_TASK_ASYNC | RPC_TASK_MOVEABLE, }; struct nfs_free_stateid_data *data; struct rpc_task *task; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index cf9cc62ec48e..cc232d1f16f2 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -954,6 +954,7 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) { struct nfs_pgio_header *hdr; int ret; + unsigned short task_flags = 0; hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); if (!hdr) { @@ -962,14 +963,17 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) } nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); ret = nfs_generic_pgio(desc, hdr); - if (ret == 0) + if (ret == 0) { + if (NFS_SERVER(hdr->inode)->nfs_client->cl_minorversion) + task_flags = RPC_TASK_MOVEABLE; ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), hdr, hdr->cred, NFS_PROTO(hdr->inode), desc->pg_rpc_callops, desc->pg_ioflags, - RPC_TASK_CRED_NOREF); + RPC_TASK_CRED_NOREF | task_flags); + } return ret; } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 2c01ee805306..ef14ea0b6ab8 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -966,10 +966,8 @@ void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, const struct cred *cred, bool update_barrier) { - u32 oldseq, newseq, new_barrier = 0; - - oldseq = be32_to_cpu(lo->plh_stateid.seqid); - newseq = be32_to_cpu(new->seqid); + u32 oldseq = be32_to_cpu(lo->plh_stateid.seqid); + u32 newseq = be32_to_cpu(new->seqid); if (!pnfs_layout_is_valid(lo)) { pnfs_set_layout_cred(lo, cred); @@ -979,19 +977,21 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, clear_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); return; } - if (pnfs_seqid_is_newer(newseq, oldseq)) { + + if (pnfs_seqid_is_newer(newseq, oldseq)) nfs4_stateid_copy(&lo->plh_stateid, new); - /* - * Because of wraparound, we want to keep the barrier - * "close" to the current seqids. - */ - new_barrier = newseq - atomic_read(&lo->plh_outstanding); - } - if (update_barrier) - new_barrier = be32_to_cpu(new->seqid); - else if (new_barrier == 0) + + if (update_barrier) { + pnfs_barrier_update(lo, newseq); return; - pnfs_barrier_update(lo, new_barrier); + } + /* + * Because of wraparound, we want to keep the barrier + * "close" to the current seqids. We really only want to + * get here from a layoutget call. + */ + if (atomic_read(&lo->plh_outstanding) == 1) + pnfs_barrier_update(lo, be32_to_cpu(lo->plh_stateid.seqid)); } static bool @@ -1128,8 +1128,7 @@ void pnfs_layoutget_free(struct nfs4_layoutget *lgp) size_t max_pages = lgp->args.layout.pglen / PAGE_SIZE; nfs4_free_pages(lgp->args.layout.pages, max_pages); - if (lgp->args.inode) - pnfs_put_layout_hdr(NFS_I(lgp->args.inode)->layout); + pnfs_put_layout_hdr(lgp->lo); put_nfs_open_context(lgp->args.ctx); kfree(lgp); } @@ -2014,7 +2013,7 @@ lookup_again: * If the layout segment list is empty, but there are outstanding * layoutget calls, then they might be subject to a layoutrecall. */ - if (list_empty(&lo->plh_segs) && + if ((list_empty(&lo->plh_segs) || !pnfs_layout_is_valid(lo)) && atomic_read(&lo->plh_outstanding) != 0) { spin_unlock(&ino->i_lock); lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding, @@ -2124,6 +2123,9 @@ lookup_again: goto out_put_layout_hdr; } + lgp->lo = lo; + pnfs_get_layout_hdr(lo); + lseg = nfs4_proc_layoutget(lgp, &timeout); trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET); @@ -2255,6 +2257,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data, pnfs_put_layout_hdr(lo); return; } + lgp->lo = lo; data->lgp = lgp; data->o_arg.lg_args = &lgp->args; data->o_res.lg_res = &lgp->res; @@ -2263,6 +2266,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data, static void _lgopen_prepare_floating(struct nfs4_opendata *data, struct nfs_open_context *ctx) { + struct inode *ino = data->dentry->d_inode; struct pnfs_layout_range rng = { .iomode = (data->o_arg.fmode & FMODE_WRITE) ? IOMODE_RW: IOMODE_READ, @@ -2271,7 +2275,7 @@ static void _lgopen_prepare_floating(struct nfs4_opendata *data, }; struct nfs4_layoutget *lgp; - lgp = pnfs_alloc_init_layoutget_args(NULL, ctx, ¤t_stateid, + lgp = pnfs_alloc_init_layoutget_args(ino, ctx, ¤t_stateid, &rng, GFP_KERNEL); if (!lgp) return; @@ -2291,6 +2295,8 @@ void pnfs_lgopen_prepare(struct nfs4_opendata *data, /* Could check on max_ops, but currently hardcoded high enough */ if (!nfs_server_capable(data->dir->d_inode, NFS_CAP_LGOPEN)) return; + if (data->lgp) + return; if (data->state) _lgopen_prepare_attached(data, ctx); else @@ -2330,13 +2336,13 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, } return; } - if (!lgp->args.inode) { + if (!lgp->lo) { lo = _pnfs_grab_empty_layout(ino, ctx); if (!lo) return; - lgp->args.inode = ino; + lgp->lo = lo; } else - lo = NFS_I(lgp->args.inode)->layout; + lo = lgp->lo; lseg = pnfs_layout_process(lgp); if (!IS_ERR(lseg)) { @@ -2349,11 +2355,9 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, void nfs4_lgopen_release(struct nfs4_layoutget *lgp) { if (lgp != NULL) { - struct inode *inode = lgp->args.inode; - if (inode) { - struct pnfs_layout_hdr *lo = NFS_I(inode)->layout; - pnfs_clear_first_layoutget(lo); - nfs_layoutget_end(lo); + if (lgp->lo) { + pnfs_clear_first_layoutget(lgp->lo); + nfs_layoutget_end(lgp->lo); } pnfs_layoutget_free(lgp); } @@ -2362,7 +2366,7 @@ void nfs4_lgopen_release(struct nfs4_layoutget *lgp) struct pnfs_layout_segment * pnfs_layout_process(struct nfs4_layoutget *lgp) { - struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout; + struct pnfs_layout_hdr *lo = lgp->lo; struct nfs4_layoutget_res *res = &lgp->res; struct pnfs_layout_segment *lseg; struct inode *ino = lo->plh_inode; @@ -2390,11 +2394,13 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) goto out_forget; } + if (!pnfs_layout_is_valid(lo) && !pnfs_is_first_layoutget(lo)) + goto out_forget; + if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { /* existing state ID, make sure the sequence number matches. */ if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { - if (!pnfs_layout_is_valid(lo) && - pnfs_is_first_layoutget(lo)) + if (!pnfs_layout_is_valid(lo)) lo->plh_barrier = 0; dprintk("%s forget reply due to sequence\n", __func__); goto out_forget; @@ -2413,8 +2419,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) goto out_forget; } else { /* We have a completely new layout */ - if (!pnfs_is_first_layoutget(lo)) - goto out_forget; pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true); } diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index 49d3389bd813..cf19914fec81 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c @@ -805,19 +805,16 @@ out: } EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add); -static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds) +static int nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds) { might_sleep(); - wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, - TASK_KILLABLE); + return wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, TASK_KILLABLE); } static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds) { smp_mb__before_atomic(); - clear_bit(NFS4DS_CONNECTING, &ds->ds_state); - smp_mb__after_atomic(); - wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING); + clear_and_wake_up_bit(NFS4DS_CONNECTING, &ds->ds_state); } static struct nfs_client *(*get_v3_ds_connect)( @@ -858,7 +855,7 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv, dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr); if (!load_v3_ds_connect()) - goto out; + return -EPROTONOSUPPORT; list_for_each_entry(da, &ds->ds_addrs, da_node) { dprintk("%s: DS %s: trying address %s\n", @@ -993,30 +990,33 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, { int err; -again: - err = 0; - if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) { - if (version == 3) { - err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, - retrans); - } else if (version == 4) { - err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, - retrans, minor_version); - } else { - dprintk("%s: unsupported DS version %d\n", __func__, - version); - err = -EPROTONOSUPPORT; - } + do { + err = nfs4_wait_ds_connect(ds); + if (err || ds->ds_clp) + goto out; + if (nfs4_test_deviceid_unavailable(devid)) + return -ENODEV; + } while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0); - nfs4_clear_ds_conn_bit(ds); - } else { - nfs4_wait_ds_connect(ds); + if (ds->ds_clp) + goto connect_done; - /* what was waited on didn't connect AND didn't mark unavail */ - if (!ds->ds_clp && !nfs4_test_deviceid_unavailable(devid)) - goto again; + switch (version) { + case 3: + err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, retrans); + break; + case 4: + err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, retrans, + minor_version); + break; + default: + dprintk("%s: unsupported DS version %d\n", __func__, version); + err = -EPROTONOSUPPORT; } +connect_done: + nfs4_clear_ds_conn_bit(ds); +out: /* * At this point the ds->ds_clp should be ready, but it might have * hit an error. diff --git a/fs/nfs/read.c b/fs/nfs/read.c index d2b6dce1f99f..9f39e0a1a38b 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -74,8 +74,7 @@ void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, } EXPORT_SYMBOL_GPL(nfs_pageio_init_read); -static void nfs_pageio_complete_read(struct nfs_pageio_descriptor *pgio, - struct inode *inode) +static void nfs_pageio_complete_read(struct nfs_pageio_descriptor *pgio) { struct nfs_pgio_mirror *pgm; unsigned long npages; @@ -86,9 +85,9 @@ static void nfs_pageio_complete_read(struct nfs_pageio_descriptor *pgio, WARN_ON_ONCE(pgio->pg_mirror_count != 1); pgm = &pgio->pg_mirrors[0]; - NFS_I(inode)->read_io += pgm->pg_bytes_written; + NFS_I(pgio->pg_inode)->read_io += pgm->pg_bytes_written; npages = (pgm->pg_bytes_written + PAGE_SIZE - 1) >> PAGE_SHIFT; - nfs_add_stats(inode, NFSIOS_READPAGES, npages); + nfs_add_stats(pgio->pg_inode, NFSIOS_READPAGES, npages); } @@ -363,22 +362,23 @@ int nfs_readpage(struct file *file, struct page *page) } else desc.ctx = get_nfs_open_context(nfs_file_open_context(file)); + xchg(&desc.ctx->error, 0); if (!IS_SYNC(inode)) { ret = nfs_readpage_from_fscache(desc.ctx, inode, page); if (ret == 0) - goto out; + goto out_wait; } - xchg(&desc.ctx->error, 0); nfs_pageio_init_read(&desc.pgio, inode, false, &nfs_async_read_completion_ops); ret = readpage_async_filler(&desc, page); + if (ret) + goto out; - if (!ret) - nfs_pageio_complete_read(&desc.pgio, inode); - + nfs_pageio_complete_read(&desc.pgio); ret = desc.pgio.pg_error < 0 ? desc.pgio.pg_error : 0; +out_wait: if (!ret) { ret = wait_on_page_locked_killable(page); if (!PageUptodate(page) && !ret) @@ -430,7 +430,7 @@ int nfs_readpages(struct file *file, struct address_space *mapping, ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); - nfs_pageio_complete_read(&desc.pgio, inode); + nfs_pageio_complete_read(&desc.pgio); read_complete: put_nfs_open_context(desc.ctx); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 3bf82178166a..eae9bf114041 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1810,6 +1810,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, struct nfs_commit_info *cinfo) { struct nfs_commit_data *data; + unsigned short task_flags = 0; /* another commit raced with us */ if (list_empty(head)) @@ -1820,8 +1821,11 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, /* Set up the argument struct */ nfs_init_commit(data, head, NULL, cinfo); atomic_inc(&cinfo->mds->rpcs_out); + if (NFS_SERVER(inode)->nfs_client->cl_minorversion) + task_flags = RPC_TASK_MOVEABLE; return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode), - data->mds_ops, how, RPC_TASK_CRED_NOREF); + data->mds_ops, how, + RPC_TASK_CRED_NOREF | task_flags); } /* diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c index 26f2a50eceac..edec45831585 100644 --- a/fs/nfs_common/grace.c +++ b/fs/nfs_common/grace.c @@ -82,6 +82,7 @@ __state_in_grace(struct net *net, bool open) /** * locks_in_grace + * @net: network namespace * * Lock managers call this function to determine when it is OK for them * to answer ordinary lock requests, and when they should accept only diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index 1058659a8d31..c99dee99a3c1 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -236,7 +236,7 @@ again: if (!buf) return -ENOMEM; - rq = blk_get_request(q, REQ_OP_SCSI_IN, 0); + rq = blk_get_request(q, REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) { error = -ENOMEM; goto out_free_buf; diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index a75abeb1e698..935c1028c217 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -176,6 +176,12 @@ struct nfsd_net { unsigned int longest_chain_cachesize; struct shrinker nfsd_reply_cache_shrinker; + + /* tracking server-to-server copy mounts */ + spinlock_t nfsd_ssc_lock; + struct list_head nfsd_ssc_mount_list; + wait_queue_head_t nfsd_ssc_waitq; + /* utsname taken from the process that starts the server */ char nfsd_name[UNX_MAXNODENAME+1]; }; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index a1591feeea22..5dfe7644a517 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -172,7 +172,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) struct nfsd3_getaclres *resp = rqstp->rq_resp; struct dentry *dentry = resp->fh.fh_dentry; struct kvec *head = rqstp->rq_res.head; - struct inode *inode = d_inode(dentry); + struct inode *inode; unsigned int base; int n; int w; @@ -181,6 +181,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) return 0; switch (resp->status) { case nfs_ok: + inode = d_inode(dentry); if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) return 0; if (xdr_stream_encode_u32(xdr, resp->mask) < 0) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 7325592b456e..0f8b10f363e7 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -915,10 +915,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c args.authflavor = clp->cl_cred.cr_flavor; clp->cl_cb_ident = conn->cb_ident; } else { - if (!conn->cb_xprt) { - trace_nfsd_cb_setup_err(clp, -EINVAL); + if (!conn->cb_xprt) return -EINVAL; - } clp->cl_cb_conn.cb_xprt = conn->cb_xprt; clp->cl_cb_session = ses; args.bc_xprt = conn->cb_xprt; @@ -941,37 +939,43 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c } clp->cl_cb_client = client; clp->cl_cb_cred = cred; - trace_nfsd_cb_setup(clp); + rcu_read_lock(); + trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID), + args.authflavor); + rcu_read_unlock(); return 0; } +static void nfsd4_mark_cb_state(struct nfs4_client *clp, int newstate) +{ + if (clp->cl_cb_state != newstate) { + clp->cl_cb_state = newstate; + trace_nfsd_cb_state(clp); + } +} + static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) { if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) return; - clp->cl_cb_state = NFSD4_CB_DOWN; - trace_nfsd_cb_state(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_DOWN); } static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) { if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) return; - clp->cl_cb_state = NFSD4_CB_FAULT; - trace_nfsd_cb_state(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_FAULT); } static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) { struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); - trace_nfsd_cb_done(clp, task->tk_status); if (task->tk_status) nfsd4_mark_cb_down(clp, task->tk_status); - else { - clp->cl_cb_state = NFSD4_CB_UP; - trace_nfsd_cb_state(clp); - } + else + nfsd4_mark_cb_state(clp, NFSD4_CB_UP); } static void nfsd4_cb_probe_release(void *calldata) @@ -995,8 +999,8 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { */ void nfsd4_probe_callback(struct nfs4_client *clp) { - clp->cl_cb_state = NFSD4_CB_UNKNOWN; - trace_nfsd_cb_state(clp); + trace_nfsd_cb_probe(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); nfsd4_run_cb(&clp->cl_cb_null); } @@ -1009,11 +1013,10 @@ void nfsd4_probe_callback_sync(struct nfs4_client *clp) void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) { - clp->cl_cb_state = NFSD4_CB_UNKNOWN; + nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); spin_lock(&clp->cl_lock); memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); spin_unlock(&clp->cl_lock); - trace_nfsd_cb_state(clp); } /* @@ -1170,8 +1173,6 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) struct nfsd4_callback *cb = calldata; struct nfs4_client *clp = cb->cb_clp; - trace_nfsd_cb_done(clp, task->tk_status); - if (!nfsd4_cb_sequence_done(task, cb)) return; @@ -1231,6 +1232,9 @@ void nfsd4_destroy_callback_queue(void) /* must be called under the state lock */ void nfsd4_shutdown_callback(struct nfs4_client *clp) { + if (clp->cl_cb_state != NFSD4_CB_UNKNOWN) + trace_nfsd_cb_shutdown(clp); + set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags); /* * Note this won't actually result in a null callback; @@ -1276,7 +1280,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) * kill the old client: */ if (clp->cl_cb_client) { - trace_nfsd_cb_shutdown(clp); rpc_shutdown_client(clp->cl_cb_client); clp->cl_cb_client = NULL; put_cred(clp->cl_cb_cred); @@ -1322,8 +1325,6 @@ nfsd4_run_cb_work(struct work_struct *work) struct rpc_clnt *clnt; int flags; - trace_nfsd_cb_work(clp, cb->cb_msg.rpc_proc->p_name); - if (cb->cb_need_restart) { cb->cb_need_restart = false; } else { @@ -1345,7 +1346,7 @@ nfsd4_run_cb_work(struct work_struct *work) * Don't send probe messages for 4.1 or later. */ if (!cb->cb_ops && clp->cl_minorversion) { - clp->cl_cb_state = NFSD4_CB_UP; + nfsd4_mark_cb_state(clp, NFSD4_CB_UP); nfsd41_destroy_cb(cb); return; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f4ce93d7f26e..486c5dba4b65 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644); MODULE_PARM_DESC(inter_copy_offload_enable, "Enable inter server to server copy offload. Default: false"); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +static int nfsd4_ssc_umount_timeout = 900000; /* default to 15 mins */ +module_param(nfsd4_ssc_umount_timeout, int, 0644); +MODULE_PARM_DESC(nfsd4_ssc_umount_timeout, + "idle msecs before unmount export from source server"); +#endif + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #include @@ -1165,6 +1172,81 @@ extern void nfs_sb_deactive(struct super_block *sb); #define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys" +/* + * setup a work entry in the ssc delayed unmount list. + */ +static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) +{ + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd4_ssc_umount_item *tmp; + DEFINE_WAIT(wait); + + *ss_mnt = NULL; + *retwork = NULL; + work = kzalloc(sizeof(*work), GFP_KERNEL); +try_again: + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (strncmp(ni->nsui_ipaddr, ipaddr, sizeof(ni->nsui_ipaddr))) + continue; + /* found a match */ + if (ni->nsui_busy) { + /* wait - and try again */ + prepare_to_wait(&nn->nfsd_ssc_waitq, &wait, + TASK_INTERRUPTIBLE); + spin_unlock(&nn->nfsd_ssc_lock); + + /* allow 20secs for mount/unmount for now - revisit */ + if (signal_pending(current) || + (schedule_timeout(20*HZ) == 0)) { + kfree(work); + return nfserr_eagain; + } + finish_wait(&nn->nfsd_ssc_waitq, &wait); + goto try_again; + } + *ss_mnt = ni->nsui_vfsmount; + refcount_inc(&ni->nsui_refcnt); + spin_unlock(&nn->nfsd_ssc_lock); + kfree(work); + + /* return vfsmount in ss_mnt */ + return 0; + } + if (work) { + strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr)); + refcount_set(&work->nsui_refcnt, 2); + work->nsui_busy = true; + list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); + *retwork = work; + } + spin_unlock(&nn->nfsd_ssc_lock); + return 0; +} + +static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn, + struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt) +{ + /* set nsui_vfsmount, clear busy flag and wakeup waiters */ + spin_lock(&nn->nfsd_ssc_lock); + work->nsui_vfsmount = ss_mnt; + work->nsui_busy = false; + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); +} + +static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, + struct nfsd4_ssc_umount_item *work) +{ + spin_lock(&nn->nfsd_ssc_lock); + list_del(&work->nsui_list); + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); + kfree(work); +} + /* * Support one copy source server for now. */ @@ -1181,6 +1263,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, char *ipaddr, *dev_name, *raw_data; int len, raw_len; __be32 status = nfserr_inval; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); naddr = &nss->u.nl4_addr; tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr, @@ -1229,12 +1313,24 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, goto out_free_rawdata; snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); + status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt); + if (status) + goto out_free_devname; + if (ss_mnt) + goto out_done; + /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */ ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data); module_put(type->owner); - if (IS_ERR(ss_mnt)) + if (IS_ERR(ss_mnt)) { + status = nfserr_nodev; + if (work) + nfsd4_ssc_cancel_dul_work(nn, work); goto out_free_devname; - + } + if (work) + nfsd4_ssc_update_dul_work(nn, work, ss_mnt); +out_done: status = 0; *mount = ss_mnt; @@ -1301,10 +1397,42 @@ static void nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, struct nfsd_file *dst) { + bool found = false; + long timeout; + struct nfsd4_ssc_umount_item *tmp; + struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); + nfs42_ssc_close(src->nf_file); - fput(src->nf_file); nfsd_file_put(dst); - mntput(ss_mnt); + fput(src->nf_file); + + if (!nn) { + mntput(ss_mnt); + return; + } + spin_lock(&nn->nfsd_ssc_lock); + timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) { + list_del(&ni->nsui_list); + /* + * vfsmount can be shared by multiple exports, + * decrement refcnt. If the count drops to 1 it + * will be unmounted when nsui_expire expires. + */ + refcount_dec(&ni->nsui_refcnt); + ni->nsui_expire = jiffies + timeout; + list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list); + found = true; + break; + } + } + spin_unlock(&nn->nfsd_ssc_lock); + if (!found) { + mntput(ss_mnt); + return; + } } #else /* CONFIG_NFSD_V4_2_INTER_SSC */ @@ -1375,7 +1503,8 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = { static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) { - copy->cp_res.wr_stable_how = NFS_UNSTABLE; + copy->cp_res.wr_stable_how = + copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE; copy->cp_synchronous = sync; gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net); } @@ -1386,6 +1515,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) u64 bytes_total = copy->cp_count; u64 src_pos = copy->cp_src_pos; u64 dst_pos = copy->cp_dst_pos; + __be32 status; /* See RFC 7862 p.67: */ if (bytes_total == 0) @@ -1403,6 +1533,16 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) src_pos += bytes_copied; dst_pos += bytes_copied; } while (bytes_total > 0 && !copy->cp_synchronous); + /* for a non-zero asynchronous copy do a commit of data */ + if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) { + down_write(©->nf_dst->nf_rwsem); + status = vfs_fsync_range(copy->nf_dst->nf_file, + copy->cp_dst_pos, + copy->cp_res.wr_bytes_written, 0); + up_write(©->nf_dst->nf_rwsem); + if (!status) + copy->committed = true; + } return bytes_copied; } @@ -1497,6 +1637,8 @@ do_callback: memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); + trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, + ©->fh, copy->cp_count, copy->nfserr); nfsd4_run_cb(&cb_copy->cp_cb); out: if (!copy->cp_intra) @@ -3232,7 +3374,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) { struct nfsd4_compoundres *resp = rqstp->rq_resp; struct nfsd4_compoundargs *argp = rqstp->rq_argp; - struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; + struct nfsd4_op *this; struct nfsd4_compound_state *cstate = &resp->cstate; struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow; u32 opiter; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cd5eac2ba054..fa67ecd5fe63 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "xdr4.h" #include "xdr4cb.h" #include "vfs.h" @@ -1745,6 +1746,8 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); struct nfs4_client *clp = c->cn_session->se_client; + trace_nfsd_cb_lost(clp); + spin_lock(&clp->cl_lock); if (!list_empty(&c->cn_persession)) { list_del(&c->cn_persession); @@ -2355,6 +2358,21 @@ static void seq_quote_mem(struct seq_file *m, char *data, int len) seq_printf(m, "\""); } +static const char *cb_state2str(int state) +{ + switch (state) { + case NFSD4_CB_UP: + return "UP"; + case NFSD4_CB_UNKNOWN: + return "UNKNOWN"; + case NFSD4_CB_DOWN: + return "DOWN"; + case NFSD4_CB_FAULT: + return "FAULT"; + } + return "UNDEFINED"; +} + static int client_info_show(struct seq_file *m, void *v) { struct inode *inode = m->private; @@ -2383,6 +2401,8 @@ static int client_info_show(struct seq_file *m, void *v) seq_printf(m, "\nImplementation time: [%lld, %ld]\n", clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); } + seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); + seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); drop_client(clp); return 0; @@ -2665,6 +2685,8 @@ static void force_expire_client(struct nfs4_client *clp) struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); bool already_expired; + trace_nfsd_clid_admin_expired(&clp->cl_clientid); + spin_lock(&clp->cl_lock); clp->cl_time = 0; spin_unlock(&clp->cl_lock); @@ -2816,14 +2838,11 @@ move_to_confirmed(struct nfs4_client *clp) lockdep_assert_held(&nn->client_lock); - dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); - if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) && - clp->cl_nfsd_dentry && - clp->cl_nfsd_info_dentry) - fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); + set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); + trace_nfsd_clid_confirmed(&clp->cl_clientid); renew_client_locked(clp); } @@ -3176,20 +3195,24 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } /* case 6 */ exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; + trace_nfsd_clid_confirmed_r(conf); goto out_copy; } if (!creds_match) { /* case 3 */ if (client_has_state(conf)) { status = nfserr_clid_inuse; + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; } goto out_new; } if (verfs_match) { /* case 2 */ conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; + trace_nfsd_clid_confirmed_r(conf); goto out_copy; } /* case 5, client reboot */ + trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); conf = NULL; goto out_new; } @@ -3199,16 +3222,19 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } - unconf = find_unconfirmed_client_by_name(&exid->clname, nn); + unconf = find_unconfirmed_client_by_name(&exid->clname, nn); if (unconf) /* case 4, possible retry or client restart */ unhash_client_locked(unconf); - /* case 1 (normal case) */ + /* case 1, new owner ID */ + trace_nfsd_clid_fresh(new); + out_new: if (conf) { status = mark_client_expired_locked(conf); if (status) goto out; + trace_nfsd_clid_replaced(&conf->cl_clientid); } new->cl_minorversion = cstate->minorversion; new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; @@ -3232,8 +3258,10 @@ out: out_nolock: if (new) expire_client(new); - if (unconf) + if (unconf) { + trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); expire_client(unconf); + } return status; } @@ -3425,9 +3453,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, goto out_free_conn; } } else if (unconf) { + status = nfserr_clid_inuse; if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { - status = nfserr_clid_inuse; + trace_nfsd_clid_cred_mismatch(unconf, rqstp); goto out_free_conn; } status = nfserr_wrong_cred; @@ -3447,6 +3476,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, old = NULL; goto out_free_conn; } + trace_nfsd_clid_replaced(&old->cl_clientid); } move_to_confirmed(unconf); conf = unconf; @@ -3471,6 +3501,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, /* cache solo and embedded create sessions under the client_lock */ nfsd4_cache_create_session(cr_ses, cs_slot, status); spin_unlock(&nn->client_lock); + if (conf == unconf) + fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); /* init connection and backchannel */ nfsd4_init_conn(rqstp, conn, new); nfsd4_put_session(new); @@ -3904,6 +3936,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, status = nfserr_wrong_cred; goto out; } + trace_nfsd_clid_destroyed(&clp->cl_clientid); unhash_client_locked(clp); out: spin_unlock(&nn->client_lock); @@ -3946,6 +3979,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, goto out; status = nfs_ok; + trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); nfsd4_client_record_create(clp); inc_reclaim_complete(clp); out: @@ -3967,27 +4001,29 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, rqstp, &clverifier); if (new == NULL) return nfserr_jukebox; - /* Cases below refer to rfc 3530 section 14.2.33: */ spin_lock(&nn->client_lock); conf = find_confirmed_client_by_name(&clname, nn); if (conf && client_has_state(conf)) { - /* case 0: */ status = nfserr_clid_inuse; if (clp_used_exchangeid(conf)) goto out; if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { - trace_nfsd_clid_inuse_err(conf); + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; } } unconf = find_unconfirmed_client_by_name(&clname, nn); if (unconf) unhash_client_locked(unconf); - /* We need to handle only case 1: probable callback update */ - if (conf && same_verf(&conf->cl_verifier, &clverifier)) { - copy_clid(new, conf); - gen_confirm(new, nn); - } + if (conf) { + if (same_verf(&conf->cl_verifier, &clverifier)) { + copy_clid(new, conf); + gen_confirm(new, nn); + } else + trace_nfsd_clid_verf_mismatch(conf, rqstp, + &clverifier); + } else + trace_nfsd_clid_fresh(new); new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); add_to_unconfirmed(new); @@ -4000,12 +4036,13 @@ out: spin_unlock(&nn->client_lock); if (new) free_client(new); - if (unconf) + if (unconf) { + trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); expire_client(unconf); + } return status; } - __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, @@ -4034,25 +4071,27 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, * Nevertheless, RFC 7530 recommends INUSE for this case: */ status = nfserr_clid_inuse; - if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) + if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { + trace_nfsd_clid_cred_mismatch(unconf, rqstp); goto out; - if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) + } + if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; - /* cases below refer to rfc 3530 section 14.2.34: */ + } if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { if (conf && same_verf(&confirm, &conf->cl_confirm)) { - /* case 2: probable retransmit */ status = nfs_ok; - } else /* case 4: client hasn't noticed we rebooted yet? */ + } else status = nfserr_stale_clientid; goto out; } status = nfs_ok; - if (conf) { /* case 1: callback update */ + if (conf) { old = unconf; unhash_client_locked(old); nfsd4_change_callback(conf, &unconf->cl_cb_conn); - } else { /* case 3: normal case; new or rebooted client */ + } else { old = find_confirmed_client_by_name(&unconf->cl_name, nn); if (old) { status = nfserr_clid_inuse; @@ -4065,12 +4104,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, old = NULL; goto out; } + trace_nfsd_clid_replaced(&old->cl_clientid); } move_to_confirmed(unconf); conf = unconf; } get_client_locked(conf); spin_unlock(&nn->client_lock); + if (conf == unconf) + fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); nfsd4_probe_callback(conf); spin_lock(&nn->client_lock); put_client_renew_locked(conf); @@ -4618,7 +4660,7 @@ nfsd_break_deleg_cb(struct file_lock *fl) struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; struct nfs4_file *fp = dp->dl_stid.sc_file; - trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid); + trace_nfsd_cb_recall(&dp->dl_stid); /* * We don't want the locks code to timeout the lease for us; @@ -5457,6 +5499,69 @@ static bool state_expired(struct laundry_time *lt, time64_t last_refresh) return false; } +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) +{ + spin_lock_init(&nn->nfsd_ssc_lock); + INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); + init_waitqueue_head(&nn->nfsd_ssc_waitq); +} +EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); + +/* + * This is called when nfsd is being shutdown, after all inter_ssc + * cleanup were done, to destroy the ssc delayed unmount list. + */ +static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) +{ + struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + list_del(&ni->nsui_list); + spin_unlock(&nn->nfsd_ssc_lock); + mntput(ni->nsui_vfsmount); + kfree(ni); + spin_lock(&nn->nfsd_ssc_lock); + } + spin_unlock(&nn->nfsd_ssc_lock); +} + +static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) +{ + bool do_wakeup = false; + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (time_after(jiffies, ni->nsui_expire)) { + if (refcount_read(&ni->nsui_refcnt) > 1) + continue; + + /* mark being unmount */ + ni->nsui_busy = true; + spin_unlock(&nn->nfsd_ssc_lock); + mntput(ni->nsui_vfsmount); + spin_lock(&nn->nfsd_ssc_lock); + + /* waiters need to start from begin of list */ + list_del(&ni->nsui_list); + kfree(ni); + + /* wakeup ssc_connect waiters */ + do_wakeup = true; + continue; + } + break; + } + if (do_wakeup) + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); +} +#endif + static time64_t nfs4_laundromat(struct nfsd_net *nn) { @@ -5495,10 +5600,8 @@ nfs4_laundromat(struct nfsd_net *nn) clp = list_entry(pos, struct nfs4_client, cl_lru); if (!state_expired(<, clp->cl_time)) break; - if (mark_client_expired_locked(clp)) { - trace_nfsd_clid_expired(&clp->cl_clientid); + if (mark_client_expired_locked(clp)) continue; - } list_add(&clp->cl_lru, &reaplist); } spin_unlock(&nn->client_lock); @@ -5568,6 +5671,10 @@ nfs4_laundromat(struct nfsd_net *nn) list_del_init(&nbl->nbl_lru); free_blocked_lock(nbl); } +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + /* service the server-to-server copy delayed unmount list */ + nfsd4_ssc_expire_umount(nn); +#endif out: return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); } @@ -6430,8 +6537,10 @@ nfsd4_lm_notify(struct file_lock *fl) } spin_unlock(&nn->blocked_locks_lock); - if (queue) + if (queue) { + trace_nfsd_cb_notify_lock(lo, nbl); nfsd4_run_cb(&nbl->nbl_cb); + } } static const struct lock_manager_operations nfsd_posix_mng_ops = { @@ -7229,7 +7338,6 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, unsigned int strhashval; struct nfs4_client_reclaim *crp; - trace_nfsd_clid_reclaim(nn, name.len, name.data); crp = alloc_reclaim(); if (crp) { strhashval = clientstr_hashval(name); @@ -7279,8 +7387,6 @@ nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) unsigned int strhashval; struct nfs4_client_reclaim *crp = NULL; - trace_nfsd_clid_find(nn, name.len, name.data); - strhashval = clientstr_hashval(name); list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { if (compare_blob(&crp->cr_name, &name) == 0) { @@ -7486,6 +7592,9 @@ nfs4_state_shutdown_net(struct net *net) nfsd4_client_tracking_exit(net); nfs4_state_destroy_net(net); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_shutdown_umount(nn); +#endif } void diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 14dbfa75059d..9664303afdaf 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -484,6 +484,10 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval) extern int nfsd4_is_junction(struct dentry *dentry); extern int register_cld_notifier(void); extern void unregister_cld_notifier(void); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); +#endif + #else /* CONFIG_NFSD_V4 */ static inline int nfsd4_is_junction(struct dentry *dentry) { diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index aff2cda5c6c3..6106697adc04 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -225,15 +225,12 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) * returns a crc32 hash for the filehandle that is compatible with * the one displayed by "wireshark". */ - -static inline u32 -knfsd_fh_hash(struct knfsd_fh *fh) +static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) { return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); } #else -static inline u32 -knfsd_fh_hash(struct knfsd_fh *fh) +static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) { return 0; } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index dd5d69921676..ccb59e91011b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -403,6 +403,9 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred) if (ret) goto out_filecache; +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_init_umount_work(nn); +#endif nn->nfsd_net_up = true; return 0; diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 27a93ebd1d80..adaec43548d1 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -408,7 +408,6 @@ TRACE_EVENT(nfsd_dirent, __entry->ino = ino; __entry->len = namlen; memcpy(__get_str(name), name, namlen); - __assign_str(name, name); ), TP_printk("fh_hash=0x%08x ino=%llu name=%.*s", __entry->fh_hash, __entry->ino, @@ -459,7 +458,6 @@ DEFINE_STATEID_EVENT(layout_recall_release); DEFINE_STATEID_EVENT(open); DEFINE_STATEID_EVENT(deleg_read); -DEFINE_STATEID_EVENT(deleg_break); DEFINE_STATEID_EVENT(deleg_recall); DECLARE_EVENT_CLASS(nfsd_stateseqid_class, @@ -511,7 +509,12 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ TP_PROTO(const clientid_t *clid), \ TP_ARGS(clid)) -DEFINE_CLIENTID_EVENT(expired); +DEFINE_CLIENTID_EVENT(expire_unconf); +DEFINE_CLIENTID_EVENT(reclaim_complete); +DEFINE_CLIENTID_EVENT(confirmed); +DEFINE_CLIENTID_EVENT(destroyed); +DEFINE_CLIENTID_EVENT(admin_expired); +DEFINE_CLIENTID_EVENT(replaced); DEFINE_CLIENTID_EVENT(purged); DEFINE_CLIENTID_EVENT(renew); DEFINE_CLIENTID_EVENT(stale); @@ -536,58 +539,102 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \ DEFINE_NET_EVENT(grace_start); DEFINE_NET_EVENT(grace_complete); -DECLARE_EVENT_CLASS(nfsd_clid_class, - TP_PROTO(const struct nfsd_net *nn, - unsigned int namelen, - const unsigned char *namedata), - TP_ARGS(nn, namelen, namedata), +TRACE_EVENT(nfsd_clid_cred_mismatch, + TP_PROTO( + const struct nfs4_client *clp, + const struct svc_rqst *rqstp + ), + TP_ARGS(clp, rqstp), TP_STRUCT__entry( - __field(unsigned long long, boot_time) - __field(unsigned int, namelen) - __dynamic_array(unsigned char, name, namelen) + __field(u32, cl_boot) + __field(u32, cl_id) + __field(unsigned long, cl_flavor) + __field(unsigned long, new_flavor) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ), TP_fast_assign( - __entry->boot_time = nn->boot_time; - __entry->namelen = namelen; - memcpy(__get_dynamic_array(name), namedata, namelen); + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + __entry->cl_flavor = clp->cl_cred.cr_flavor; + __entry->new_flavor = rqstp->rq_cred.cr_flavor; + memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, + sizeof(struct sockaddr_in6)); ), - TP_printk("boot_time=%16llx nfs4_clientid=%.*s", - __entry->boot_time, __entry->namelen, __get_str(name)) + TP_printk("client %08x:%08x flavor=%s, conflict=%s from addr=%pISpc", + __entry->cl_boot, __entry->cl_id, + show_nfsd_authflavor(__entry->cl_flavor), + show_nfsd_authflavor(__entry->new_flavor), __entry->addr + ) ) -#define DEFINE_CLID_EVENT(name) \ -DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ - TP_PROTO(const struct nfsd_net *nn, \ - unsigned int namelen, \ - const unsigned char *namedata), \ - TP_ARGS(nn, namelen, namedata)) +TRACE_EVENT(nfsd_clid_verf_mismatch, + TP_PROTO( + const struct nfs4_client *clp, + const struct svc_rqst *rqstp, + const nfs4_verifier *verf + ), + TP_ARGS(clp, rqstp, verf), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __array(unsigned char, cl_verifier, NFS4_VERIFIER_SIZE) + __array(unsigned char, new_verifier, NFS4_VERIFIER_SIZE) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + memcpy(__entry->cl_verifier, (void *)&clp->cl_verifier, + NFS4_VERIFIER_SIZE); + memcpy(__entry->new_verifier, (void *)verf, + NFS4_VERIFIER_SIZE); + memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, + sizeof(struct sockaddr_in6)); + ), + TP_printk("client %08x:%08x verf=0x%s, updated=0x%s from addr=%pISpc", + __entry->cl_boot, __entry->cl_id, + __print_hex_str(__entry->cl_verifier, NFS4_VERIFIER_SIZE), + __print_hex_str(__entry->new_verifier, NFS4_VERIFIER_SIZE), + __entry->addr + ) +); -DEFINE_CLID_EVENT(find); -DEFINE_CLID_EVENT(reclaim); - -TRACE_EVENT(nfsd_clid_inuse_err, +DECLARE_EVENT_CLASS(nfsd_clid_class, TP_PROTO(const struct nfs4_client *clp), TP_ARGS(clp), TP_STRUCT__entry( __field(u32, cl_boot) __field(u32, cl_id) __array(unsigned char, addr, sizeof(struct sockaddr_in6)) - __field(unsigned int, namelen) - __dynamic_array(unsigned char, name, clp->cl_name.len) + __field(unsigned long, flavor) + __array(unsigned char, verifier, NFS4_VERIFIER_SIZE) + __dynamic_array(char, name, clp->cl_name.len + 1) ), TP_fast_assign( __entry->cl_boot = clp->cl_clientid.cl_boot; __entry->cl_id = clp->cl_clientid.cl_id; memcpy(__entry->addr, &clp->cl_addr, sizeof(struct sockaddr_in6)); - __entry->namelen = clp->cl_name.len; - memcpy(__get_dynamic_array(name), clp->cl_name.data, - clp->cl_name.len); + __entry->flavor = clp->cl_cred.cr_flavor; + memcpy(__entry->verifier, (void *)&clp->cl_verifier, + NFS4_VERIFIER_SIZE); + memcpy(__get_str(name), clp->cl_name.data, clp->cl_name.len); + __get_str(name)[clp->cl_name.len] = '\0'; ), - TP_printk("nfs4_clientid %.*s already in use by %pISpc, client %08x:%08x", - __entry->namelen, __get_str(name), __entry->addr, + TP_printk("addr=%pISpc name='%s' verifier=0x%s flavor=%s client=%08x:%08x", + __entry->addr, __get_str(name), + __print_hex_str(__entry->verifier, NFS4_VERIFIER_SIZE), + show_nfsd_authflavor(__entry->flavor), __entry->cl_boot, __entry->cl_id) -) +); + +#define DEFINE_CLID_EVENT(name) \ +DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ + TP_PROTO(const struct nfs4_client *clp), \ + TP_ARGS(clp)) + +DEFINE_CLID_EVENT(fresh); +DEFINE_CLID_EVENT(confirmed_r); /* * from fs/nfsd/filecache.h @@ -809,9 +856,9 @@ TRACE_EVENT(nfsd_cb_args, memcpy(__entry->addr, &conn->cb_addr, sizeof(struct sockaddr_in6)); ), - TP_printk("client %08x:%08x callback addr=%pISpc prog=%u ident=%u", - __entry->cl_boot, __entry->cl_id, - __entry->addr, __entry->prog, __entry->ident) + TP_printk("addr=%pISpc client %08x:%08x prog=%u ident=%u", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->prog, __entry->ident) ); TRACE_EVENT(nfsd_cb_nodelegs, @@ -828,11 +875,6 @@ TRACE_EVENT(nfsd_cb_nodelegs, TP_printk("client %08x:%08x", __entry->cl_boot, __entry->cl_id) ) -TRACE_DEFINE_ENUM(NFSD4_CB_UP); -TRACE_DEFINE_ENUM(NFSD4_CB_UNKNOWN); -TRACE_DEFINE_ENUM(NFSD4_CB_DOWN); -TRACE_DEFINE_ENUM(NFSD4_CB_FAULT); - #define show_cb_state(val) \ __print_symbolic(val, \ { NFSD4_CB_UP, "UP" }, \ @@ -866,10 +908,53 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ TP_PROTO(const struct nfs4_client *clp), \ TP_ARGS(clp)) -DEFINE_NFSD_CB_EVENT(setup); DEFINE_NFSD_CB_EVENT(state); +DEFINE_NFSD_CB_EVENT(probe); +DEFINE_NFSD_CB_EVENT(lost); DEFINE_NFSD_CB_EVENT(shutdown); +TRACE_DEFINE_ENUM(RPC_AUTH_NULL); +TRACE_DEFINE_ENUM(RPC_AUTH_UNIX); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P); + +#define show_nfsd_authflavor(val) \ + __print_symbolic(val, \ + { RPC_AUTH_NULL, "none" }, \ + { RPC_AUTH_UNIX, "sys" }, \ + { RPC_AUTH_GSS, "gss" }, \ + { RPC_AUTH_GSS_KRB5, "krb5" }, \ + { RPC_AUTH_GSS_KRB5I, "krb5i" }, \ + { RPC_AUTH_GSS_KRB5P, "krb5p" }) + +TRACE_EVENT(nfsd_cb_setup, + TP_PROTO(const struct nfs4_client *clp, + const char *netid, + rpc_authflavor_t authflavor + ), + TP_ARGS(clp, netid, authflavor), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(unsigned long, authflavor) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + __array(unsigned char, netid, 8) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + strlcpy(__entry->netid, netid, sizeof(__entry->netid)); + __entry->authflavor = authflavor; + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->netid, show_nfsd_authflavor(__entry->authflavor)) +); + TRACE_EVENT(nfsd_cb_setup_err, TP_PROTO( const struct nfs4_client *clp, @@ -893,52 +978,97 @@ TRACE_EVENT(nfsd_cb_setup_err, __entry->addr, __entry->cl_boot, __entry->cl_id, __entry->error) ); -TRACE_EVENT(nfsd_cb_work, +TRACE_EVENT(nfsd_cb_recall, TP_PROTO( - const struct nfs4_client *clp, - const char *procedure + const struct nfs4_stid *stid ), - TP_ARGS(clp, procedure), + TP_ARGS(stid), TP_STRUCT__entry( __field(u32, cl_boot) __field(u32, cl_id) - __string(procedure, procedure) + __field(u32, si_id) + __field(u32, si_generation) __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ), TP_fast_assign( - __entry->cl_boot = clp->cl_clientid.cl_boot; - __entry->cl_id = clp->cl_clientid.cl_id; - __assign_str(procedure, procedure) - memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, - sizeof(struct sockaddr_in6)); + const stateid_t *stp = &stid->sc_stateid; + const struct nfs4_client *clp = stid->sc_client; + + __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; + __entry->cl_id = stp->si_opaque.so_clid.cl_id; + __entry->si_id = stp->si_opaque.so_id; + __entry->si_generation = stp->si_generation; + if (clp) + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + else + memset(__entry->addr, 0, sizeof(struct sockaddr_in6)); ), - TP_printk("addr=%pISpc client %08x:%08x procedure=%s", + TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x", __entry->addr, __entry->cl_boot, __entry->cl_id, - __get_str(procedure)) + __entry->si_id, __entry->si_generation) ); -TRACE_EVENT(nfsd_cb_done, +TRACE_EVENT(nfsd_cb_notify_lock, TP_PROTO( - const struct nfs4_client *clp, - int status + const struct nfs4_lockowner *lo, + const struct nfsd4_blocked_lock *nbl ), - TP_ARGS(clp, status), + TP_ARGS(lo, nbl), TP_STRUCT__entry( __field(u32, cl_boot) __field(u32, cl_id) - __field(int, status) + __field(u32, fh_hash) __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ), TP_fast_assign( + const struct nfs4_client *clp = lo->lo_owner.so_client; + __entry->cl_boot = clp->cl_clientid.cl_boot; __entry->cl_id = clp->cl_clientid.cl_id; - __entry->status = status; + __entry->fh_hash = knfsd_fh_hash(&nbl->nbl_fh); memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, sizeof(struct sockaddr_in6)); ), - TP_printk("addr=%pISpc client %08x:%08x status=%d", + TP_printk("addr=%pISpc client %08x:%08x fh_hash=0x%08x", __entry->addr, __entry->cl_boot, __entry->cl_id, - __entry->status) + __entry->fh_hash) +); + +TRACE_EVENT(nfsd_cb_offload, + TP_PROTO( + const struct nfs4_client *clp, + const stateid_t *stp, + const struct knfsd_fh *fh, + u64 count, + __be32 status + ), + TP_ARGS(clp, stp, fh, count, status), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(u32, si_id) + __field(u32, si_generation) + __field(u32, fh_hash) + __field(int, status) + __field(u64, count) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; + __entry->cl_id = stp->si_opaque.so_clid.cl_id; + __entry->si_id = stp->si_opaque.so_id; + __entry->si_generation = stp->si_generation; + __entry->fh_hash = knfsd_fh_hash(fh); + __entry->status = be32_to_cpu(status); + __entry->count = count; + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x fh_hash=0x%08x count=%llu status=%d", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->si_id, __entry->si_generation, + __entry->fh_hash, __entry->count, __entry->status) ); #endif /* _NFSD_TRACE_H */ diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 15adf1f6ab21..a224a5e23cc1 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1123,6 +1123,19 @@ out: } #ifdef CONFIG_NFSD_V3 +static int +nfsd_filemap_write_and_wait_range(struct nfsd_file *nf, loff_t offset, + loff_t end) +{ + struct address_space *mapping = nf->nf_file->f_mapping; + int ret = filemap_fdatawrite_range(mapping, offset, end); + + if (ret) + return ret; + filemap_fdatawait_range_keep_errors(mapping, offset, end); + return 0; +} + /* * Commit all pending writes to stable storage. * @@ -1153,10 +1166,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, if (err) goto out; if (EX_ISSYNC(fhp->fh_export)) { - int err2; + int err2 = nfsd_filemap_write_and_wait_range(nf, offset, end); down_write(&nf->nf_rwsem); - err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + if (!err2) + err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); switch (err2) { case 0: nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, @@ -1613,9 +1627,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path); err = nfserrno(host_err); + fh_unlock(fhp); if (!err) err = nfserrno(commit_metadata(fhp)); - fh_unlock(fhp); fh_drop_write(fhp); @@ -1680,6 +1694,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, if (d_really_is_negative(dold)) goto out_dput; host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); + fh_unlock(ffhp); if (!host_err) { err = nfserrno(commit_metadata(ffhp)); if (!err) @@ -1859,6 +1874,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, { struct dentry *dentry, *rdentry; struct inode *dirp; + struct inode *rinode; __be32 err; int host_err; @@ -1887,6 +1903,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, host_err = -ENOENT; goto out_drop_write; } + rinode = d_inode(rdentry); + ihold(rinode); if (!type) type = d_inode(rdentry)->i_mode & S_IFMT; @@ -1899,9 +1917,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, host_err = vfs_rmdir(&init_user_ns, dirp, rdentry); } + fh_unlock(fhp); if (!host_err) host_err = commit_metadata(fhp); dput(rdentry); + iput(rinode); /* truncate the inode here */ out_drop_write: fh_drop_write(fhp); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index a7c425254fee..3e4052e3bd50 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -567,6 +567,7 @@ struct nfsd4_copy { struct vfsmount *ss_mnt; struct nfs_fh c_fh; nfs4_stateid stateid; + bool committed; }; struct nfsd4_seek { diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 1bbb9fe661b1..fc718f6178f2 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2824,7 +2824,7 @@ void dbg_debugfs_init_fs(struct ubifs_info *c) n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, c->vi.ubi_num, c->vi.vol_id); - if (n == UBIFS_DFS_DIR_LEN) { + if (n > UBIFS_DFS_DIR_LEN) { /* The array size is too small */ return; } diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 5bd8482e660a..7c61d0ec0159 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1337,7 +1337,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_release; } + spin_lock(&whiteout->i_lock); whiteout->i_state |= I_LINKABLE; + spin_unlock(&whiteout->i_lock); + whiteout_ui = ubifs_inode(whiteout); whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); @@ -1430,7 +1433,11 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, inc_nlink(whiteout); mark_inode_dirty(whiteout); + + spin_lock(&whiteout->i_lock); whiteout->i_state &= ~I_LINKABLE; + spin_unlock(&whiteout->i_lock); + iput(whiteout); } diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 2857e64d673d..8ea680dba61e 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -882,6 +882,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) struct ubifs_dent_node *xent, *pxent = NULL; if (ui->xattr_cnt > ubifs_xattr_max_cnt(c)) { + err = -EPERM; ubifs_err(c, "Cannot delete inode, it has too much xattrs!"); goto out_release; } @@ -1431,7 +1432,7 @@ out_free: /** * truncate_data_node - re-compress/encrypt a truncated data node. * @c: UBIFS file-system description object - * @inode: inode which referes to the data node + * @inode: inode which refers to the data node * @block: data block number * @dn: data node to re-compress * @new_len: new length diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c index 0df9a3dd0aaa..7adc37c10b6a 100644 --- a/fs/ubifs/master.c +++ b/fs/ubifs/master.c @@ -37,7 +37,7 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2) return ret; /* - * Do not compare the embedded HMAC aswell which also must be different + * Do not compare the embedded HMAC as well which also must be different * due to the different common node header. */ behind = hmac_offs + UBIFS_MAX_HMAC_LEN; diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 382a54c82930..5260d3e531bb 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -296,7 +296,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) * @b: second replay entry * * This is a comparios function for 'list_sort()' which compares 2 replay - * entries @a and @b by comparing their sequence numer. Returns %1 if @a has + * entries @a and @b by comparing their sequence number. Returns %1 if @a has * greater sequence number and %-1 otherwise. */ static int replay_entries_cmp(void *priv, const struct list_head *a, diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 7b572e1414ba..f0fb25727d96 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -275,6 +275,7 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb) memset((void *)ui + sizeof(struct inode), 0, sizeof(struct ubifs_inode) - sizeof(struct inode)); mutex_init(&ui->ui_mutex); + init_rwsem(&ui->xattr_sem); spin_lock_init(&ui->ui_lock); return &ui->vfs_inode; }; @@ -2060,7 +2061,7 @@ const struct super_operations ubifs_super_operations = { * @mode: UBI volume open mode * * The primary method of mounting UBIFS is by specifying the UBI volume - * character device node path. However, UBIFS may also be mounted withoug any + * character device node path. However, UBIFS may also be mounted without any * character device node using one of the following methods: * * o ubiX_Y - mount UBI device number X, volume Y; diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 234be1c4dc87..58c92c96ecef 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -930,7 +930,7 @@ static int write_index(struct ubifs_info *c) * flag cleared before %COW_ZNODE. Specifically, it matters in * the 'dirty_cow_znode()' function. This is the reason for the * first barrier. Also, we want the bit changes to be seen to - * other threads ASAP, to avoid unnecesarry copying, which is + * other threads ASAP, to avoid unnecessary copying, which is * the reason for the second barrier. */ clear_bit(DIRTY_ZNODE, &znode->flags); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index b65c599a386a..c38066ce9ab0 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -356,6 +356,7 @@ struct ubifs_gced_idx_leb { * @ui_mutex: serializes inode write-back with the rest of VFS operations, * serializes "clean <-> dirty" state changes, serializes bulk-read, * protects @dirty, @bulk_read, @ui_size, and @xattr_size + * @xattr_sem: serilizes write operations (remove|set|create) on xattr * @ui_lock: protects @synced_i_size * @synced_i_size: synchronized size of inode, i.e. the value of inode size * currently stored on the flash; used only for regular file @@ -409,6 +410,7 @@ struct ubifs_inode { unsigned int bulk_read:1; unsigned int compr_type:2; struct mutex ui_mutex; + struct rw_semaphore xattr_sem; spinlock_t ui_lock; loff_t synced_i_size; loff_t ui_size; @@ -912,7 +914,7 @@ struct ubifs_budget_req { * @rb: rb-tree node of rb-tree of orphans sorted by inode number * @list: list head of list of orphans in order added * @new_list: list head of list of orphans added since the last commit - * @child_list: list of xattr childs if this orphan hosts xattrs, list head + * @child_list: list of xattr children if this orphan hosts xattrs, list head * if this orphan is a xattr, not used otherwise. * @cnext: next orphan to commit * @dnext: next orphan to delete diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 6b1e9830b274..e4f193eae4b2 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -208,13 +208,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, err = -ENOMEM; goto out_free; } - mutex_lock(&ui->ui_mutex); kfree(ui->data); ui->data = buf; inode->i_size = ui->ui_size = size; old_size = ui->data_len; ui->data_len = size; - mutex_unlock(&ui->ui_mutex); mutex_lock(&host_ui->ui_mutex); host->i_ctime = current_time(host); @@ -285,6 +283,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value, if (!xent) return -ENOMEM; + down_write(&ubifs_inode(host)->xattr_sem); /* * The extended attribute entries are stored in LNC, so multiple * look-ups do not involve reading the flash. @@ -319,6 +318,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value, iput(inode); out_free: + up_write(&ubifs_inode(host)->xattr_sem); kfree(xent); return err; } @@ -341,25 +341,25 @@ ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf, if (!xent) return -ENOMEM; + down_read(&ubifs_inode(host)->xattr_sem); xent_key_init(c, &key, host->i_ino, &nm); err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); if (err) { if (err == -ENOENT) err = -ENODATA; - goto out_unlock; + goto out_cleanup; } inode = iget_xattr(c, le64_to_cpu(xent->inum)); if (IS_ERR(inode)) { err = PTR_ERR(inode); - goto out_unlock; + goto out_cleanup; } ui = ubifs_inode(inode); ubifs_assert(c, inode->i_size == ui->data_len); ubifs_assert(c, ubifs_inode(host)->xattr_size > ui->data_len); - mutex_lock(&ui->ui_mutex); if (buf) { /* If @buf is %NULL we are supposed to return the length */ if (ui->data_len > size) { @@ -372,9 +372,9 @@ ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf, err = ui->data_len; out_iput: - mutex_unlock(&ui->ui_mutex); iput(inode); -out_unlock: +out_cleanup: + up_read(&ubifs_inode(host)->xattr_sem); kfree(xent); return err; } @@ -406,16 +406,21 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino, dentry, size); + down_read(&host_ui->xattr_sem); len = host_ui->xattr_names + host_ui->xattr_cnt; - if (!buffer) + if (!buffer) { /* * We should return the minimum buffer size which will fit a * null-terminated list of all the extended attribute names. */ - return len; + err = len; + goto out_err; + } - if (len > size) - return -ERANGE; + if (len > size) { + err = -ERANGE; + goto out_err; + } lowest_xent_key(c, &key, host->i_ino); while (1) { @@ -437,8 +442,9 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) pxent = xent; key_read(c, &xent->key, &key); } - kfree(pxent); + up_read(&host_ui->xattr_sem); + if (err != -ENOENT) { ubifs_err(c, "cannot find next direntry, error %d", err); return err; @@ -446,6 +452,10 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ubifs_assert(c, written <= size); return written; + +out_err: + up_read(&host_ui->xattr_sem); + return err; } static int remove_xattr(struct ubifs_info *c, struct inode *host, @@ -504,6 +514,7 @@ int ubifs_purge_xattrs(struct inode *host) ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion", host->i_ino); + down_write(&ubifs_inode(host)->xattr_sem); lowest_xent_key(c, &key, host->i_ino); while (1) { xent = ubifs_tnc_next_ent(c, &key, &nm); @@ -523,7 +534,7 @@ int ubifs_purge_xattrs(struct inode *host) ubifs_ro_mode(c, err); kfree(pxent); kfree(xent); - return err; + goto out_err; } ubifs_assert(c, ubifs_inode(xino)->xattr); @@ -535,7 +546,7 @@ int ubifs_purge_xattrs(struct inode *host) kfree(xent); iput(xino); ubifs_err(c, "cannot remove xattr, error %d", err); - return err; + goto out_err; } iput(xino); @@ -544,14 +555,19 @@ int ubifs_purge_xattrs(struct inode *host) pxent = xent; key_read(c, &xent->key, &key); } - kfree(pxent); + up_write(&ubifs_inode(host)->xattr_sem); + if (err != -ENOENT) { ubifs_err(c, "cannot find next direntry, error %d", err); return err; } return 0; + +out_err: + up_write(&ubifs_inode(host)->xattr_sem); + return err; } /** @@ -594,6 +610,7 @@ static int ubifs_xattr_remove(struct inode *host, const char *name) if (!xent) return -ENOMEM; + down_write(&ubifs_inode(host)->xattr_sem); xent_key_init(c, &key, host->i_ino, &nm); err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); if (err) { @@ -618,6 +635,7 @@ static int ubifs_xattr_remove(struct inode *host, const char *name) iput(inode); out_free: + up_write(&ubifs_inode(host)->xattr_sem); kfree(xent); return err; } diff --git a/include/asm-generic/logic_io.h b/include/asm-generic/logic_io.h new file mode 100644 index 000000000000..a53116b8c57e --- /dev/null +++ b/include/asm-generic/logic_io.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Intel Corporation + * Author: johannes@sipsolutions.net + */ +#ifndef _LOGIC_IO_H +#define _LOGIC_IO_H +#include + +/* include this file into asm/io.h */ + +#ifdef CONFIG_INDIRECT_IOMEM + +#ifdef CONFIG_INDIRECT_IOMEM_FALLBACK +/* + * If you want emulated IO memory to fall back to 'normal' IO memory + * if a region wasn't registered as emulated, then you need to have + * all of the real_* functions implemented. + */ +#if !defined(real_ioremap) || !defined(real_iounmap) || \ + !defined(real_raw_readb) || !defined(real_raw_writeb) || \ + !defined(real_raw_readw) || !defined(real_raw_writew) || \ + !defined(real_raw_readl) || !defined(real_raw_writel) || \ + (defined(CONFIG_64BIT) && \ + (!defined(real_raw_readq) || !defined(real_raw_writeq))) || \ + !defined(real_memset_io) || \ + !defined(real_memcpy_fromio) || \ + !defined(real_memcpy_toio) +#error "Must provide fallbacks for real IO memory access" +#endif /* defined ... */ +#endif /* CONFIG_INDIRECT_IOMEM_FALLBACK */ + +#define ioremap ioremap +void __iomem *ioremap(phys_addr_t offset, size_t size); + +#define iounmap iounmap +void iounmap(void __iomem *addr); + +#define __raw_readb __raw_readb +u8 __raw_readb(const volatile void __iomem *addr); + +#define __raw_readw __raw_readw +u16 __raw_readw(const volatile void __iomem *addr); + +#define __raw_readl __raw_readl +u32 __raw_readl(const volatile void __iomem *addr); + +#ifdef CONFIG_64BIT +#define __raw_readq __raw_readq +u64 __raw_readq(const volatile void __iomem *addr); +#endif /* CONFIG_64BIT */ + +#define __raw_writeb __raw_writeb +void __raw_writeb(u8 value, volatile void __iomem *addr); + +#define __raw_writew __raw_writew +void __raw_writew(u16 value, volatile void __iomem *addr); + +#define __raw_writel __raw_writel +void __raw_writel(u32 value, volatile void __iomem *addr); + +#ifdef CONFIG_64BIT +#define __raw_writeq __raw_writeq +void __raw_writeq(u64 value, volatile void __iomem *addr); +#endif /* CONFIG_64BIT */ + +#define memset_io memset_io +void memset_io(volatile void __iomem *addr, int value, size_t size); + +#define memcpy_fromio memcpy_fromio +void memcpy_fromio(void *buffer, const volatile void __iomem *addr, + size_t size); + +#define memcpy_toio memcpy_toio +void memcpy_toio(volatile void __iomem *addr, const void *buffer, size_t size); + +#endif /* CONFIG_INDIRECT_IOMEM */ +#endif /* _LOGIC_IO_H */ diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h index 2f6b1befb129..03b7dae47dd4 100644 --- a/include/asm-generic/pgtable-nop4d.h +++ b/include/asm-generic/pgtable-nop4d.h @@ -41,7 +41,7 @@ static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) #define __p4d(x) ((p4d_t) { __pgd(x) }) #define pgd_page(pgd) (p4d_page((p4d_t){ pgd })) -#define pgd_page_vaddr(pgd) (p4d_page_vaddr((p4d_t){ pgd })) +#define pgd_page_vaddr(pgd) ((unsigned long)(p4d_pgtable((p4d_t){ pgd }))) /* * allocating and freeing a p4d is trivial: the 1-entry p4d is diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h index 3e13acd019ae..10789cf51d16 100644 --- a/include/asm-generic/pgtable-nopmd.h +++ b/include/asm-generic/pgtable-nopmd.h @@ -51,7 +51,7 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address) #define __pmd(x) ((pmd_t) { __pud(x) } ) #define pud_page(pud) (pmd_page((pmd_t){ pud })) -#define pud_page_vaddr(pud) (pmd_page_vaddr((pmd_t){ pud })) +#define pud_pgtable(pud) ((pmd_t *)(pmd_page_vaddr((pmd_t){ pud }))) /* * allocating and freeing a pmd is trivial: the 1-entry pmd is diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h index a9d751fbda9e..eb70c6d7ceff 100644 --- a/include/asm-generic/pgtable-nopud.h +++ b/include/asm-generic/pgtable-nopud.h @@ -49,7 +49,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address) #define __pud(x) ((pud_t) { __p4d(x) }) #define p4d_page(p4d) (pud_page((pud_t){ p4d })) -#define p4d_page_vaddr(p4d) (pud_page_vaddr((pud_t){ p4d })) +#define p4d_pgtable(p4d) ((pud_t *)(pud_pgtable((pud_t){ p4d }))) /* * allocating and freeing a pud is trivial: the 1-entry pud is diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index c837d0775474..7af08174a721 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -81,12 +81,7 @@ static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out, struct page *page; page = sg_page(walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT); - /* Test ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE first as - * PageSlab cannot be optimised away per se due to - * use of volatile pointer. - */ - if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE && !PageSlab(page)) - flush_dcache_page(page); + flush_dcache_page(page); } if (more && walk->offset >= walk->sg->offset + walk->sg->length) diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h index 3acebe937bfc..3d00c98b9654 100644 --- a/include/dt-bindings/clock/mt8173-clk.h +++ b/include/dt-bindings/clock/mt8173-clk.h @@ -186,7 +186,6 @@ #define CLK_INFRA_PMICWRAP 11 #define CLK_INFRA_CLK_13M 12 #define CLK_INFRA_CA53SEL 13 -#define CLK_INFRA_CA57SEL 14 /* Deprecated. Don't use it. */ #define CLK_INFRA_CA72SEL 14 #define CLK_INFRA_NR_CLK 15 diff --git a/include/dt-bindings/mailbox/qcom-ipcc.h b/include/dt-bindings/mailbox/qcom-ipcc.h index 4c23eefed5f3..eb91a6c05b71 100644 --- a/include/dt-bindings/mailbox/qcom-ipcc.h +++ b/include/dt-bindings/mailbox/qcom-ipcc.h @@ -29,5 +29,6 @@ #define IPCC_CLIENT_PCIE1 14 #define IPCC_CLIENT_PCIE2 15 #define IPCC_CLIENT_SPSS 16 +#define IPCC_CLIENT_WPSS 24 #endif diff --git a/include/dt-bindings/pinctrl/hisi.h b/include/dt-bindings/pinctrl/hisi.h index 0359bfdc9119..93064c750c8c 100644 --- a/include/dt-bindings/pinctrl/hisi.h +++ b/include/dt-bindings/pinctrl/hisi.h @@ -1,7 +1,7 @@ /* * This header provides constants for hisilicon pinctrl bindings. * - * Copyright (c) 2015 Hisilicon Limited. + * Copyright (c) 2015 HiSilicon Limited. * Copyright (c) 2015 Linaro Limited. * * This program is free software; you can redistribute it and/or modify diff --git a/include/dt-bindings/power/imx8mm-power.h b/include/dt-bindings/power/imx8mm-power.h new file mode 100644 index 000000000000..fc9c2e16aadc --- /dev/null +++ b/include/dt-bindings/power/imx8mm-power.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (C) 2020 Pengutronix, Lucas Stach + */ + +#ifndef __DT_BINDINGS_IMX8MM_POWER_H__ +#define __DT_BINDINGS_IMX8MM_POWER_H__ + +#define IMX8MM_POWER_DOMAIN_HSIOMIX 0 +#define IMX8MM_POWER_DOMAIN_PCIE 1 +#define IMX8MM_POWER_DOMAIN_OTG1 2 +#define IMX8MM_POWER_DOMAIN_OTG2 3 +#define IMX8MM_POWER_DOMAIN_GPUMIX 4 +#define IMX8MM_POWER_DOMAIN_GPU 5 +#define IMX8MM_POWER_DOMAIN_VPUMIX 6 +#define IMX8MM_POWER_DOMAIN_VPUG1 7 +#define IMX8MM_POWER_DOMAIN_VPUG2 8 +#define IMX8MM_POWER_DOMAIN_VPUH1 9 +#define IMX8MM_POWER_DOMAIN_DISPMIX 10 +#define IMX8MM_POWER_DOMAIN_MIPI 11 + +#endif diff --git a/include/dt-bindings/power/imx8mn-power.h b/include/dt-bindings/power/imx8mn-power.h new file mode 100644 index 000000000000..102ee85a9b62 --- /dev/null +++ b/include/dt-bindings/power/imx8mn-power.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (C) 2020 Compass Electronics Group, LLC + */ + +#ifndef __DT_BINDINGS_IMX8MN_POWER_H__ +#define __DT_BINDINGS_IMX8MN_POWER_H__ + +#define IMX8MN_POWER_DOMAIN_HSIOMIX 0 +#define IMX8MN_POWER_DOMAIN_OTG1 1 +#define IMX8MN_POWER_DOMAIN_GPUMIX 2 +#define IMX8MN_POWER_DOMAIN_DISPMIX 3 +#define IMX8MN_POWER_DOMAIN_MIPI 4 + +#endif diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index eedb5d94c020..8b5708bb9671 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -81,6 +81,19 @@ #define SC7280_LCX 7 #define SC7280_MSS 8 +/* SC8180X Power Domain Indexes */ +#define SC8180X_CX 0 +#define SC8180X_CX_AO 1 +#define SC8180X_EBI 2 +#define SC8180X_GFX 3 +#define SC8180X_LCX 4 +#define SC8180X_LMX 5 +#define SC8180X_MMCX 6 +#define SC8180X_MMCX_AO 7 +#define SC8180X_MSS 8 +#define SC8180X_MX 9 +#define SC8180X_MX_AO 10 + /* SDM845 Power Domain performance levels */ #define RPMH_REGULATOR_LEVEL_RETENTION 16 #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 @@ -95,6 +108,14 @@ #define RPMH_REGULATOR_LEVEL_TURBO 384 #define RPMH_REGULATOR_LEVEL_TURBO_L1 416 +/* MDM9607 Power Domains */ +#define MDM9607_VDDCX 0 +#define MDM9607_VDDCX_AO 1 +#define MDM9607_VDDCX_VFL 2 +#define MDM9607_VDDMX 3 +#define MDM9607_VDDMX_AO 4 +#define MDM9607_VDDMX_VFL 5 + /* MSM8939 Power Domains */ #define MSM8939_VDDMDCX 0 #define MSM8939_VDDMDCX_AO 1 diff --git a/include/dt-bindings/power/rk3568-power.h b/include/dt-bindings/power/rk3568-power.h new file mode 100644 index 000000000000..6cc1af1a9d26 --- /dev/null +++ b/include/dt-bindings/power/rk3568-power.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_POWER_RK3568_POWER_H__ +#define __DT_BINDINGS_POWER_RK3568_POWER_H__ + +/* VD_CORE */ +#define RK3568_PD_CPU_0 0 +#define RK3568_PD_CPU_1 1 +#define RK3568_PD_CPU_2 2 +#define RK3568_PD_CPU_3 3 +#define RK3568_PD_CORE_ALIVE 4 + +/* VD_PMU */ +#define RK3568_PD_PMU 5 + +/* VD_NPU */ +#define RK3568_PD_NPU 6 + +/* VD_GPU */ +#define RK3568_PD_GPU 7 + +/* VD_LOGIC */ +#define RK3568_PD_VI 8 +#define RK3568_PD_VO 9 +#define RK3568_PD_RGA 10 +#define RK3568_PD_VPU 11 +#define RK3568_PD_CENTER 12 +#define RK3568_PD_RKVDEC 13 +#define RK3568_PD_RKVENC 14 +#define RK3568_PD_PIPE 15 +#define RK3568_PD_LOGIC_ALIVE 16 + +#endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 6bb36fd6ba31..72e4f7fd268c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -554,8 +554,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); #define OSC_SB_OSLPI_SUPPORT 0x00000100 #define OSC_SB_CPC_DIVERSE_HIGH_SUPPORT 0x00001000 #define OSC_SB_GENERIC_INITIATOR_SUPPORT 0x00002000 -#define OSC_SB_PRM_SUPPORT 0x00020000 #define OSC_SB_NATIVE_USB4_SUPPORT 0x00040000 +#define OSC_SB_PRM_SUPPORT 0x00200000 extern bool osc_sb_apei_support_acked; extern bool osc_pc_lpi_support_confirmed; diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 00996dec02cb..f99a7fd8b268 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -38,6 +38,7 @@ bool topology_scale_freq_invariant(void); enum scale_freq_source { SCALE_FREQ_SOURCE_CPUFREQ = 0, SCALE_FREQ_SOURCE_ARCH, + SCALE_FREQ_SOURCE_CPPC, }; struct scale_freq_data { diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h new file mode 100644 index 000000000000..505c679b6a9b --- /dev/null +++ b/include/linux/arm_ffa.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 ARM Ltd. + */ + +#ifndef _LINUX_ARM_FFA_H +#define _LINUX_ARM_FFA_H + +#include +#include +#include +#include + +/* FFA Bus/Device/Driver related */ +struct ffa_device { + int vm_id; + bool mode_32bit; + uuid_t uuid; + struct device dev; +}; + +#define to_ffa_dev(d) container_of(d, struct ffa_device, dev) + +struct ffa_device_id { + uuid_t uuid; +}; + +struct ffa_driver { + const char *name; + int (*probe)(struct ffa_device *sdev); + void (*remove)(struct ffa_device *sdev); + const struct ffa_device_id *id_table; + + struct device_driver driver; +}; + +#define to_ffa_driver(d) container_of(d, struct ffa_driver, driver) + +static inline void ffa_dev_set_drvdata(struct ffa_device *fdev, void *data) +{ + fdev->dev.driver_data = data; +} + +#if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id); +void ffa_device_unregister(struct ffa_device *ffa_dev); +int ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name); +void ffa_driver_unregister(struct ffa_driver *driver); +bool ffa_device_is_valid(struct ffa_device *ffa_dev); +const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev); + +#else +static inline +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) +{ + return NULL; +} + +static inline void ffa_device_unregister(struct ffa_device *dev) {} + +static inline int +ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name) +{ + return -EINVAL; +} + +static inline void ffa_driver_unregister(struct ffa_driver *driver) {} + +static inline +bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } + +static inline +const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) +{ + return NULL; +} +#endif /* CONFIG_ARM_FFA_TRANSPORT */ + +#define ffa_register(driver) \ + ffa_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) +#define ffa_unregister(driver) \ + ffa_driver_unregister(driver) + +/** + * module_ffa_driver() - Helper macro for registering a psa_ffa driver + * @__ffa_driver: ffa_driver structure + * + * Helper macro for psa_ffa drivers to set up proper module init / exit + * functions. Replaces module_init() and module_exit() and keeps people from + * printing pointless things to the kernel log when their driver is loaded. + */ +#define module_ffa_driver(__ffa_driver) \ + module_driver(__ffa_driver, ffa_register, ffa_unregister) + +/* FFA transport related */ +struct ffa_partition_info { + u16 id; + u16 exec_ctxt; +/* partition supports receipt of direct requests */ +#define FFA_PARTITION_DIRECT_RECV BIT(0) +/* partition can send direct requests. */ +#define FFA_PARTITION_DIRECT_SEND BIT(1) +/* partition can send and receive indirect messages. */ +#define FFA_PARTITION_INDIRECT_MSG BIT(2) + u32 properties; +}; + +/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */ +struct ffa_send_direct_data { + unsigned long data0; /* w3/x3 */ + unsigned long data1; /* w4/x4 */ + unsigned long data2; /* w5/x5 */ + unsigned long data3; /* w6/x6 */ + unsigned long data4; /* w7/x7 */ +}; + +struct ffa_mem_region_addr_range { + /* The base IPA of the constituent memory region, aligned to 4 kiB */ + u64 address; + /* The number of 4 kiB pages in the constituent memory region. */ + u32 pg_cnt; + u32 reserved; +}; + +struct ffa_composite_mem_region { + /* + * The total number of 4 kiB pages included in this memory region. This + * must be equal to the sum of page counts specified in each + * `struct ffa_mem_region_addr_range`. + */ + u32 total_pg_cnt; + /* The number of constituents included in this memory region range */ + u32 addr_range_cnt; + u64 reserved; + /** An array of `addr_range_cnt` memory region constituents. */ + struct ffa_mem_region_addr_range constituents[]; +}; + +struct ffa_mem_region_attributes { + /* The ID of the VM to which the memory is being given or shared. */ + u16 receiver; + /* + * The permissions with which the memory region should be mapped in the + * receiver's page table. + */ +#define FFA_MEM_EXEC BIT(3) +#define FFA_MEM_NO_EXEC BIT(2) +#define FFA_MEM_RW BIT(1) +#define FFA_MEM_RO BIT(0) + u8 attrs; + /* + * Flags used during FFA_MEM_RETRIEVE_REQ and FFA_MEM_RETRIEVE_RESP + * for memory regions with multiple borrowers. + */ +#define FFA_MEM_RETRIEVE_SELF_BORROWER BIT(0) + u8 flag; + u32 composite_off; + /* + * Offset in bytes from the start of the outer `ffa_memory_region` to + * an `struct ffa_mem_region_addr_range`. + */ + u64 reserved; +}; + +struct ffa_mem_region { + /* The ID of the VM/owner which originally sent the memory region */ + u16 sender_id; +#define FFA_MEM_NORMAL BIT(5) +#define FFA_MEM_DEVICE BIT(4) + +#define FFA_MEM_WRITE_BACK (3 << 2) +#define FFA_MEM_NON_CACHEABLE (1 << 2) + +#define FFA_DEV_nGnRnE (0 << 2) +#define FFA_DEV_nGnRE (1 << 2) +#define FFA_DEV_nGRE (2 << 2) +#define FFA_DEV_GRE (3 << 2) + +#define FFA_MEM_NON_SHAREABLE (0) +#define FFA_MEM_OUTER_SHAREABLE (2) +#define FFA_MEM_INNER_SHAREABLE (3) + u8 attributes; + u8 reserved_0; +/* + * Clear memory region contents after unmapping it from the sender and + * before mapping it for any receiver. + */ +#define FFA_MEM_CLEAR BIT(0) +/* + * Whether the hypervisor may time slice the memory sharing or retrieval + * operation. + */ +#define FFA_TIME_SLICE_ENABLE BIT(1) + +#define FFA_MEM_RETRIEVE_TYPE_IN_RESP (0 << 3) +#define FFA_MEM_RETRIEVE_TYPE_SHARE (1 << 3) +#define FFA_MEM_RETRIEVE_TYPE_LEND (2 << 3) +#define FFA_MEM_RETRIEVE_TYPE_DONATE (3 << 3) + +#define FFA_MEM_RETRIEVE_ADDR_ALIGN_HINT BIT(9) +#define FFA_MEM_RETRIEVE_ADDR_ALIGN(x) ((x) << 5) + /* Flags to control behaviour of the transaction. */ + u32 flags; +#define HANDLE_LOW_MASK GENMASK_ULL(31, 0) +#define HANDLE_HIGH_MASK GENMASK_ULL(63, 32) +#define HANDLE_LOW(x) ((u32)(FIELD_GET(HANDLE_LOW_MASK, (x)))) +#define HANDLE_HIGH(x) ((u32)(FIELD_GET(HANDLE_HIGH_MASK, (x)))) + +#define PACK_HANDLE(l, h) \ + (FIELD_PREP(HANDLE_LOW_MASK, (l)) | FIELD_PREP(HANDLE_HIGH_MASK, (h))) + /* + * A globally-unique ID assigned by the hypervisor for a region + * of memory being sent between VMs. + */ + u64 handle; + /* + * An implementation defined value associated with the receiver and the + * memory region. + */ + u64 tag; + u32 reserved_1; + /* + * The number of `ffa_mem_region_attributes` entries included in this + * transaction. + */ + u32 ep_count; + /* + * An array of endpoint memory access descriptors. + * Each one specifies a memory region offset, an endpoint and the + * attributes with which this memory region should be mapped in that + * endpoint's page table. + */ + struct ffa_mem_region_attributes ep_mem_access[]; +}; + +#define COMPOSITE_OFFSET(x) \ + (offsetof(struct ffa_mem_region, ep_mem_access[x])) +#define CONSTITUENTS_OFFSET(x) \ + (offsetof(struct ffa_composite_mem_region, constituents[x])) +#define COMPOSITE_CONSTITUENTS_OFFSET(x, y) \ + (COMPOSITE_OFFSET(x) + CONSTITUENTS_OFFSET(y)) + +struct ffa_mem_ops_args { + bool use_txbuf; + u32 nattrs; + u32 flags; + u64 tag; + u64 g_handle; + struct scatterlist *sg; + struct ffa_mem_region_attributes *attrs; +}; + +struct ffa_dev_ops { + u32 (*api_version_get)(void); + int (*partition_info_get)(const char *uuid_str, + struct ffa_partition_info *buffer); + void (*mode_32bit_set)(struct ffa_device *dev); + int (*sync_send_receive)(struct ffa_device *dev, + struct ffa_send_direct_data *data); + int (*memory_reclaim)(u64 g_handle, u32 flags); + int (*memory_share)(struct ffa_device *dev, + struct ffa_mem_ops_args *args); +}; + +#endif /* _LINUX_ARM_FFA_H */ diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index fd2de2b422ed..1d18447ebebc 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -439,8 +439,6 @@ enum { struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata); struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); -struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, - void *queuedata); int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, struct request_queue *q); void blk_mq_unregister_dev(struct device *, struct request_queue *); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 550d485cfec2..c2890767ac3e 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -354,9 +354,6 @@ enum req_opf { /* reset all the zone present on the device */ REQ_OP_ZONE_RESET_ALL = 17, - /* SCSI passthrough using struct scsi_request */ - REQ_OP_SCSI_IN = 32, - REQ_OP_SCSI_OUT = 33, /* Driver private requests */ REQ_OP_DRV_IN = 34, REQ_OP_DRV_OUT = 35, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 103acc5228e7..3177181c4326 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -240,42 +240,15 @@ struct request { void *end_io_data; }; -static inline bool blk_op_is_scsi(unsigned int op) -{ - return op == REQ_OP_SCSI_IN || op == REQ_OP_SCSI_OUT; -} - -static inline bool blk_op_is_private(unsigned int op) +static inline bool blk_op_is_passthrough(unsigned int op) { + op &= REQ_OP_MASK; return op == REQ_OP_DRV_IN || op == REQ_OP_DRV_OUT; } -static inline bool blk_rq_is_scsi(struct request *rq) -{ - return blk_op_is_scsi(req_op(rq)); -} - -static inline bool blk_rq_is_private(struct request *rq) -{ - return blk_op_is_private(req_op(rq)); -} - static inline bool blk_rq_is_passthrough(struct request *rq) { - return blk_rq_is_scsi(rq) || blk_rq_is_private(rq); -} - -static inline bool bio_is_passthrough(struct bio *bio) -{ - unsigned op = bio_op(bio); - - return blk_op_is_scsi(op) || blk_op_is_private(op); -} - -static inline bool blk_op_is_passthrough(unsigned int op) -{ - return (blk_op_is_scsi(op & REQ_OP_MASK) || - blk_op_is_private(op & REQ_OP_MASK)); + return blk_op_is_passthrough(req_op(rq)); } static inline unsigned short req_get_ioprio(struct request *req) @@ -936,10 +909,12 @@ extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, uns extern int blk_rq_map_user_iov(struct request_queue *, struct request *, struct rq_map_data *, const struct iov_iter *, gfp_t); -extern void blk_execute_rq(struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(struct gendisk *, struct request *, int, rq_end_io_fn *); +blk_status_t blk_execute_rq(struct gendisk *bd_disk, struct request *rq, + int at_head); + /* Helper to convert REQ_OP_XXX to its string format XXX */ extern const char *blk_op_str(unsigned int op); diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index 6bdd94cff4e2..abe089c27529 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -214,10 +214,10 @@ static inline struct xbc_node * __init xbc_node_get_subkey(struct xbc_node *node * @value: Iterated value of array entry. * * Iterate array entries of given @key under @node. Each array entry node - * is stroed to @anode and @value. If the @node doesn't have @key node, + * is stored to @anode and @value. If the @node doesn't have @key node, * it does nothing. * Note that even if the found key node has only one value (not array) - * this executes block once. Hoever, if the found key node has no value + * this executes block once. However, if the found key node has no value * (key-only node), this does nothing. So don't use this for testing the * key-value pair existence. */ diff --git a/include/linux/buildid.h b/include/linux/buildid.h index 40232f90db6e..3b7a0ff4642f 100644 --- a/include/linux/buildid.h +++ b/include/linux/buildid.h @@ -8,5 +8,13 @@ int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size); +int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size); + +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) || IS_ENABLED(CONFIG_CRASH_CORE) +extern unsigned char vmlinux_build_id[BUILD_ID_SIZE_MAX]; +void init_vmlinux_build_id(void); +#else +static inline void init_vmlinux_build_id(void) { } +#endif #endif diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 0862317f3175..77ccafab29a2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -643,6 +643,12 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, u8 width, unsigned long flags, unsigned int val); +int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req, + const struct clk_div_table *table, u8 width, + unsigned long flags); +int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val); int divider_get_val(unsigned long rate, unsigned long parent_rate, const struct clk_div_table *table, u8 width, unsigned long flags); diff --git a/include/linux/compaction.h b/include/linux/compaction.h index 4221888bdcd6..c24098c7acca 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h @@ -35,12 +35,12 @@ enum compact_result { COMPACT_CONTINUE, /* - * The full zone was compacted scanned but wasn't successfull to compact + * The full zone was compacted scanned but wasn't successful to compact * suitable pages. */ COMPACT_COMPLETE, /* - * direct compaction has scanned part of the zone but wasn't successfull + * direct compaction has scanned part of the zone but wasn't successful * to compact suitable pages. */ COMPACT_PARTIAL_SKIPPED, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 41710d07ac6a..c6f114cabcaf 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -330,15 +330,6 @@ struct cpufreq_driver { unsigned long target_perf, unsigned long capacity); - /* - * Caches and returns the lowest driver-supported frequency greater than - * or equal to the target frequency, subject to any driver limitations. - * Does not set the frequency. Only to be implemented for drivers with - * target(). - */ - unsigned int (*resolve_freq)(struct cpufreq_policy *policy, - unsigned int target_freq); - /* * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION * unset. @@ -371,7 +362,6 @@ struct cpufreq_driver { int (*online)(struct cpufreq_policy *policy); int (*offline)(struct cpufreq_policy *policy); int (*exit)(struct cpufreq_policy *policy); - void (*stop_cpu)(struct cpufreq_policy *policy); int (*suspend)(struct cpufreq_policy *policy); int (*resume)(struct cpufreq_policy *policy); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 47e13582d9fc..f39b34b13871 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -171,7 +171,6 @@ enum cpuhp_state { CPUHP_AP_PERF_X86_CSTATE_ONLINE, CPUHP_AP_PERF_X86_IDXD_ONLINE, CPUHP_AP_PERF_S390_CF_ONLINE, - CPUHP_AP_PERF_S390_CFD_ONLINE, CPUHP_AP_PERF_S390_SF_ONLINE, CPUHP_AP_PERF_ARM_CCI_ONLINE, CPUHP_AP_PERF_ARM_CCN_ONLINE, diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index bfc4690de4f4..f3689a52bfd0 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -259,7 +259,7 @@ extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool /** * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location * @cpu: the (optionally unsigned) integer iterator - * @mask: the cpumask poiter + * @mask: the cpumask pointer * @start: the start location * * The implementation does not assume any bit in @mask is set (including @start). diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h index 206bde8308b2..de62a722431e 100644 --- a/include/linux/crash_core.h +++ b/include/linux/crash_core.h @@ -38,8 +38,12 @@ phys_addr_t paddr_vmcoreinfo_note(void); #define VMCOREINFO_OSRELEASE(value) \ vmcoreinfo_append_str("OSRELEASE=%s\n", value) -#define VMCOREINFO_BUILD_ID(value) \ - vmcoreinfo_append_str("BUILD-ID=%s\n", value) +#define VMCOREINFO_BUILD_ID() \ + ({ \ + static_assert(sizeof(vmlinux_build_id) == 20); \ + vmcoreinfo_append_str("BUILD-ID=%20phN\n", vmlinux_build_id); \ + }) + #define VMCOREINFO_PAGESIZE(value) \ vmcoreinfo_append_str("PAGESIZE=%ld\n", value) #define VMCOREINFO_SYMBOL(name) \ @@ -69,10 +73,6 @@ extern unsigned char *vmcoreinfo_data; extern size_t vmcoreinfo_size; extern u32 *vmcoreinfo_note; -/* raw contents of kernel .notes section */ -extern const void __start_notes __weak; -extern const void __stop_notes __weak; - Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type, void *data, size_t data_len); void final_note(Elf_Word *buf); diff --git a/include/linux/debugobjects.h b/include/linux/debugobjects.h index 8d2dde23e9fb..32444686b6ff 100644 --- a/include/linux/debugobjects.h +++ b/include/linux/debugobjects.h @@ -18,7 +18,7 @@ enum debug_obj_state { struct debug_obj_descr; /** - * struct debug_obj - representaion of an tracked object + * struct debug_obj - representation of an tracked object * @node: hlist node to link the object into the tracker list * @state: tracked object state * @astate: current active state diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index 562b885cf9c3..e1ca2080a1ff 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -212,7 +212,7 @@ static inline void dma_resv_unlock(struct dma_resv *obj) } /** - * dma_resv_exclusive - return the object's exclusive fence + * dma_resv_excl_fence - return the object's exclusive fence * @obj: the reservation object * * Returns the exclusive fence (if any). Caller must either hold the objects diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 5487a80617a3..d445150c5350 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -34,6 +34,7 @@ #define F2FS_ROOT_INO(sbi) ((sbi)->root_ino_num) #define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num) #define F2FS_META_INO(sbi) ((sbi)->meta_ino_num) +#define F2FS_COMPRESS_INO(sbi) (NM_I(sbi)->max_nid) #define F2FS_MAX_QUOTAS 3 @@ -229,6 +230,7 @@ struct f2fs_extent { #define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */ #define F2FS_PIN_FILE 0x40 /* file should not be gced */ +#define F2FS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */ struct f2fs_inode { __le16 i_mode; /* file mode */ diff --git a/include/linux/hmm.h b/include/linux/hmm.h index 866a0fa104c4..2fd2e91d5107 100644 --- a/include/linux/hmm.h +++ b/include/linux/hmm.h @@ -113,7 +113,7 @@ int hmm_range_fault(struct hmm_range *range); * HMM_RANGE_DEFAULT_TIMEOUT - default timeout (ms) when waiting for a range * * When waiting for mmu notifiers we need some kind of time out otherwise we - * could potentialy wait for ever, 1000ms ie 1s sounds like a long time to + * could potentially wait for ever, 1000ms ie 1s sounds like a long time to * wait already. */ #define HMM_RANGE_DEFAULT_TIMEOUT 1000 diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 8e0f32f935bd..f7ca1a3870ea 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -51,7 +51,7 @@ struct hugepage_subpool { long count; long max_hpages; /* Maximum huge pages or -1 if no maximum. */ long used_hpages; /* Used count against maximum, includes */ - /* both alloced and reserved pages. */ + /* both allocated and reserved pages. */ struct hstate *hstate; long min_hpages; /* Minimum huge pages or -1 if no minimum. */ long rsv_hpages; /* Pages reserved against global pool to */ @@ -85,7 +85,7 @@ struct resv_map { * by a resv_map's lock. The set of regions within the resv_map represent * reservations for huge pages, or huge pages that have already been * instantiated within the map. The from and to elements are huge page - * indicies into the associated mapping. from indicates the starting index + * indices into the associated mapping. from indicates the starting index * of the region. to represents the first index past the end of the region. * * For example, a file region structure with from == 0 and to == 4 represents @@ -797,7 +797,7 @@ static inline bool hugepage_migration_supported(struct hstate *h) * It determines whether or not a huge page should be placed on * movable zone or not. Movability of any huge page should be * required only if huge page size is supported for migration. - * There wont be any reason for the huge page to be movable if + * There won't be any reason for the huge page to be movable if * it is not migratable to start with. Also the size of the huge * page should be large enough to be placed under a movable zone * and still feasible enough to be migratable. Just the presence diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 6cc035321562..fd933c45281a 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -918,11 +918,11 @@ struct journal_s struct shrinker j_shrinker; /** - * @j_jh_shrink_count: + * @j_checkpoint_jh_count: * * Number of journal buffers on the checkpoint list. [j_list_lock] */ - struct percpu_counter j_jh_shrink_count; + struct percpu_counter j_checkpoint_jh_count; /** * @j_shrink_transaction: @@ -1556,8 +1556,6 @@ extern int jbd2_journal_set_features (journal_t *, unsigned long, unsigned long, unsigned long); extern void jbd2_journal_clear_features (journal_t *, unsigned long, unsigned long, unsigned long); -extern int jbd2_journal_register_shrinker(journal_t *journal); -extern void jbd2_journal_unregister_shrinker(journal_t *journal); extern int jbd2_journal_load (journal_t *journal); extern int jbd2_journal_destroy (journal_t *); extern int jbd2_journal_recover (journal_t *journal); diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 465060acc981..a1d6fc82d7f0 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -7,6 +7,7 @@ #define _LINUX_KALLSYMS_H #include +#include #include #include #include @@ -15,8 +16,10 @@ #include #define KSYM_NAME_LEN 128 -#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ - 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) +#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s %s]") + \ + (KSYM_NAME_LEN - 1) + \ + 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + \ + (BUILD_ID_SIZE_MAX * 2) + 1) struct cred; struct module; @@ -91,8 +94,10 @@ const char *kallsyms_lookup(unsigned long addr, /* Look up a kernel symbol and return it in a text buffer. */ extern int sprint_symbol(char *buffer, unsigned long address); +extern int sprint_symbol_build_id(char *buffer, unsigned long address); extern int sprint_symbol_no_offset(char *buffer, unsigned long address); extern int sprint_backtrace(char *buffer, unsigned long address); +extern int sprint_backtrace_build_id(char *buffer, unsigned long address); int lookup_symbol_name(unsigned long addr, char *symname); int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); @@ -128,6 +133,12 @@ static inline int sprint_symbol(char *buffer, unsigned long addr) return 0; } +static inline int sprint_symbol_build_id(char *buffer, unsigned long address) +{ + *buffer = '\0'; + return 0; +} + static inline int sprint_symbol_no_offset(char *buffer, unsigned long addr) { *buffer = '\0'; @@ -140,6 +151,12 @@ static inline int sprint_backtrace(char *buffer, unsigned long addr) return 0; } +static inline int sprint_backtrace_build_id(char *buffer, unsigned long addr) +{ + *buffer = '\0'; + return 0; +} + static inline int lookup_symbol_name(unsigned long addr, char *symname) { return -ERANGE; diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index cc8fa109cfa3..20d1079e92b4 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -51,7 +51,8 @@ /* * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0 - * otherwise. + * otherwise. CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1" in + * autoconf.h. */ #define IS_MODULE(option) __is_defined(option##_MODULE) @@ -66,7 +67,8 @@ /* * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', - * 0 otherwise. + * 0 otherwise. Note that CONFIG_FOO=y results in "#define CONFIG_FOO 1" in + * autoconf.h, while CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1". */ #define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option)) diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index 9dcaa3e582c9..1b5fceb565df 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -146,7 +146,7 @@ typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, * @lru: the lru pointer. * @nid: the node id to scan from. * @memcg: the cgroup to scan from. - * @isolate: callback function that is resposible for deciding what to do with + * @isolate: callback function that is responsible for deciding what to do with * the item currently being scanned * @cb_arg: opaque type that will be passed to @isolate * @nr_to_walk: how many items to scan. @@ -172,7 +172,7 @@ unsigned long list_lru_walk_one(struct list_lru *lru, * @lru: the lru pointer. * @nid: the node id to scan from. * @memcg: the cgroup to scan from. - * @isolate: callback function that is resposible for deciding what to do with + * @isolate: callback function that is responsible for deciding what to do with * the item currently being scanned * @cb_arg: opaque type that will be passed to @isolate * @nr_to_walk: how many items to scan. diff --git a/include/linux/litex.h b/include/linux/litex.h index 5ea9ccf5cce4..f2edb86d5f44 100644 --- a/include/linux/litex.h +++ b/include/linux/litex.h @@ -11,18 +11,6 @@ #include -/* LiteX SoCs support 8- or 32-bit CSR Bus data width (i.e., subreg. size) */ -#if defined(CONFIG_LITEX_SUBREG_SIZE) && \ - (CONFIG_LITEX_SUBREG_SIZE == 1 || CONFIG_LITEX_SUBREG_SIZE == 4) -#define LITEX_SUBREG_SIZE CONFIG_LITEX_SUBREG_SIZE -#else -#error LiteX subregister size (LITEX_SUBREG_SIZE) must be 4 or 1! -#endif -#define LITEX_SUBREG_SIZE_BIT (LITEX_SUBREG_SIZE * 8) - -/* LiteX subregisters of any width are always aligned on a 4-byte boundary */ -#define LITEX_SUBREG_ALIGN 0x4 - static inline void _write_litex_subregister(u32 val, void __iomem *addr) { writel((u32 __force)cpu_to_le32(val), addr); @@ -42,115 +30,54 @@ static inline u32 _read_litex_subregister(void __iomem *addr) * 32-bit wide logical CSR will be laid out as four 32-bit physical * subregisters, each one containing one byte of meaningful data. * + * For Linux support, upstream LiteX enforces a 32-bit wide CSR bus, which + * means that only larger-than-32-bit CSRs will be split across multiple + * subregisters (e.g., a 64-bit CSR will be spread across two consecutive + * 32-bit subregisters). + * * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus */ -/* number of LiteX subregisters needed to store a register of given reg_size */ -#define _litex_num_subregs(reg_size) \ - (((reg_size) - 1) / LITEX_SUBREG_SIZE + 1) - -/* - * since the number of 4-byte aligned subregisters required to store a single - * LiteX CSR (MMIO) register varies with LITEX_SUBREG_SIZE, the offset of the - * next adjacent LiteX CSR register w.r.t. the offset of the current one also - * depends on how many subregisters the latter is spread across - */ -#define _next_reg_off(off, size) \ - ((off) + _litex_num_subregs(size) * LITEX_SUBREG_ALIGN) - -/* - * The purpose of `_litex_[set|get]_reg()` is to implement the logic of - * writing to/reading from the LiteX CSR in a single place that can be then - * reused by all LiteX drivers via the `litex_[write|read][8|16|32|64]()` - * accessors for the appropriate data width. - * NOTE: direct use of `_litex_[set|get]_reg()` by LiteX drivers is strongly - * discouraged, as they perform no error checking on the requested data width! - */ - -/** - * _litex_set_reg() - Writes a value to the LiteX CSR (Control&Status Register) - * @reg: Address of the CSR - * @reg_size: The width of the CSR expressed in the number of bytes - * @val: Value to be written to the CSR - * - * This function splits a single (possibly multi-byte) LiteX CSR write into - * a series of subregister writes with a proper offset. - * NOTE: caller is responsible for ensuring (0 < reg_size <= sizeof(u64)). - */ -static inline void _litex_set_reg(void __iomem *reg, size_t reg_size, u64 val) -{ - u8 shift = _litex_num_subregs(reg_size) * LITEX_SUBREG_SIZE_BIT; - - while (shift > 0) { - shift -= LITEX_SUBREG_SIZE_BIT; - _write_litex_subregister(val >> shift, reg); - reg += LITEX_SUBREG_ALIGN; - } -} - -/** - * _litex_get_reg() - Reads a value of the LiteX CSR (Control&Status Register) - * @reg: Address of the CSR - * @reg_size: The width of the CSR expressed in the number of bytes - * - * Return: Value read from the CSR - * - * This function generates a series of subregister reads with a proper offset - * and joins their results into a single (possibly multi-byte) LiteX CSR value. - * NOTE: caller is responsible for ensuring (0 < reg_size <= sizeof(u64)). - */ -static inline u64 _litex_get_reg(void __iomem *reg, size_t reg_size) -{ - u64 r; - u8 i; - - r = _read_litex_subregister(reg); - for (i = 1; i < _litex_num_subregs(reg_size); i++) { - r <<= LITEX_SUBREG_SIZE_BIT; - reg += LITEX_SUBREG_ALIGN; - r |= _read_litex_subregister(reg); - } - return r; -} - static inline void litex_write8(void __iomem *reg, u8 val) { - _litex_set_reg(reg, sizeof(u8), val); + _write_litex_subregister(val, reg); } static inline void litex_write16(void __iomem *reg, u16 val) { - _litex_set_reg(reg, sizeof(u16), val); + _write_litex_subregister(val, reg); } static inline void litex_write32(void __iomem *reg, u32 val) { - _litex_set_reg(reg, sizeof(u32), val); + _write_litex_subregister(val, reg); } static inline void litex_write64(void __iomem *reg, u64 val) { - _litex_set_reg(reg, sizeof(u64), val); + _write_litex_subregister(val >> 32, reg); + _write_litex_subregister(val, reg + 4); } static inline u8 litex_read8(void __iomem *reg) { - return _litex_get_reg(reg, sizeof(u8)); + return _read_litex_subregister(reg); } static inline u16 litex_read16(void __iomem *reg) { - return _litex_get_reg(reg, sizeof(u16)); + return _read_litex_subregister(reg); } static inline u32 litex_read32(void __iomem *reg) { - return _litex_get_reg(reg, sizeof(u32)); + return _read_litex_subregister(reg); } static inline u64 litex_read64(void __iomem *reg) { - return _litex_get_reg(reg, sizeof(u64)); + return ((u64)_read_litex_subregister(reg) << 32) | + _read_litex_subregister(reg + 4); } #endif /* _LINUX_LITEX_H */ diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index 7ab9f264313f..a98309c0121c 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -109,11 +109,5 @@ int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *); int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *); int nlmsvc_decode_notify(struct svc_rqst *, __be32 *); int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *); -/* -int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); - */ #endif /* LOCKD_XDR_H */ diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index e709fe5924f2..5ae766f26e04 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -37,12 +37,7 @@ int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *); int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *); int nlm4svc_decode_notify(struct svc_rqst *, __be32 *); int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *); -/* -int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); - */ + extern const struct rpc_version nlm_version4; #endif /* LOCKD_XDR4_H */ diff --git a/include/linux/logic_iomem.h b/include/linux/logic_iomem.h new file mode 100644 index 000000000000..3fa65c964379 --- /dev/null +++ b/include/linux/logic_iomem.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Intel Corporation + * Author: johannes@sipsolutions.net + */ +#ifndef __LOGIC_IOMEM_H +#define __LOGIC_IOMEM_H +#include +#include + +/** + * struct logic_iomem_ops - emulated IO memory ops + * @read: read an 8, 16, 32 or 64 bit quantity from the given offset, + * size is given in bytes (1, 2, 4 or 8) + * (64-bit only necessary if CONFIG_64BIT is set) + * @write: write an 8, 16 32 or 64 bit quantity to the given offset, + * size is given in bytes (1, 2, 4 or 8) + * (64-bit only necessary if CONFIG_64BIT is set) + * @set: optional, for memset_io() + * @copy_from: optional, for memcpy_fromio() + * @copy_to: optional, for memcpy_toio() + * @unmap: optional, this region is getting unmapped + */ +struct logic_iomem_ops { + unsigned long (*read)(void *priv, unsigned int offset, int size); + void (*write)(void *priv, unsigned int offset, int size, + unsigned long val); + + void (*set)(void *priv, unsigned int offset, u8 value, int size); + void (*copy_from)(void *priv, void *buffer, unsigned int offset, + int size); + void (*copy_to)(void *priv, unsigned int offset, const void *buffer, + int size); + + void (*unmap)(void *priv); +}; + +/** + * struct logic_iomem_region_ops - ops for an IO memory handler + * @map: map a range in the registered IO memory region, must + * fill *ops with the ops and may fill *priv to be passed + * to the ops. The offset is given as the offset into the + * registered resource region. + * The return value is negative for errors, or >= 0 for + * success. On success, the return value is added to the + * offset for later ops, to allow for partial mappings. + */ +struct logic_iomem_region_ops { + long (*map)(unsigned long offset, size_t size, + const struct logic_iomem_ops **ops, + void **priv); +}; + +/** + * logic_iomem_add_region - register an IO memory region + * @resource: the resource description for this region + * @ops: the IO memory mapping ops for this resource + */ +int logic_iomem_add_region(struct resource *resource, + const struct logic_iomem_region_ops *ops); + +#endif /* __LOGIC_IOMEM_H */ diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h index 429d67d815ce..07add7882a5d 100644 --- a/include/linux/lru_cache.h +++ b/include/linux/lru_cache.h @@ -32,7 +32,7 @@ This header file (and its .c file; kernel-doc of functions see there) Because of this later property, it is called "lru_cache". As it actually Tracks Objects in an Active SeT, we could also call it toast (incidentally that is what may happen to the data on the - backend storage uppon next resync, if we don't get it right). + backend storage upon next resync, if we don't get it right). What for? @@ -152,7 +152,7 @@ struct lc_element { * for paranoia, and for "lc_element_to_index" */ unsigned lc_index; /* if we want to track a larger set of objects, - * it needs to become arch independend u64 */ + * it needs to become an architecture independent u64 */ unsigned lc_number; /* special label when on free list */ #define LC_FREE (~0U) @@ -263,7 +263,7 @@ extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char * * Allows (expects) the set to be "dirty". Note that the reference counts and * order on the active and lru lists may still change. Used to serialize - * changing transactions. Returns true if we aquired the lock. + * changing transactions. Returns true if we acquired the lock. */ static inline int lc_try_lock_for_transaction(struct lru_cache *lc) { @@ -275,7 +275,7 @@ static inline int lc_try_lock_for_transaction(struct lru_cache *lc) * @lc: the lru cache to operate on * * Note that the reference counts and order on the active and lru lists may - * still change. Only works on a "clean" set. Returns true if we aquired the + * still change. Only works on a "clean" set. Returns true if we acquired the * lock, which means there are no pending changes, and any further attempt to * change the set will not succeed until the next lc_unlock(). */ diff --git a/include/linux/max17040_battery.h b/include/linux/max17040_battery.h deleted file mode 100644 index 593602fc9317..000000000000 --- a/include/linux/max17040_battery.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang - */ - -#ifndef __MAX17040_BATTERY_H_ -#define __MAX17040_BATTERY_H_ - -struct max17040_platform_data { - int (*battery_online)(void); - int (*charger_online)(void); - int (*charger_enable)(void); -}; - -#endif diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index b4546e29e561..b0009aa3647f 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1512,7 +1512,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 uar_4k[0x1]; u8 reserved_at_241[0x9]; u8 uar_sz[0x6]; - u8 reserved_at_250[0x8]; + u8 reserved_at_248[0x2]; + u8 umem_uid_0[0x1]; + u8 reserved_at_250[0x5]; u8 log_pg_sz[0x8]; u8 bf[0x1]; diff --git a/include/linux/mm.h b/include/linux/mm.h index d69ce06e66e3..7f52f3af2b91 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -238,6 +238,9 @@ int __add_to_page_cache_locked(struct page *page, struct address_space *mapping, #define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) +void setup_initial_init_mm(void *start_code, void *end_code, + void *end_data, void *brk); + /* * Linux kernel virtual memory manager primitives. * The idea being to have a "virtual" mm in the same way diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index 6692da8d121d..45fc2c81e370 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -33,7 +33,7 @@ struct mmu_interval_notifier; * * @MMU_NOTIFY_SOFT_DIRTY: soft dirty accounting (still same page and same * access flags). User should soft dirty the page in the end callback to make - * sure that anyone relying on soft dirtyness catch pages that might be written + * sure that anyone relying on soft dirtiness catch pages that might be written * through non CPU mappings. * * @MMU_NOTIFY_RELEASE: used during mmu_interval_notifier invalidate to signal @@ -167,7 +167,7 @@ struct mmu_notifier_ops { * decrease the refcount. If the refcount is decreased on * invalidate_range_start() then the VM can free pages as page * table entries are removed. If the refcount is only - * droppped on invalidate_range_end() then the driver itself + * dropped on invalidate_range_end() then the driver itself * will drop the last refcount but it must take care to flush * any secondary tlb before doing the final free on the * page. Pages will no longer be referenced by the linux @@ -196,7 +196,7 @@ struct mmu_notifier_ops { * If invalidate_range() is used to manage a non-CPU TLB with * shared page-tables, it not necessary to implement the * invalidate_range_start()/end() notifiers, as - * invalidate_range() alread catches the points in time when an + * invalidate_range() already catches the points in time when an * external TLB range needs to be flushed. For more in depth * discussion on this see Documentation/vm/mmu_notifier.rst * @@ -369,7 +369,7 @@ mmu_interval_read_retry(struct mmu_interval_notifier *interval_sub, * mmu_interval_read_retry() will return true. * * False is not reliable and only suggests a collision may not have - * occured. It can be called many times and does not have to hold the user + * occurred. It can be called many times and does not have to hold the user * provided lock. * * This call can be used as part of loops and other expensive operations to diff --git a/include/linux/module.h b/include/linux/module.h index e3b7bcd11f01..de4a842f5a6d 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -369,6 +370,11 @@ struct module { /* Unique handle for this module */ char name[MODULE_NAME_LEN]; +#ifdef CONFIG_STACKTRACE_BUILD_ID + /* Module build ID */ + unsigned char build_id[BUILD_ID_SIZE_MAX]; +#endif + /* Sysfs stuff. */ struct module_kobject mkobj; struct module_attribute *modinfo_attrs; @@ -639,7 +645,7 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr); const char *module_address_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *offset, - char **modname, + char **modname, const unsigned char **modbuildid, char *namebuf); int lookup_module_symbol_name(unsigned long addr, char *symname); int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); @@ -743,6 +749,7 @@ static inline const char *module_address_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *offset, char **modname, + const unsigned char **modbuildid, char *namebuf) { return NULL; diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h index 47e5679b48e1..000b126acfb6 100644 --- a/include/linux/mv643xx.h +++ b/include/linux/mv643xx.h @@ -918,12 +918,4 @@ extern void mv64340_irq_init(unsigned int base); -/* Watchdog Platform Device, Driver Data */ -#define MV64x60_WDT_NAME "mv64x60_wdt" - -struct mv64x60_wdt_pdata { - int timeout; /* watchdog expiry in seconds, default 10 */ - int bus_clk; /* bus clock in MHz, default 133 */ -}; - #endif /* __ASM_MV643XX_H */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index ffba254d2098..ce6474594872 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -84,6 +84,7 @@ struct nfs_open_context { #define NFS_CONTEXT_RESEND_WRITES (1) #define NFS_CONTEXT_BAD (2) #define NFS_CONTEXT_UNLOCK (3) +#define NFS_CONTEXT_FILE_OPEN (4) int error; struct list_head list; diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h index f5ba0fbff72f..222ae8883e85 100644 --- a/include/linux/nfs_ssc.h +++ b/include/linux/nfs_ssc.h @@ -8,6 +8,7 @@ */ #include +#include extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl; @@ -52,6 +53,19 @@ static inline void nfs42_ssc_close(struct file *filep) if (nfs_ssc_client_tbl.ssc_nfs4_ops) (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep); } + +struct nfsd4_ssc_umount_item { + struct list_head nsui_list; + bool nsui_busy; + /* + * nsui_refcnt inited to 2, 1 on list and 1 for consumer. Entry + * is removed when refcnt drops to 1 and nsui_expire expires. + */ + refcount_t nsui_refcnt; + unsigned long nsui_expire; + struct vfsmount *nsui_vfsmount; + char nsui_ipaddr[RPC_MAX_ADDRBUFLEN]; +}; #endif /* diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 717ecc87c9e7..e9698b6278a5 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -277,6 +277,7 @@ struct nfs4_layoutget { struct nfs4_layoutget_args args; struct nfs4_layoutget_res res; const struct cred *cred; + struct pnfs_layout_hdr *lo; gfp_t gfp_flags; }; diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index ac398e143c9a..567c3ddba2c4 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -119,7 +119,7 @@ static inline const unsigned long *__nodemask_pr_bits(const nodemask_t *m) * The inline keyword gives the compiler room to decide to inline, or * not inline a function as it sees best. However, as these functions * are called in both __init and non-__init functions, if they are not - * inlined we will end up with a section mis-match error (of the type of + * inlined we will end up with a section mismatch error (of the type of * freeable items not being freed). So we must use __always_inline here * to fix the problem. If other functions in the future also end up in * this situation they will also need to be annotated as __always_inline @@ -515,7 +515,7 @@ static inline int node_random(const nodemask_t *mask) #define for_each_online_node(node) for_each_node_state(node, N_ONLINE) /* - * For nodemask scrach area. + * For nodemask scratch area. * NODEMASK_ALLOC(type, name) allocates an object with a specified type and * name. */ @@ -528,7 +528,7 @@ static inline int node_random(const nodemask_t *mask) #define NODEMASK_FREE(m) do {} while (0) #endif -/* A example struture for using NODEMASK_ALLOC, used in mempolicy. */ +/* Example structure for using NODEMASK_ALLOC, used in mempolicy. */ struct nodemask_scratch { nodemask_t mask1; nodemask_t mask2; diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index fbdadd4d8377..adea5a4771cf 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -55,6 +55,7 @@ struct pci_ecam_ops { struct pci_config_window { struct resource res; struct resource busr; + unsigned int bus_shift; void *priv; const struct pci_ecam_ops *ops; union { diff --git a/include/linux/pci-ep-cfs.h b/include/linux/pci-ep-cfs.h index 662881335c7e..3e2140d7e31d 100644 --- a/include/linux/pci-ep-cfs.h +++ b/include/linux/pci-ep-cfs.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -/** +/* * PCI Endpoint ConfigFS header file * * Copyright (C) 2017 Texas Instruments diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index b82c9b100e97..50a649d33e68 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* * PCI Endpoint *Controller* (EPC) header file * * Copyright (C) 2017 Texas Instruments @@ -58,6 +58,7 @@ pci_epc_interface_string(enum pci_epc_interface_type type) * @map_msi_irq: ops to map physical address to MSI address and return MSI data * @start: ops to start the PCI link * @stop: ops to stop the PCI link + * @get_features: ops to get the features supported by the EPC * @owner: the module owner containing the ops */ struct pci_epc_ops { @@ -150,6 +151,8 @@ struct pci_epc { /** * struct pci_epc_features - features supported by a EPC device per function * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up + * @core_init_notifier: indicate cores that can notify about their availability + * for initialization * @msi_capable: indicate if the endpoint function has MSI capability * @msix_capable: indicate if the endpoint function has MSI-X capability * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index 6833e2160ef1..2debc27ba95e 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* * PCI Endpoint *Function* (EPF) header file * * Copyright (C) 2017 Texas Instruments @@ -102,6 +102,8 @@ struct pci_epf_driver { * @phys_addr: physical address that should be mapped to the BAR * @addr: virtual address corresponding to the @phys_addr * @size: the size of the address space present in BAR + * @barno: BAR number + * @flags: flags that are set for the BAR */ struct pci_epf_bar { dma_addr_t phys_addr; @@ -118,6 +120,7 @@ struct pci_epf_bar { * @header: represents standard configuration header * @bar: represents the BAR of EPF device * @msi_interrupts: number of MSI interrupts required by this function + * @msix_interrupts: number of MSI-X interrupts required by this function * @func_no: unique function number within this endpoint device * @epc: the EPC device to which this EPF device is bound * @driver: the EPF driver to which this EPF device is bound diff --git a/include/linux/pci.h b/include/linux/pci.h index eb45078abc3a..540b377ca8f6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -497,7 +497,7 @@ struct pci_dev { u16 pasid_features; #endif #ifdef CONFIG_PCI_P2PDMA - struct pci_p2pdma *p2pdma; + struct pci_p2pdma __rcu *p2pdma; #endif u16 acs_cap; /* ACS Capability offset */ phys_addr_t rom; /* Physical address if not from BAR */ diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index b482e42d7153..2dac431d94ac 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -50,6 +50,8 @@ struct hotplug_slot_ops { /** * struct hotplug_slot - used to register a physical slot with the hotplug pci core * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @slot_list: internal list used to track hotplug PCI slots + * @pci_slot: represents a physical slot * @owner: The module owner of this structure * @mod_name: The module name (KBUILD_MODNAME) of this structure */ diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index dff7040f629a..af1071535de8 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -412,7 +412,7 @@ do { \ * instead. * * If there is no other protection through preempt disable and/or disabling - * interupts then one of these RMW operations can show unexpected behavior + * interrupts then one of these RMW operations can show unexpected behavior * because the execution thread was rescheduled on another processor or an * interrupt occurred and the same percpu variable was modified from the * interrupt context. diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index 16c35a728b4c..ae16a9856305 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h @@ -213,7 +213,7 @@ static inline void percpu_ref_get_many(struct percpu_ref *ref, unsigned long nr) * percpu_ref_get - increment a percpu refcount * @ref: percpu_ref to get * - * Analagous to atomic_long_inc(). + * Analogous to atomic_long_inc(). * * This function is safe to call as long as @ref is between init and exit. */ diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index e82660f7b9e4..d147480cdefc 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -106,7 +106,7 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) #ifndef pmd_offset static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) { - return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address); + return pud_pgtable(*pud) + pmd_index(address); } #define pmd_offset pmd_offset #endif @@ -114,7 +114,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) #ifndef pud_offset static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address) { - return (pud_t *)p4d_page_vaddr(*p4d) + pud_index(address); + return p4d_pgtable(*p4d) + pud_index(address); } #define pud_offset pud_offset #endif diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index 2955ba976048..6beb26b7151d 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -44,10 +44,6 @@ static inline bool arch_pkeys_enabled(void) return false; } -static inline void copy_init_pkru_to_fpregs(void) -{ -} - #endif /* ! CONFIG_ARCH_HAS_PKEYS */ #endif /* _LINUX_PKEYS_H */ diff --git a/include/linux/platform_data/pata_ixp4xx_cf.h b/include/linux/platform_data/pata_ixp4xx_cf.h new file mode 100644 index 000000000000..601ba97fef57 --- /dev/null +++ b/include/linux/platform_data/pata_ixp4xx_cf.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PLATFORM_DATA_PATA_IXP4XX_H +#define __PLATFORM_DATA_PATA_IXP4XX_H + +#include + +/* + * This structure provide a means for the board setup code + * to give information to th pata_ixp4xx driver. It is + * passed as platform_data. + */ +struct ixp4xx_pata_data { + volatile u32 *cs0_cfg; + volatile u32 *cs1_cfg; + unsigned long cs0_bits; + unsigned long cs1_bits; + void __iomem *cs0; + void __iomem *cs1; +}; + +#endif diff --git a/include/linux/pm2301_charger.h b/include/linux/pm2301_charger.h deleted file mode 100644 index b8fac96f05aa..000000000000 --- a/include/linux/pm2301_charger.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * PM2301 charger driver. - * - * Copyright (C) 2012 ST Ericsson Corporation - * - * Contact: Olivier LAUNAY (olivier.launay@stericsson.com - */ - -#ifndef __LINUX_PM2301_H -#define __LINUX_PM2301_H - -/** - * struct pm2xxx_bm_charger_parameters - Charger specific parameters - * @ac_volt_max: maximum allowed AC charger voltage in mV - * @ac_curr_max: maximum allowed AC charger current in mA - */ -struct pm2xxx_bm_charger_parameters { - int ac_volt_max; - int ac_curr_max; -}; - -/** - * struct pm2xxx_bm_data - pm2xxx battery management data - * @enable_overshoot flag to enable VBAT overshoot control - * @chg_params charger parameters - */ -struct pm2xxx_bm_data { - bool enable_overshoot; - const struct pm2xxx_bm_charger_parameters *chg_params; -}; - -struct pm2xxx_charger_platform_data { - char **supplied_to; - size_t num_supplicants; - int i2c_bus; - const char *label; - int gpio_irq_number; - unsigned int lpn_gpio; - int irq_type; -}; - -struct pm2xxx_platform_data { - struct pm2xxx_charger_platform_data *wall_charger; - struct pm2xxx_bm_data *battery; -}; - -#endif /* __LINUX_PM2301_H */ diff --git a/include/linux/power/ab8500.h b/include/linux/power/ab8500.h deleted file mode 100644 index 51976b52f373..000000000000 --- a/include/linux/power/ab8500.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson 2013 - * Author: Hongbo Zhang - */ - -#ifndef PWR_AB8500_H -#define PWR_AB8500_H - -extern const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[]; -extern const int ab8500_temp_tbl_a_size; - -extern const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[]; -extern const int ab8500_temp_tbl_b_size; - -#endif /* PWR_AB8500_H */ diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 5bb90af4997e..a0b7e43049d5 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -54,12 +54,17 @@ enum { * @duty_cycle: PWM duty cycle (in nanoseconds) * @polarity: PWM polarity * @enabled: PWM enabled status + * @usage_power: If set, the PWM driver is only required to maintain the power + * output but has more freedom regarding signal form. + * If supported, the signal can be optimized, for example to + * improve EMI by phase shifting individual channels. */ struct pwm_state { u64 period; u64 duty_cycle; enum pwm_polarity polarity; bool enabled; + bool usage_power; }; /** @@ -188,6 +193,7 @@ static inline void pwm_init_state(const struct pwm_device *pwm, state->period = args.period; state->polarity = args.polarity; state->duty_cycle = 0; + state->usage_power = false; } /** @@ -399,6 +405,9 @@ void *pwm_get_chip_data(struct pwm_device *pwm); int pwmchip_add(struct pwm_chip *chip); int pwmchip_remove(struct pwm_chip *chip); + +int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip); + struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, unsigned int index, const char *label); @@ -417,7 +426,6 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, struct pwm_device *devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id); -void devm_pwm_put(struct device *dev, struct pwm_device *pwm); #else static inline struct pwm_device *pwm_request(int pwm_id, const char *label) { @@ -524,10 +532,6 @@ devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, { return ERR_PTR(-ENODEV); } - -static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm) -{ -} #endif static inline void pwm_apply_args(struct pwm_device *pwm) @@ -558,6 +562,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm) state.enabled = false; state.polarity = pwm->args.polarity; state.period = pwm->args.period; + state.usage_power = false; pwm_apply_state(pwm, &state); } diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 8b795b544f75..a5b37bc10865 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -243,7 +243,7 @@ struct fw_rsc_trace { * @da: device address * @align: the alignment between the consumer and producer parts of the vring * @num: num of buffers supported by this vring (must be power of two) - * @notifyid is a unique rproc-wide notify index for this vring. This notify + * @notifyid: a unique rproc-wide notify index for this vring. This notify * index is used when kicking a remote processor, to let it know that this * vring is triggered. * @pa: physical address @@ -266,18 +266,18 @@ struct fw_rsc_vdev_vring { /** * struct fw_rsc_vdev - virtio device header * @id: virtio device id (as in virtio_ids.h) - * @notifyid is a unique rproc-wide notify index for this vdev. This notify + * @notifyid: a unique rproc-wide notify index for this vdev. This notify * index is used when kicking a remote processor, to let it know that the * status/features of this vdev have changes. - * @dfeatures specifies the virtio device features supported by the firmware - * @gfeatures is a place holder used by the host to write back the + * @dfeatures: specifies the virtio device features supported by the firmware + * @gfeatures: a place holder used by the host to write back the * negotiated features that are supported by both sides. - * @config_len is the size of the virtio config space of this vdev. The config + * @config_len: the size of the virtio config space of this vdev. The config * space lies in the resource table immediate after this vdev header. - * @status is a place holder where the host will indicate its virtio progress. - * @num_of_vrings indicates how many vrings are described in this vdev header + * @status: a place holder where the host will indicate its virtio progress. + * @num_of_vrings: indicates how many vrings are described in this vdev header * @reserved: reserved (must be zero) - * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. + * @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. * * This resource is a virtio device header: it provides information about * the vdev, and is then used by the host and its peer remote processors @@ -287,16 +287,17 @@ struct fw_rsc_vdev_vring { * to statically allocate a vdev upon registration of the rproc (dynamic vdev * allocation is not yet supported). * - * Note: unlike virtualization systems, the term 'host' here means - * the Linux side which is running remoteproc to control the remote - * processors. We use the name 'gfeatures' to comply with virtio's terms, - * though there isn't really any virtualized guest OS here: it's the host - * which is responsible for negotiating the final features. - * Yeah, it's a bit confusing. + * Note: + * 1. unlike virtualization systems, the term 'host' here means + * the Linux side which is running remoteproc to control the remote + * processors. We use the name 'gfeatures' to comply with virtio's terms, + * though there isn't really any virtualized guest OS here: it's the host + * which is responsible for negotiating the final features. + * Yeah, it's a bit confusing. * - * Note: immediately following this structure is the virtio config space for - * this vdev (which is specific to the vdev; for more info, read the virtio - * spec). the size of the config space is specified by @config_len. + * 2. immediately following this structure is the virtio config space for + * this vdev (which is specific to the vdev; for more info, read the virtio + * spec). The size of the config space is specified by @config_len. */ struct fw_rsc_vdev { u32 id; @@ -440,7 +441,7 @@ enum rproc_state { * enum rproc_crash_type - remote processor crash types * @RPROC_MMUFAULT: iommu fault * @RPROC_WATCHDOG: watchdog bite - * @RPROC_FATAL_ERROR fatal error + * @RPROC_FATAL_ERROR: fatal error * * Each element of the enum is used as an array index. So that, the value of * the elements should be always something sane. @@ -457,9 +458,9 @@ enum rproc_crash_type { * enum rproc_dump_mechanism - Coredump options for core * @RPROC_COREDUMP_DISABLED: Don't perform any dump * @RPROC_COREDUMP_ENABLED: Copy dump to separate buffer and carry on with - recovery + * recovery * @RPROC_COREDUMP_INLINE: Read segments directly from device memory. Stall - recovery until all segments are read + * recovery until all segments are read */ enum rproc_dump_mechanism { RPROC_COREDUMP_DISABLED, @@ -475,6 +476,7 @@ enum rproc_dump_mechanism { * @priv: private data associated with the dump_segment * @dump: custom dump function to fill device memory segment associated * with coredump + * @offset: offset of the segment */ struct rproc_dump_segment { struct list_head node; @@ -524,7 +526,9 @@ struct rproc_dump_segment { * @auto_boot: flag to indicate if remote processor should be auto-started * @dump_segments: list of segments in the firmware * @nb_vdev: number of vdev currently handled by rproc - * @char_dev: character device of the rproc + * @elf_class: firmware ELF class + * @elf_machine: firmware ELF machine + * @cdev: character device of the rproc * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release */ struct rproc { @@ -613,10 +617,10 @@ struct rproc_vring { * struct rproc_vdev - remoteproc state for a supported virtio device * @refcount: reference counter for the vdev and vring allocations * @subdev: handle for registering the vdev as a rproc subdevice + * @dev: device struct used for reference count semantics * @id: virtio device id (as in virtio_ids.h) * @node: list node * @rproc: the rproc handle - * @vdev: the virio device * @vring: the vrings for this vdev * @rsc_offset: offset of the vdev's resource entry * @index: vdev position versus other vdev declared in resource table diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index ec35814e0bbb..0fa4f60e1186 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h @@ -79,6 +79,7 @@ struct reset_controller_dev { unsigned int nr_resets; }; +#if IS_ENABLED(CONFIG_RESET_CONTROLLER) int reset_controller_register(struct reset_controller_dev *rcdev); void reset_controller_unregister(struct reset_controller_dev *rcdev); @@ -88,5 +89,26 @@ int devm_reset_controller_register(struct device *dev, void reset_controller_add_lookup(struct reset_control_lookup *lookup, unsigned int num_entries); +#else +static inline int reset_controller_register(struct reset_controller_dev *rcdev) +{ + return 0; +} + +static inline void reset_controller_unregister(struct reset_controller_dev *rcdev) +{ +} + +static inline int devm_reset_controller_register(struct device *dev, + struct reset_controller_dev *rcdev) +{ + return 0; +} + +static inline void reset_controller_add_lookup(struct reset_control_lookup *lookup, + unsigned int num_entries) +{ +} +#endif #endif diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 6f70572b2938..ecf87484814f 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -474,7 +474,7 @@ sg_page_iter_dma_address(struct sg_dma_page_iter *dma_iter) * Iterates over sg entries mapping page-by-page. On each successful * iteration, @miter->page points to the mapped page and * @miter->length bytes of data can be accessed at @miter->addr. As - * long as an interation is enclosed between start and stop, the user + * long as an iteration is enclosed between start and stop, the user * is free to choose control structure and when to stop. * * @miter->consumed is set to @miter->length on each iteration. It diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index c9cf678c347d..b9126fe06c3f 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -538,6 +538,17 @@ static inline int kill_cad_pid(int sig, int priv) #define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0) #define SEND_SIG_PRIV ((struct kernel_siginfo *) 1) +static inline int __on_sig_stack(unsigned long sp) +{ +#ifdef CONFIG_STACK_GROWSUP + return sp >= current->sas_ss_sp && + sp - current->sas_ss_sp < current->sas_ss_size; +#else + return sp > current->sas_ss_sp && + sp - current->sas_ss_sp <= current->sas_ss_size; +#endif +} + /* * True if we are on the alternate signal stack. */ @@ -555,13 +566,7 @@ static inline int on_sig_stack(unsigned long sp) if (current->sas_ss_flags & SS_AUTODISARM) return 0; -#ifdef CONFIG_STACK_GROWSUP - return sp >= current->sas_ss_sp && - sp - current->sas_ss_sp < current->sas_ss_size; -#else - return sp > current->sas_ss_sp && - sp - current->sas_ss_sp <= current->sas_ss_size; -#endif + return __on_sig_stack(sp); } static inline int sas_ss_flags(unsigned long sp) diff --git a/include/linux/secretmem.h b/include/linux/secretmem.h new file mode 100644 index 000000000000..21c3771e6a56 --- /dev/null +++ b/include/linux/secretmem.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_SECRETMEM_H +#define _LINUX_SECRETMEM_H + +#ifdef CONFIG_SECRETMEM + +extern const struct address_space_operations secretmem_aops; + +static inline bool page_is_secretmem(struct page *page) +{ + struct address_space *mapping; + + /* + * Using page_mapping() is quite slow because of the actual call + * instruction and repeated compound_head(page) inside the + * page_mapping() function. + * We know that secretmem pages are not compound and LRU so we can + * save a couple of cycles here. + */ + if (PageCompound(page) || !PageLRU(page)) + return false; + + mapping = (struct address_space *) + ((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS); + + if (mapping != page->mapping) + return false; + + return mapping->a_ops == &secretmem_aops; +} + +bool vma_is_secretmem(struct vm_area_struct *vma); +bool secretmem_active(void); + +#else + +static inline bool vma_is_secretmem(struct vm_area_struct *vma) +{ + return false; +} + +static inline bool page_is_secretmem(struct page *page) +{ + return false; +} + +static inline bool secretmem_active(void) +{ + return false; +} + +#endif /* CONFIG_SECRETMEM */ + +#endif /* _LINUX_SECRETMEM_H */ diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h index fe1aa4e54680..f36be5166c19 100644 --- a/include/linux/set_memory.h +++ b/include/linux/set_memory.h @@ -28,7 +28,19 @@ static inline bool kernel_page_present(struct page *page) { return true; } +#else /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */ +/* + * Some architectures, e.g. ARM64 can disable direct map modifications at + * boot time. Let them overrive this query. + */ +#ifndef can_set_direct_map +static inline bool can_set_direct_map(void) +{ + return true; +} +#define can_set_direct_map can_set_direct_map #endif +#endif /* CONFIG_ARCH_HAS_SET_DIRECT_MAP */ #ifndef set_mce_nospec static inline int set_mce_nospec(unsigned long pfn, bool unmap) diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 1eac79ce57d4..9814fff58a69 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -4,7 +4,7 @@ /* * This struct is used to pass information from page reclaim to the shrinkers. - * We consolidate the values for easier extention later. + * We consolidate the values for easier extension later. * * The 'gfpmask' refers to the allocation we are currently trying to * fulfil. diff --git a/include/linux/soc/ixp4xx/cpu.h b/include/linux/soc/ixp4xx/cpu.h new file mode 100644 index 000000000000..88bd8de0e803 --- /dev/null +++ b/include/linux/soc/ixp4xx/cpu.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * IXP4XX cpu type detection + * + * Copyright (C) 2007 MontaVista Software, Inc. + */ + +#ifndef __SOC_IXP4XX_CPU_H__ +#define __SOC_IXP4XX_CPU_H__ + +#include +#ifdef CONFIG_ARM +#include +#endif + +/* Processor id value in CP15 Register 0 */ +#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */ +#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0 + +#define IXP43X_PROCESSOR_ID_VALUE 0x69054040 +#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0 + +#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */ +#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0 + +/* "fuse" bits of IXP_EXP_CFG2 */ +/* All IXP4xx CPUs */ +#define IXP4XX_FEATURE_RCOMP (1 << 0) +#define IXP4XX_FEATURE_USB_DEVICE (1 << 1) +#define IXP4XX_FEATURE_HASH (1 << 2) +#define IXP4XX_FEATURE_AES (1 << 3) +#define IXP4XX_FEATURE_DES (1 << 4) +#define IXP4XX_FEATURE_HDLC (1 << 5) +#define IXP4XX_FEATURE_AAL (1 << 6) +#define IXP4XX_FEATURE_HSS (1 << 7) +#define IXP4XX_FEATURE_UTOPIA (1 << 8) +#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9) +#define IXP4XX_FEATURE_NPEC_ETH (1 << 10) +#define IXP4XX_FEATURE_RESET_NPEA (1 << 11) +#define IXP4XX_FEATURE_RESET_NPEB (1 << 12) +#define IXP4XX_FEATURE_RESET_NPEC (1 << 13) +#define IXP4XX_FEATURE_PCI (1 << 14) +#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16) +#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) +#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \ + IXP4XX_FEATURE_USB_DEVICE | \ + IXP4XX_FEATURE_HASH | \ + IXP4XX_FEATURE_AES | \ + IXP4XX_FEATURE_DES | \ + IXP4XX_FEATURE_HDLC | \ + IXP4XX_FEATURE_AAL | \ + IXP4XX_FEATURE_HSS | \ + IXP4XX_FEATURE_UTOPIA | \ + IXP4XX_FEATURE_NPEB_ETH0 | \ + IXP4XX_FEATURE_NPEC_ETH | \ + IXP4XX_FEATURE_RESET_NPEA | \ + IXP4XX_FEATURE_RESET_NPEB | \ + IXP4XX_FEATURE_RESET_NPEC | \ + IXP4XX_FEATURE_PCI | \ + IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \ + IXP4XX_FEATURE_XSCALE_MAX_FREQ) + + +/* IXP43x/46x CPUs */ +#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15) +#define IXP4XX_FEATURE_USB_HOST (1 << 18) +#define IXP4XX_FEATURE_NPEA_ETH (1 << 19) +#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \ + IXP4XX_FEATURE_ECC_TIMESYNC | \ + IXP4XX_FEATURE_USB_HOST | \ + IXP4XX_FEATURE_NPEA_ETH) + +/* IXP46x CPU (including IXP455) only */ +#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20) +#define IXP4XX_FEATURE_RSA (1 << 21) +#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \ + IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ + IXP4XX_FEATURE_RSA) + +#ifdef CONFIG_ARCH_IXP4XX +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \ + IXP42X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \ + IXP42X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \ + IXP43X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \ + IXP46X_PROCESSOR_ID_VALUE) + +u32 ixp4xx_read_feature_bits(void); +void ixp4xx_write_feature_bits(u32 value); +#else +#define cpu_is_ixp42x_rev_a0() 0 +#define cpu_is_ixp42x() 0 +#define cpu_is_ixp43x() 0 +#define cpu_is_ixp46x() 0 +static inline u32 ixp4xx_read_feature_bits(void) +{ + return 0; +} +static inline void ixp4xx_write_feature_bits(u32 value) +{ +} +#endif + +#endif /* _ASM_ARCH_CPU_H */ diff --git a/include/linux/soc/qcom/smem_state.h b/include/linux/soc/qcom/smem_state.h index 63ad8cddad14..652c0158baac 100644 --- a/include/linux/soc/qcom/smem_state.h +++ b/include/linux/soc/qcom/smem_state.h @@ -14,6 +14,7 @@ struct qcom_smem_state_ops { #ifdef CONFIG_QCOM_SMEM_STATE struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit); +struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit); void qcom_smem_state_put(struct qcom_smem_state *); int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 value); @@ -29,6 +30,13 @@ static inline struct qcom_smem_state *qcom_smem_state_get(struct device *dev, return ERR_PTR(-EINVAL); } +static inline struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev, + const char *con_id, + unsigned *bit) +{ + return ERR_PTR(-EINVAL); +} + static inline void qcom_smem_state_put(struct qcom_smem_state *state) { } diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h index fc9250fb3133..aa840ed043e1 100644 --- a/include/linux/soc/samsung/exynos-regs-pmu.h +++ b/include/linux/soc/samsung/exynos-regs-pmu.h @@ -611,12 +611,6 @@ #define EXYNOS5420_FSYS2_OPTION 0x4168 #define EXYNOS5420_PSGEN_OPTION 0x4188 -/* For EXYNOS_CENTRAL_SEQ_OPTION */ -#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16) -#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17) -#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24) -#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25) - #define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4) #define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5) #define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6) diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 02e7a5863d28..8b5d5c97553e 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -29,6 +29,7 @@ #include struct rpc_inode; +struct rpc_sysfs_client; /* * The high-level client handle @@ -71,6 +72,7 @@ struct rpc_clnt { #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct dentry *cl_debugfs; /* debugfs directory */ #endif + struct rpc_sysfs_client *cl_sysfs; /* sysfs directory */ /* cl_work is only needed after cl_xpi is no longer used, * and that are of similar size */ diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index df696efdd675..a237b8dbf608 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -121,6 +121,7 @@ struct rpc_task_setup { */ #define RPC_TASK_ASYNC 0x0001 /* is an async task */ #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ +#define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */ #define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */ #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ @@ -139,6 +140,7 @@ struct rpc_task_setup { #define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT)) #define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) #define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT) +#define RPC_IS_MOVEABLE(t) ((t)->tk_flags & RPC_TASK_MOVEABLE) #define RPC_TASK_RUNNING 0 #define RPC_TASK_QUEUED 1 diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 61b622e334ee..c8c39f22d3b1 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -53,6 +53,7 @@ enum rpc_display_format_t { struct rpc_task; struct rpc_xprt; +struct xprt_class; struct seq_file; struct svc_serv; struct net; @@ -182,9 +183,11 @@ enum xprt_transports { XPRT_TRANSPORT_LOCAL = 257, }; +struct rpc_sysfs_xprt; struct rpc_xprt { struct kref kref; /* Reference count */ const struct rpc_xprt_ops *ops; /* transport methods */ + unsigned int id; /* transport id */ const struct rpc_timeout *timeout; /* timeout parms */ struct sockaddr_storage addr; /* server address */ @@ -288,6 +291,9 @@ struct rpc_xprt { atomic_t inject_disconnect; #endif struct rcu_head rcu; + const struct xprt_class *xprt_class; + struct rpc_sysfs_xprt *xprt_sysfs; + bool main; /*mark if this is the 1st transport */ }; #if defined(CONFIG_SUNRPC_BACKCHANNEL) @@ -370,6 +376,7 @@ struct rpc_xprt * xprt_alloc(struct net *net, size_t size, void xprt_free(struct rpc_xprt *); void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task); bool xprt_wake_up_backlog(struct rpc_xprt *xprt, struct rpc_rqst *req); +void xprt_cleanup_ids(void); static inline int xprt_enable_swap(struct rpc_xprt *xprt) @@ -408,6 +415,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); bool xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *); void xprt_unlock_connect(struct rpc_xprt *, void *); +void xprt_release_write(struct rpc_xprt *, struct rpc_task *); /* * Reserved bit positions in xprt->state @@ -419,6 +427,8 @@ void xprt_unlock_connect(struct rpc_xprt *, void *); #define XPRT_BOUND (4) #define XPRT_BINDING (5) #define XPRT_CLOSING (6) +#define XPRT_OFFLINE (7) +#define XPRT_REMOVE (8) #define XPRT_CONGESTED (9) #define XPRT_CWND_WAIT (10) #define XPRT_WRITE_SPACE (11) diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h index c6cce3fbf29d..b19addc8b715 100644 --- a/include/linux/sunrpc/xprtmultipath.h +++ b/include/linux/sunrpc/xprtmultipath.h @@ -10,10 +10,12 @@ #define _NET_SUNRPC_XPRTMULTIPATH_H struct rpc_xprt_iter_ops; +struct rpc_sysfs_xprt_switch; struct rpc_xprt_switch { spinlock_t xps_lock; struct kref xps_kref; + unsigned int xps_id; unsigned int xps_nxprts; unsigned int xps_nactive; atomic_long_t xps_queuelen; @@ -23,6 +25,7 @@ struct rpc_xprt_switch { const struct rpc_xprt_iter_ops *xps_iter_ops; + struct rpc_sysfs_xprt_switch *xps_sysfs; struct rcu_head xps_rcu; }; @@ -71,4 +74,7 @@ extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi); extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, const struct sockaddr *sap); + +extern void xprt_multipath_cleanup_ids(void); + #endif diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 3c1423ee74b4..8c2a712cb242 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -10,6 +10,7 @@ int init_socket_xprt(void); void cleanup_socket_xprt(void); +unsigned short get_srcport(struct rpc_xprt *); #define RPC_MIN_RESVPORT (1U) #define RPC_MAX_RESVPORT (65535U) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 586128d5c3b8..69c9a7010081 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1050,6 +1050,7 @@ asmlinkage long sys_landlock_create_ruleset(const struct landlock_ruleset_attr _ asmlinkage long sys_landlock_add_rule(int ruleset_fd, enum landlock_rule_type rule_type, const void __user *rule_attr, __u32 flags); asmlinkage long sys_landlock_restrict_self(int ruleset_fd, __u32 flags); +asmlinkage long sys_memfd_secret(unsigned int flags); /* * Architecture-specific system calls diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index f311d227aa1b..3357ac98878d 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -28,13 +28,34 @@ struct vdpa_notification_area { }; /** - * struct vdpa_vq_state - vDPA vq_state definition + * struct vdpa_vq_state_split - vDPA split virtqueue state * @avail_index: available index */ -struct vdpa_vq_state { +struct vdpa_vq_state_split { u16 avail_index; }; +/** + * struct vdpa_vq_state_packed - vDPA packed virtqueue state + * @last_avail_counter: last driver ring wrap counter observed by device + * @last_avail_idx: device available index + * @last_used_counter: device ring wrap counter + * @last_used_idx: used index + */ +struct vdpa_vq_state_packed { + u16 last_avail_counter:1; + u16 last_avail_idx:15; + u16 last_used_counter:1; + u16 last_used_idx:15; +}; + +struct vdpa_vq_state { + union { + struct vdpa_vq_state_split split; + struct vdpa_vq_state_packed packed; + }; +}; + struct vdpa_mgmt_dev; /** diff --git a/include/linux/virtio_pci_modern.h b/include/linux/virtio_pci_modern.h index 6a95b58fd0f4..eb2bd9b4077d 100644 --- a/include/linux/virtio_pci_modern.h +++ b/include/linux/virtio_pci_modern.h @@ -79,6 +79,7 @@ static inline void vp_iowrite64_twopart(u64 val, } u64 vp_modern_get_features(struct virtio_pci_modern_device *mdev); +u64 vp_modern_get_driver_features(struct virtio_pci_modern_device *mdev); void vp_modern_set_features(struct virtio_pci_modern_device *mdev, u64 features); u32 vp_modern_generation(struct virtio_pci_modern_device *mdev); diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 1dabd6f22486..2644425b6dce 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -29,7 +29,7 @@ struct notifier_block; /* in notifier.h */ #define VM_NO_HUGE_VMAP 0x00000400 /* force PAGE_SIZE pte mapping */ /* - * VM_KASAN is used slighly differently depending on CONFIG_KASAN_VMALLOC. + * VM_KASAN is used slightly differently depending on CONFIG_KASAN_VMALLOC. * * If IS_ENABLED(CONFIG_KASAN_VMALLOC), VM_KASAN is set on a vm_struct after * shadow memory has been mapped. It's used to handle allocation errors so that @@ -247,7 +247,7 @@ static inline void set_vm_flush_reset_perms(void *addr) extern long vread(char *buf, char *addr, unsigned long count); /* - * Internals. Dont't use.. + * Internals. Don't use.. */ extern struct list_head vmap_area_list; extern __init void vm_area_add_early(struct vm_struct *vm); diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index 14cfd036268a..e3e770f76f34 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -19,7 +19,7 @@ enum rpcif_data_dir { RPCIF_DATA_OUT, }; -struct rpcif_op { +struct rpcif_op { struct { u8 buswidth; u8 opcode; @@ -57,7 +57,7 @@ struct rpcif_op { } data; }; -struct rpcif { +struct rpcif { struct device *dev; void __iomem *dirmap; struct regmap *regmap; @@ -76,7 +76,7 @@ struct rpcif { u32 ddr; /* DRDRENR or SMDRENR */ }; -int rpcif_sw_init(struct rpcif *rpc, struct device *dev); +int rpcif_sw_init(struct rpcif *rpc, struct device *dev); void rpcif_hw_init(struct rpcif *rpc, bool hyperflash); void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, size_t *len); diff --git a/include/soc/imx/cpu.h b/include/soc/imx/cpu.h index 42d6aeb951fa..0bf610acafd0 100644 --- a/include/soc/imx/cpu.h +++ b/include/soc/imx/cpu.h @@ -9,6 +9,7 @@ #define MXC_CPU_MX27 27 #define MXC_CPU_MX31 31 #define MXC_CPU_MX35 35 +#define MXC_CPU_MX50 50 #define MXC_CPU_MX51 51 #define MXC_CPU_MX53 53 #define MXC_CPU_IMX6SL 0x60 diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index 98027a76ce3d..af41ad80ec21 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -6,6 +6,37 @@ #ifndef __SOC_TEGRA_COMMON_H__ #define __SOC_TEGRA_COMMON_H__ +#include +#include + +struct device; + +/** + * Tegra SoC core device OPP table configuration + * + * @init_state: pre-initialize OPP state of a device + */ +struct tegra_core_opp_params { + bool init_state; +}; + +#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra(void); +int devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params); +#else +static inline bool soc_is_tegra(void) +{ + return false; +} + +static inline int +devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params) +{ + return -ENODEV; +} +#endif + #endif /* __SOC_TEGRA_COMMON_H__ */ diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 78cbc787a4dc..990701f788bc 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -52,14 +52,28 @@ struct tegra_sku_info { enum tegra_revision revision; }; +#ifdef CONFIG_ARCH_TEGRA +extern struct tegra_sku_info tegra_sku_info; u32 tegra_read_straps(void); u32 tegra_read_ram_code(void); int tegra_fuse_readl(unsigned long offset, u32 *value); - -#ifdef CONFIG_ARCH_TEGRA -extern struct tegra_sku_info tegra_sku_info; #else static struct tegra_sku_info tegra_sku_info __maybe_unused; + +static inline u32 tegra_read_straps(void) +{ + return 0; +} + +static inline u32 tegra_read_ram_code(void) +{ + return 0; +} + +static inline int tegra_fuse_readl(unsigned long offset, u32 *value) +{ + return -ENODEV; +} #endif struct device *tegra_soc_device_register(void); diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index d2fbe6a8b25b..e19c2504a14b 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -17,34 +18,48 @@ struct clk; struct device; struct page; -struct tegra_smmu_enable { - unsigned int reg; - unsigned int bit; -}; - struct tegra_mc_timing { unsigned long rate; u32 *emem_data; }; -/* latency allowance */ -struct tegra_mc_la { - unsigned int reg; - unsigned int shift; - unsigned int mask; - unsigned int def; -}; - struct tegra_mc_client { unsigned int id; const char *name; - unsigned int swgroup; + /* + * For Tegra210 and earlier, this is the SWGROUP ID used for IOVA translations in the + * Tegra SMMU, whereas on Tegra186 and later this is the ID used to override the ARM SMMU + * stream ID used for IOVA translations for the given memory client. + */ + union { + unsigned int swgroup; + unsigned int sid; + }; unsigned int fifo_size; - struct tegra_smmu_enable smmu; - struct tegra_mc_la la; + struct { + /* Tegra SMMU enable (Tegra210 and earlier) */ + struct { + unsigned int reg; + unsigned int bit; + } smmu; + + /* latency allowance */ + struct { + unsigned int reg; + unsigned int shift; + unsigned int mask; + unsigned int def; + } la; + + /* stream ID overrides (Tegra186 and later) */ + struct { + unsigned int override; + unsigned int security; + } sid; + } regs; }; struct tegra_smmu_swgroup { @@ -155,6 +170,19 @@ struct tegra_mc_icc_ops { void *data); }; +struct tegra_mc_ops { + /* + * @probe: Callback to set up SoC-specific bits of the memory controller. This is called + * after basic, common set up that is done by the SoC-agnostic bits. + */ + int (*probe)(struct tegra_mc *mc); + void (*remove)(struct tegra_mc *mc); + int (*suspend)(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); +}; + struct tegra_mc_soc { const struct tegra_mc_client *clients; unsigned int num_clients; @@ -176,8 +204,7 @@ struct tegra_mc_soc { unsigned int num_resets; const struct tegra_mc_icc_ops *icc_ops; - - int (*init)(struct tegra_mc *mc); + const struct tegra_mc_ops *ops; }; struct tegra_mc { @@ -218,4 +245,6 @@ devm_tegra_memory_controller_get(struct device *dev) } #endif +int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev); + #endif /* __SOC_TEGRA_MC_H__ */ diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index 361cb64246f7..d186bccd125d 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -171,6 +171,8 @@ int tegra_io_rail_power_off(unsigned int id); void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); +bool tegra_pmc_core_domain_state_synced(void); + #else static inline int tegra_powergate_power_on(unsigned int id) { @@ -227,6 +229,11 @@ static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) { } +static inline bool tegra_pmc_core_domain_state_synced(void) +{ + return false; +} + #endif /* CONFIG_SOC_TEGRA_PMC */ #if defined(CONFIG_SOC_TEGRA_PMC) && defined(CONFIG_PM_SLEEP) diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index f211961ce1da..a9d6fcd95f42 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -873,8 +873,13 @@ __SYSCALL(__NR_landlock_add_rule, sys_landlock_add_rule) #define __NR_landlock_restrict_self 446 __SYSCALL(__NR_landlock_restrict_self, sys_landlock_restrict_self) +#ifdef __ARCH_WANT_MEMFD_SECRET +#define __NR_memfd_secret 447 +__SYSCALL(__NR_memfd_secret, sys_memfd_secret) +#endif + #undef __NR_syscalls -#define __NR_syscalls 447 +#define __NR_syscalls 448 /* * 32 bit systems traditionally used different diff --git a/include/uapi/linux/auxvec.h b/include/uapi/linux/auxvec.h index abe5f2b6581b..c7e502bf5a6f 100644 --- a/include/uapi/linux/auxvec.h +++ b/include/uapi/linux/auxvec.h @@ -33,5 +33,8 @@ #define AT_EXECFN 31 /* filename of program */ +#ifndef AT_MINSIGSTKSZ +#define AT_MINSIGSTKSZ 51 /* minimal stack size for signal delivery */ +#endif #endif /* _UAPI_LINUX_AUXVEC_H */ diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index f3956fc11de6..35687dcb1a42 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -97,5 +97,6 @@ #define DEVMEM_MAGIC 0x454d444d /* "DMEM" */ #define Z3FOLD_MAGIC 0x33 #define PPC_CMM_MAGIC 0xc7571590 +#define SECRETMEM_MAGIC 0x5345434d /* "SECM" */ #endif /* __LINUX_MAGIC_H__ */ diff --git a/include/uapi/linux/nbd-netlink.h b/include/uapi/linux/nbd-netlink.h index c5d0ef7aa7d5..2d0b90964227 100644 --- a/include/uapi/linux/nbd-netlink.h +++ b/include/uapi/linux/nbd-netlink.h @@ -35,6 +35,7 @@ enum { NBD_ATTR_SOCKETS, NBD_ATTR_DEAD_CONN_TIMEOUT, NBD_ATTR_DEVICE_LIST, + NBD_ATTR_BACKEND_IDENTIFIER, __NBD_ATTR_MAX, }; #define NBD_ATTR_MAX (__NBD_ATTR_MAX - 1) diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h index c3ab4c826297..f9c1af8d141b 100644 --- a/include/uapi/linux/pcitest.h +++ b/include/uapi/linux/pcitest.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/** +/* * pcitest.h - PCI test uapi defines * * Copyright (C) 2017 Texas Instruments diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 4fe842c3a3a9..70a8057ad4bb 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -57,4 +57,16 @@ #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ #define VIRTIO_ID_BT 40 /* virtio bluetooth */ +/* + * Virtio Transitional IDs + */ + +#define VIRTIO_TRANS_ID_NET 1000 /* transitional virtio net */ +#define VIRTIO_TRANS_ID_BLOCK 1001 /* transitional virtio block */ +#define VIRTIO_TRANS_ID_BALLOON 1002 /* transitional virtio balloon */ +#define VIRTIO_TRANS_ID_CONSOLE 1003 /* transitional virtio console */ +#define VIRTIO_TRANS_ID_SCSI 1004 /* transitional virtio SCSI */ +#define VIRTIO_TRANS_ID_RNG 1005 /* transitional virtio rng */ +#define VIRTIO_TRANS_ID_9P 1009 /* transitional virtio 9p console */ + #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/linux/virtio_pcidev.h b/include/uapi/linux/virtio_pcidev.h new file mode 100644 index 000000000000..89daa88bcfef --- /dev/null +++ b/include/uapi/linux/virtio_pcidev.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * Copyright (C) 2021 Intel Corporation + * Author: Johannes Berg + */ +#ifndef _UAPI_LINUX_VIRTIO_PCIDEV_H +#define _UAPI_LINUX_VIRTIO_PCIDEV_H +#include + +/** + * enum virtio_pcidev_ops - virtual PCI device operations + * @VIRTIO_PCIDEV_OP_CFG_READ: read config space, size is 1, 2, 4 or 8; + * the @data field should be filled in by the device (in little endian). + * @VIRTIO_PCIDEV_OP_CFG_WRITE: write config space, size is 1, 2, 4 or 8; + * the @data field contains the data to write (in little endian). + * @VIRTIO_PCIDEV_OP_BAR_READ: read BAR mem/pio, size can be variable; + * the @data field should be filled in by the device (in little endian). + * @VIRTIO_PCIDEV_OP_BAR_WRITE: write BAR mem/pio, size can be variable; + * the @data field contains the data to write (in little endian). + * @VIRTIO_PCIDEV_OP_MMIO_MEMSET: memset MMIO, size is variable but + * the @data field only has one byte (unlike @VIRTIO_PCIDEV_OP_MMIO_WRITE) + * @VIRTIO_PCIDEV_OP_INT: legacy INTx# pin interrupt, the addr field is 1-4 for + * the number + * @VIRTIO_PCIDEV_OP_MSI: MSI(-X) interrupt, this message basically transports + * the 16- or 32-bit write that would otherwise be done into memory, + * analogous to the write messages (@VIRTIO_PCIDEV_OP_MMIO_WRITE) above + * @VIRTIO_PCIDEV_OP_PME: Dummy message whose content is ignored (and should be + * all zeroes) to signal the PME# pin. + */ +enum virtio_pcidev_ops { + VIRTIO_PCIDEV_OP_RESERVED = 0, + VIRTIO_PCIDEV_OP_CFG_READ, + VIRTIO_PCIDEV_OP_CFG_WRITE, + VIRTIO_PCIDEV_OP_MMIO_READ, + VIRTIO_PCIDEV_OP_MMIO_WRITE, + VIRTIO_PCIDEV_OP_MMIO_MEMSET, + VIRTIO_PCIDEV_OP_INT, + VIRTIO_PCIDEV_OP_MSI, + VIRTIO_PCIDEV_OP_PME, +}; + +/** + * struct virtio_pcidev_msg - virtio PCI device operation + * @op: the operation to do + * @bar: the bar (only with BAR read/write messages) + * @reserved: reserved + * @size: the size of the read/write (in bytes) + * @addr: the address to read/write + * @data: the data, normally @size long, but just one byte for + * %VIRTIO_PCIDEV_OP_MMIO_MEMSET + * + * Note: the fields are all in native (CPU) endian, however, the + * @data values will often be in little endian (see the ops above.) + */ +struct virtio_pcidev_msg { + __u8 op; + __u8 bar; + __u16 reserved; + __u32 size; + __u64 addr; + __u8 data[]; +}; + +#endif /* _UAPI_LINUX_VIRTIO_PCIDEV_H */ diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h index 2af7a1cd6658..b39cdbc522ec 100644 --- a/include/xen/interface/io/ring.h +++ b/include/xen/interface/io/ring.h @@ -1,21 +1,53 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /****************************************************************************** * ring.h * * Shared producer-consumer ring macros. * + * 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 + * AUTHORS OR COPYRIGHT HOLDERS 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. + * * Tim Deegan and Andrew Warfield November 2004. */ #ifndef __XEN_PUBLIC_IO_RING_H__ #define __XEN_PUBLIC_IO_RING_H__ +/* + * When #include'ing this header, you need to provide the following + * declaration upfront: + * - standard integers types (uint8_t, uint16_t, etc) + * They are provided by stdint.h of the standard headers. + * + * In addition, if you intend to use the FLEX macros, you also need to + * provide the following, before invoking the FLEX macros: + * - size_t + * - memcpy + * - grant_ref_t + * These declarations are provided by string.h of the standard headers, + * and grant_table.h from the Xen public headers. + */ + #include typedef unsigned int RING_IDX; /* Round a 32-bit unsigned constant down to the nearest power of two. */ -#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) +#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) #define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x)) #define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x)) #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) @@ -27,82 +59,79 @@ typedef unsigned int RING_IDX; * A ring contains as many entries as will fit, rounded down to the nearest * power of two (so we can mask with (size-1) to loop around). */ -#define __CONST_RING_SIZE(_s, _sz) \ - (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \ - sizeof(((struct _s##_sring *)0)->ring[0]))) - +#define __CONST_RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \ + sizeof(((struct _s##_sring *)0)->ring[0]))) /* * The same for passing in an actual pointer instead of a name tag. */ -#define __RING_SIZE(_s, _sz) \ - (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) +#define __RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) /* * Macros to make the correct C datatypes for a new kind of ring. * * To make a new ring datatype, you need to have two message structures, - * let's say struct request, and struct response already defined. + * let's say request_t, and response_t already defined. * * In a header where you want the ring datatype declared, you then do: * - * DEFINE_RING_TYPES(mytag, struct request, struct response); + * DEFINE_RING_TYPES(mytag, request_t, response_t); * * These expand out to give you a set of types, as you can see below. * The most important of these are: * - * struct mytag_sring - The shared ring. - * struct mytag_front_ring - The 'front' half of the ring. - * struct mytag_back_ring - The 'back' half of the ring. + * mytag_sring_t - The shared ring. + * mytag_front_ring_t - The 'front' half of the ring. + * mytag_back_ring_t - The 'back' half of the ring. * * To initialize a ring in your code you need to know the location and size * of the shared memory area (PAGE_SIZE, for instance). To initialise * the front half: * - * struct mytag_front_ring front_ring; - * SHARED_RING_INIT((struct mytag_sring *)shared_page); - * FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page, - * PAGE_SIZE); + * mytag_front_ring_t front_ring; + * SHARED_RING_INIT((mytag_sring_t *)shared_page); + * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); * * Initializing the back follows similarly (note that only the front * initializes the shared ring): * - * struct mytag_back_ring back_ring; - * BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page, - * PAGE_SIZE); + * mytag_back_ring_t back_ring; + * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); */ -#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ - \ -/* Shared ring entry */ \ -union __name##_sring_entry { \ - __req_t req; \ - __rsp_t rsp; \ -}; \ - \ -/* Shared ring page */ \ -struct __name##_sring { \ - RING_IDX req_prod, req_event; \ - RING_IDX rsp_prod, rsp_event; \ - uint8_t pad[48]; \ - union __name##_sring_entry ring[1]; /* variable-length */ \ -}; \ - \ -/* "Front" end's private variables */ \ -struct __name##_front_ring { \ - RING_IDX req_prod_pvt; \ - RING_IDX rsp_cons; \ - unsigned int nr_ents; \ - struct __name##_sring *sring; \ -}; \ - \ -/* "Back" end's private variables */ \ -struct __name##_back_ring { \ - RING_IDX rsp_prod_pvt; \ - RING_IDX req_cons; \ - unsigned int nr_ents; \ - struct __name##_sring *sring; \ -}; - +#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ + \ +/* Shared ring entry */ \ +union __name##_sring_entry { \ + __req_t req; \ + __rsp_t rsp; \ +}; \ + \ +/* Shared ring page */ \ +struct __name##_sring { \ + RING_IDX req_prod, req_event; \ + RING_IDX rsp_prod, rsp_event; \ + uint8_t __pad[48]; \ + union __name##_sring_entry ring[1]; /* variable-length */ \ +}; \ + \ +/* "Front" end's private variables */ \ +struct __name##_front_ring { \ + RING_IDX req_prod_pvt; \ + RING_IDX rsp_cons; \ + unsigned int nr_ents; \ + struct __name##_sring *sring; \ +}; \ + \ +/* "Back" end's private variables */ \ +struct __name##_back_ring { \ + RING_IDX rsp_prod_pvt; \ + RING_IDX req_cons; \ + unsigned int nr_ents; \ + struct __name##_sring *sring; \ +}; \ + \ /* * Macros for manipulating rings. * @@ -119,94 +148,99 @@ struct __name##_back_ring { \ */ /* Initialising empty rings */ -#define SHARED_RING_INIT(_s) do { \ - (_s)->req_prod = (_s)->rsp_prod = 0; \ - (_s)->req_event = (_s)->rsp_event = 1; \ - memset((_s)->pad, 0, sizeof((_s)->pad)); \ +#define SHARED_RING_INIT(_s) do { \ + (_s)->req_prod = (_s)->rsp_prod = 0; \ + (_s)->req_event = (_s)->rsp_event = 1; \ + (void)memset((_s)->__pad, 0, sizeof((_s)->__pad)); \ } while(0) -#define FRONT_RING_ATTACH(_r, _s, _i, __size) do { \ - (_r)->req_prod_pvt = (_i); \ - (_r)->rsp_cons = (_i); \ - (_r)->nr_ents = __RING_SIZE(_s, __size); \ - (_r)->sring = (_s); \ +#define FRONT_RING_ATTACH(_r, _s, _i, __size) do { \ + (_r)->req_prod_pvt = (_i); \ + (_r)->rsp_cons = (_i); \ + (_r)->nr_ents = __RING_SIZE(_s, __size); \ + (_r)->sring = (_s); \ } while (0) #define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size) -#define BACK_RING_ATTACH(_r, _s, _i, __size) do { \ - (_r)->rsp_prod_pvt = (_i); \ - (_r)->req_cons = (_i); \ - (_r)->nr_ents = __RING_SIZE(_s, __size); \ - (_r)->sring = (_s); \ +#define BACK_RING_ATTACH(_r, _s, _i, __size) do { \ + (_r)->rsp_prod_pvt = (_i); \ + (_r)->req_cons = (_i); \ + (_r)->nr_ents = __RING_SIZE(_s, __size); \ + (_r)->sring = (_s); \ } while (0) #define BACK_RING_INIT(_r, _s, __size) BACK_RING_ATTACH(_r, _s, 0, __size) /* How big is this ring? */ -#define RING_SIZE(_r) \ +#define RING_SIZE(_r) \ ((_r)->nr_ents) /* Number of free requests (for use on front side only). */ -#define RING_FREE_REQUESTS(_r) \ +#define RING_FREE_REQUESTS(_r) \ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons)) /* Test if there is an empty slot available on the front ring. * (This is only meaningful from the front. ) */ -#define RING_FULL(_r) \ +#define RING_FULL(_r) \ (RING_FREE_REQUESTS(_r) == 0) /* Test if there are outstanding messages to be processed on a ring. */ -#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ +#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ ((_r)->sring->rsp_prod - (_r)->rsp_cons) -#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ - ({ \ - unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ - unsigned int rsp = RING_SIZE(_r) - \ - ((_r)->req_cons - (_r)->rsp_prod_pvt); \ - req < rsp ? req : rsp; \ - }) +#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ + unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ + unsigned int rsp = RING_SIZE(_r) - \ + ((_r)->req_cons - (_r)->rsp_prod_pvt); \ + req < rsp ? req : rsp; \ +}) /* Direct access to individual ring elements, by index. */ -#define RING_GET_REQUEST(_r, _idx) \ +#define RING_GET_REQUEST(_r, _idx) \ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) +#define RING_GET_RESPONSE(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) + /* - * Get a local copy of a request. + * Get a local copy of a request/response. * - * Use this in preference to RING_GET_REQUEST() so all processing is + * Use this in preference to RING_GET_{REQUEST,RESPONSE}() so all processing is * done on a local copy that cannot be modified by the other end. * * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this - * to be ineffective where _req is a struct which consists of only bitfields. + * to be ineffective where dest is a struct which consists of only bitfields. */ -#define RING_COPY_REQUEST(_r, _idx, _req) do { \ - /* Use volatile to force the copy into _req. */ \ - *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \ +#define RING_COPY_(type, r, idx, dest) do { \ + /* Use volatile to force the copy into dest. */ \ + *(dest) = *(volatile typeof(dest))RING_GET_##type(r, idx); \ } while (0) -#define RING_GET_RESPONSE(_r, _idx) \ - (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) +#define RING_COPY_REQUEST(r, idx, req) RING_COPY_(REQUEST, r, idx, req) +#define RING_COPY_RESPONSE(r, idx, rsp) RING_COPY_(RESPONSE, r, idx, rsp) /* Loop termination condition: Would the specified index overflow the ring? */ -#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ +#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) /* Ill-behaved frontend determination: Can there be this many requests? */ -#define RING_REQUEST_PROD_OVERFLOW(_r, _prod) \ +#define RING_REQUEST_PROD_OVERFLOW(_r, _prod) \ (((_prod) - (_r)->rsp_prod_pvt) > RING_SIZE(_r)) +/* Ill-behaved backend determination: Can there be this many responses? */ +#define RING_RESPONSE_PROD_OVERFLOW(_r, _prod) \ + (((_prod) - (_r)->rsp_cons) > RING_SIZE(_r)) -#define RING_PUSH_REQUESTS(_r) do { \ - virt_wmb(); /* back sees requests /before/ updated producer index */ \ - (_r)->sring->req_prod = (_r)->req_prod_pvt; \ +#define RING_PUSH_REQUESTS(_r) do { \ + virt_wmb(); /* back sees requests /before/ updated producer index */\ + (_r)->sring->req_prod = (_r)->req_prod_pvt; \ } while (0) -#define RING_PUSH_RESPONSES(_r) do { \ - virt_wmb(); /* front sees responses /before/ updated producer index */ \ - (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ +#define RING_PUSH_RESPONSES(_r) do { \ + virt_wmb(); /* front sees resps /before/ updated producer index */ \ + (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ } while (0) /* @@ -239,40 +273,40 @@ struct __name##_back_ring { \ * field appropriately. */ -#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ - RING_IDX __old = (_r)->sring->req_prod; \ - RING_IDX __new = (_r)->req_prod_pvt; \ - virt_wmb(); /* back sees requests /before/ updated producer index */ \ - (_r)->sring->req_prod = __new; \ - virt_mb(); /* back sees new requests /before/ we check req_event */ \ - (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ - (RING_IDX)(__new - __old)); \ +#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ + RING_IDX __old = (_r)->sring->req_prod; \ + RING_IDX __new = (_r)->req_prod_pvt; \ + virt_wmb(); /* back sees requests /before/ updated producer index */\ + (_r)->sring->req_prod = __new; \ + virt_mb(); /* back sees new requests /before/ we check req_event */ \ + (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ + (RING_IDX)(__new - __old)); \ } while (0) -#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ - RING_IDX __old = (_r)->sring->rsp_prod; \ - RING_IDX __new = (_r)->rsp_prod_pvt; \ - virt_wmb(); /* front sees responses /before/ updated producer index */ \ - (_r)->sring->rsp_prod = __new; \ - virt_mb(); /* front sees new responses /before/ we check rsp_event */ \ - (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ - (RING_IDX)(__new - __old)); \ +#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ + RING_IDX __old = (_r)->sring->rsp_prod; \ + RING_IDX __new = (_r)->rsp_prod_pvt; \ + virt_wmb(); /* front sees resps /before/ updated producer index */ \ + (_r)->sring->rsp_prod = __new; \ + virt_mb(); /* front sees new resps /before/ we check rsp_event */ \ + (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ + (RING_IDX)(__new - __old)); \ } while (0) -#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ - (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ - if (_work_to_do) break; \ - (_r)->sring->req_event = (_r)->req_cons + 1; \ - virt_mb(); \ - (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ +#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ + (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ + if (_work_to_do) break; \ + (_r)->sring->req_event = (_r)->req_cons + 1; \ + virt_mb(); \ + (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ } while (0) -#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ - (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ - if (_work_to_do) break; \ - (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ - virt_mb(); \ - (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ +#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ + (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ + if (_work_to_do) break; \ + (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ + virt_mb(); \ + (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ } while (0) diff --git a/init/Kconfig b/init/Kconfig index 3892833bb972..969e6e7f3d6f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1858,6 +1858,7 @@ config SLUB_DEBUG default y bool "Enable SLUB debugging support" if EXPERT depends on SLUB && SYSFS + select STACKDEPOT if STACKTRACE_SUPPORT help SLUB has extensive debug support features. Disabling these can result in significant savings in code size. This also disables diff --git a/init/Makefile b/init/Makefile index 6bc37f64b361..2846113677ee 100644 --- a/init/Makefile +++ b/init/Makefile @@ -27,11 +27,11 @@ $(obj)/version.o: include/generated/compile.h # mkcompile_h will make sure to only update the # actual file if its content has changed. - chk_compile.h = : - quiet_chk_compile.h = echo ' CHK $@' -silent_chk_compile.h = : -include/generated/compile.h: FORCE - @$($(quiet)chk_compile.h) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ +quiet_cmd_compile.h = CHK $@ + cmd_compile.h = \ + $(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" \ "$(CONFIG_PREEMPT_RT)" $(CONFIG_CC_VERSION_TEXT) "$(LD)" + +include/generated/compile.h: FORCE + $(call cmd,compile.h) diff --git a/init/main.c b/init/main.c index af521b30a3b8..f5b8246e8aa1 100644 --- a/init/main.c +++ b/init/main.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -913,6 +914,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) set_task_stack_end_magic(&init_task); smp_setup_processor_id(); debug_objects_early_init(); + init_vmlinux_build_id(); cgroup_init_early(); diff --git a/kernel/crash_core.c b/kernel/crash_core.c index da449c1cdca7..eb53f5ec62c9 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -4,6 +4,7 @@ * Copyright (C) 2002-2004 Eric Biederman */ +#include #include #include #include @@ -378,53 +379,6 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void) } EXPORT_SYMBOL(paddr_vmcoreinfo_note); -#define NOTES_SIZE (&__stop_notes - &__start_notes) -#define BUILD_ID_MAX SHA1_DIGEST_SIZE -#define NT_GNU_BUILD_ID 3 - -struct elf_note_section { - struct elf_note n_hdr; - u8 n_data[]; -}; - -/* - * Add build ID from .notes section as generated by the GNU ld(1) - * or LLVM lld(1) --build-id option. - */ -static void add_build_id_vmcoreinfo(void) -{ - char build_id[BUILD_ID_MAX * 2 + 1]; - int n_remain = NOTES_SIZE; - - while (n_remain >= sizeof(struct elf_note)) { - const struct elf_note_section *note_sec = - &__start_notes + NOTES_SIZE - n_remain; - const u32 n_namesz = note_sec->n_hdr.n_namesz; - - if (note_sec->n_hdr.n_type == NT_GNU_BUILD_ID && - n_namesz != 0 && - !strcmp((char *)¬e_sec->n_data[0], "GNU")) { - if (note_sec->n_hdr.n_descsz <= BUILD_ID_MAX) { - const u32 n_descsz = note_sec->n_hdr.n_descsz; - const u8 *s = ¬e_sec->n_data[n_namesz]; - - s = PTR_ALIGN(s, 4); - bin2hex(build_id, s, n_descsz); - build_id[2 * n_descsz] = '\0'; - VMCOREINFO_BUILD_ID(build_id); - return; - } - pr_warn("Build ID is too large to include in vmcoreinfo: %u > %u\n", - note_sec->n_hdr.n_descsz, - BUILD_ID_MAX); - return; - } - n_remain -= sizeof(struct elf_note) + - ALIGN(note_sec->n_hdr.n_namesz, 4) + - ALIGN(note_sec->n_hdr.n_descsz, 4); - } -} - static int __init crash_save_vmcoreinfo_init(void) { vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL); @@ -443,7 +397,7 @@ static int __init crash_save_vmcoreinfo_init(void) } VMCOREINFO_OSRELEASE(init_uts_ns.name.release); - add_build_id_vmcoreinfo(); + VMCOREINFO_BUILD_ID(); VMCOREINFO_PAGESIZE(PAGE_SIZE); VMCOREINFO_SYMBOL(init_uts_ns); diff --git a/kernel/gen_kheaders.sh b/kernel/gen_kheaders.sh index 34a1dc2abc7d..1966a749e0d9 100755 --- a/kernel/gen_kheaders.sh +++ b/kernel/gen_kheaders.sh @@ -56,9 +56,7 @@ if [ -f kernel/kheaders.md5 ] && exit fi -if [ "${quiet}" != "silent_" ]; then - echo " GEN $tarfile" -fi +echo " GEN $tarfile" rm -rf $cpio_dir mkdir $cpio_dir diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 6db413a3fd15..f931389a0647 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -682,7 +682,6 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq); * usually for a root interrupt controller * @domain: The domain where to perform the lookup * @hwirq: The HW irq number to convert to a logical one - * @lookup: Whether to perform the domain lookup or not * @regs: Register file coming from the low-level handling code * * Returns: 0 on success, or -EINVAL if conversion has failed diff --git a/kernel/jump_label.c b/kernel/jump_label.c index bdb0681bece8..b156e152d6b4 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -316,14 +316,16 @@ static int addr_conflict(struct jump_entry *entry, void *start, void *end) } static int __jump_label_text_reserved(struct jump_entry *iter_start, - struct jump_entry *iter_stop, void *start, void *end) + struct jump_entry *iter_stop, void *start, void *end, bool init) { struct jump_entry *iter; iter = iter_start; while (iter < iter_stop) { - if (addr_conflict(iter, start, end)) - return 1; + if (init || !jump_entry_is_init(iter)) { + if (addr_conflict(iter, start, end)) + return 1; + } iter++; } @@ -562,7 +564,7 @@ static int __jump_label_mod_text_reserved(void *start, void *end) ret = __jump_label_text_reserved(mod->jump_entries, mod->jump_entries + mod->num_jump_entries, - start, end); + start, end, mod->state == MODULE_STATE_COMING); module_put(mod); @@ -788,8 +790,9 @@ early_initcall(jump_label_init_module); */ int jump_label_text_reserved(void *start, void *end) { + bool init = system_state < SYSTEM_RUNNING; int ret = __jump_label_text_reserved(__start___jump_table, - __stop___jump_table, start, end); + __stop___jump_table, start, end, init); if (ret) return ret; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index c851ca0ed357..0ba87982d017 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -25,7 +25,10 @@ #include #include #include +#include #include +#include +#include /* * These will be re-linked against their real values @@ -297,21 +300,14 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, get_symbol_pos(addr, symbolsize, offset); return 1; } - return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) || + return !!module_address_lookup(addr, symbolsize, offset, NULL, NULL, namebuf) || !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); } -/* - * Lookup an address - * - modname is set to NULL if it's in the kernel. - * - We guarantee that the returned name is valid until we reschedule even if. - * It resides in a module. - * - We also guarantee that modname will be valid until rescheduled. - */ -const char *kallsyms_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, char *namebuf) +static const char *kallsyms_lookup_buildid(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset, char **modname, + const unsigned char **modbuildid, char *namebuf) { const char *ret; @@ -327,6 +323,8 @@ const char *kallsyms_lookup(unsigned long addr, namebuf, KSYM_NAME_LEN); if (modname) *modname = NULL; + if (modbuildid) + *modbuildid = NULL; ret = namebuf; goto found; @@ -334,7 +332,7 @@ const char *kallsyms_lookup(unsigned long addr, /* See if it's in a module or a BPF JITed image. */ ret = module_address_lookup(addr, symbolsize, offset, - modname, namebuf); + modname, modbuildid, namebuf); if (!ret) ret = bpf_address_lookup(addr, symbolsize, offset, modname, namebuf); @@ -348,6 +346,22 @@ found: return ret; } +/* + * Lookup an address + * - modname is set to NULL if it's in the kernel. + * - We guarantee that the returned name is valid until we reschedule even if. + * It resides in a module. + * - We also guarantee that modname will be valid until rescheduled. + */ +const char *kallsyms_lookup(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset, + char **modname, char *namebuf) +{ + return kallsyms_lookup_buildid(addr, symbolsize, offset, modname, + NULL, namebuf); +} + int lookup_symbol_name(unsigned long addr, char *symname) { int res; @@ -404,15 +418,17 @@ found: /* Look up a kernel symbol and return it in a text buffer. */ static int __sprint_symbol(char *buffer, unsigned long address, - int symbol_offset, int add_offset) + int symbol_offset, int add_offset, int add_buildid) { char *modname; + const unsigned char *buildid; const char *name; unsigned long offset, size; int len; address += symbol_offset; - name = kallsyms_lookup(address, &size, &offset, &modname, buffer); + name = kallsyms_lookup_buildid(address, &size, &offset, &modname, &buildid, + buffer); if (!name) return sprintf(buffer, "0x%lx", address - symbol_offset); @@ -424,8 +440,19 @@ static int __sprint_symbol(char *buffer, unsigned long address, if (add_offset) len += sprintf(buffer + len, "+%#lx/%#lx", offset, size); - if (modname) - len += sprintf(buffer + len, " [%s]", modname); + if (modname) { + len += sprintf(buffer + len, " [%s", modname); +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) + if (add_buildid && buildid) { + /* build ID should match length of sprintf */ +#if IS_ENABLED(CONFIG_MODULES) + static_assert(sizeof(typeof_member(struct module, build_id)) == 20); +#endif + len += sprintf(buffer + len, " %20phN", buildid); + } +#endif + len += sprintf(buffer + len, "]"); + } return len; } @@ -443,10 +470,27 @@ static int __sprint_symbol(char *buffer, unsigned long address, */ int sprint_symbol(char *buffer, unsigned long address) { - return __sprint_symbol(buffer, address, 0, 1); + return __sprint_symbol(buffer, address, 0, 1, 0); } EXPORT_SYMBOL_GPL(sprint_symbol); +/** + * sprint_symbol_build_id - Look up a kernel symbol and return it in a text buffer + * @buffer: buffer to be stored + * @address: address to lookup + * + * This function looks up a kernel symbol with @address and stores its name, + * offset, size, module name and module build ID to @buffer if possible. If no + * symbol was found, just saves its @address as is. + * + * This function returns the number of bytes stored in @buffer. + */ +int sprint_symbol_build_id(char *buffer, unsigned long address) +{ + return __sprint_symbol(buffer, address, 0, 1, 1); +} +EXPORT_SYMBOL_GPL(sprint_symbol_build_id); + /** * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer * @buffer: buffer to be stored @@ -460,7 +504,7 @@ EXPORT_SYMBOL_GPL(sprint_symbol); */ int sprint_symbol_no_offset(char *buffer, unsigned long address) { - return __sprint_symbol(buffer, address, 0, 0); + return __sprint_symbol(buffer, address, 0, 0, 0); } EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); @@ -480,7 +524,27 @@ EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); */ int sprint_backtrace(char *buffer, unsigned long address) { - return __sprint_symbol(buffer, address, -1, 1); + return __sprint_symbol(buffer, address, -1, 1, 0); +} + +/** + * sprint_backtrace_build_id - Look up a backtrace symbol and return it in a text buffer + * @buffer: buffer to be stored + * @address: address to lookup + * + * This function is for stack backtrace and does the same thing as + * sprint_symbol() but with modified/decreased @address. If there is a + * tail-call to the function marked "noreturn", gcc optimized out code after + * the call so that the stack-saved return address could point outside of the + * caller. This function ensures that kallsyms will find the original caller + * by decreasing @address. This function also appends the module build ID to + * the @buffer if @address is within a kernel module. + * + * This function returns the number of bytes stored in @buffer. + */ +int sprint_backtrace_build_id(char *buffer, unsigned long address) +{ + return __sprint_symbol(buffer, address, -1, 1, 1); } /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 471b1d18a92f..790a573bbe00 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1561,6 +1562,7 @@ static int check_kprobe_address_safe(struct kprobe *p, if (!kernel_text_address((unsigned long) p->addr) || within_kprobe_blacklist((unsigned long) p->addr) || jump_label_text_reserved(p->addr, p->addr) || + static_call_text_reserved(p->addr, p->addr) || find_bug((unsigned long)p->addr)) { ret = -EINVAL; goto out; diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c index 806978314496..b8d9a050c337 100644 --- a/kernel/locking/lockdep_proc.c +++ b/kernel/locking/lockdep_proc.c @@ -70,26 +70,28 @@ static int l_show(struct seq_file *m, void *v) #ifdef CONFIG_DEBUG_LOCKDEP seq_printf(m, " OPS:%8ld", debug_class_ops_read(class)); #endif -#ifdef CONFIG_PROVE_LOCKING - seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); - seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class)); -#endif + if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { + seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); + seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class)); - get_usage_chars(class, usage); - seq_printf(m, " %s", usage); + get_usage_chars(class, usage); + seq_printf(m, " %s", usage); + } seq_printf(m, ": "); print_name(m, class); seq_puts(m, "\n"); - list_for_each_entry(entry, &class->locks_after, entry) { - if (entry->distance == 1) { - seq_printf(m, " -> [%p] ", entry->class->key); - print_name(m, entry->class); - seq_puts(m, "\n"); + if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { + list_for_each_entry(entry, &class->locks_after, entry) { + if (entry->distance == 1) { + seq_printf(m, " -> [%p] ", entry->class->key); + print_name(m, entry->class); + seq_puts(m, "\n"); + } } + seq_puts(m, "\n"); } - seq_puts(m, "\n"); return 0; } diff --git a/kernel/module.c b/kernel/module.c index 073286a54d7c..d333d97ee1e8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1019,8 +1020,7 @@ void __symbol_put(const char *symbol) }; preempt_disable(); - if (!find_symbol(&fsa)) - BUG(); + BUG_ON(!find_symbol(&fsa)); module_put(fsa.owner); preempt_enable(); } @@ -1468,6 +1468,13 @@ resolve_symbol_wait(struct module *mod, return ksym; } +#ifdef CONFIG_KALLSYMS +static inline bool sect_empty(const Elf_Shdr *sect) +{ + return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; +} +#endif + /* * /sys/module/foo/sections stuff * J. Corbet @@ -1475,11 +1482,6 @@ resolve_symbol_wait(struct module *mod, #ifdef CONFIG_SYSFS #ifdef CONFIG_KALLSYMS -static inline bool sect_empty(const Elf_Shdr *sect) -{ - return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; -} - struct module_sect_attr { struct bin_attribute battr; unsigned long address; @@ -2800,6 +2802,26 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) } #endif /* CONFIG_KALLSYMS */ +#if IS_ENABLED(CONFIG_KALLSYMS) && IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +static void init_build_id(struct module *mod, const struct load_info *info) +{ + const Elf_Shdr *sechdr; + unsigned int i; + + for (i = 0; i < info->hdr->e_shnum; i++) { + sechdr = &info->sechdrs[i]; + if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE && + !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id, + sechdr->sh_size)) + break; + } +} +#else +static void init_build_id(struct module *mod, const struct load_info *info) +{ +} +#endif + static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num) { if (!debug) @@ -4024,6 +4046,7 @@ static int load_module(struct load_info *info, const char __user *uargs, goto free_arch_cleanup; } + init_build_id(mod, info); dynamic_debug_setup(mod, info->debug, info->num_debug); /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ @@ -4257,6 +4280,7 @@ const char *module_address_lookup(unsigned long addr, unsigned long *size, unsigned long *offset, char **modname, + const unsigned char **modbuildid, char *namebuf) { const char *ret = NULL; @@ -4267,6 +4291,13 @@ const char *module_address_lookup(unsigned long addr, if (mod) { if (modname) *modname = mod->name; + if (modbuildid) { +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) + *modbuildid = mod->build_id; +#else + *modbuildid = NULL; +#endif + } ret = find_kallsyms_symbol(mod, addr, size, offset); } @@ -4427,9 +4458,10 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, ret = fn(data, kallsyms_symbol_name(kallsyms, i), mod, kallsyms_symbol_value(sym)); if (ret != 0) - break; + goto out; } } +out: mutex_unlock(&module_mutex); return ret; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index da0b41914177..559acef3fddb 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "power.h" @@ -81,7 +82,9 @@ void hibernate_release(void) bool hibernation_available(void) { - return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION); + return nohibernate == 0 && + !security_locked_down(LOCKDOWN_HIBERNATION) && + !secretmem_active(); } /** diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1dd248dbd1cb..249479dd4633 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7218,6 +7218,7 @@ int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr) { return __sched_setscheduler(p, attr, false, true); } +EXPORT_SYMBOL_GPL(sched_setattr_nocheck); /** * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace. diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e344a3147824..a19f0ffe9db1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3040,8 +3040,9 @@ enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) static inline void dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { + u32 divider = get_pelt_divider(&se->avg); sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg); - sub_positive(&cfs_rq->avg.load_sum, se_weight(se) * se->avg.load_sum); + cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * divider; } #else static inline void @@ -5084,7 +5085,7 @@ static const u64 cfs_bandwidth_slack_period = 5 * NSEC_PER_MSEC; static int runtime_refresh_within(struct cfs_bandwidth *cfs_b, u64 min_expire) { struct hrtimer *refresh_timer = &cfs_b->period_timer; - u64 remaining; + s64 remaining; /* if the call-back is running a quota refresh is already occurring */ if (hrtimer_callback_running(refresh_timer)) @@ -5092,7 +5093,7 @@ static int runtime_refresh_within(struct cfs_bandwidth *cfs_b, u64 min_expire) /* is a quota refresh about to occur? */ remaining = ktime_to_ns(hrtimer_expires_remaining(refresh_timer)); - if (remaining < min_expire) + if (remaining < (s64)min_expire) return 1; return 0; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 92a60d37b471..1c92a258e571 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2828,20 +2828,27 @@ static __always_inline unsigned long uclamp_rq_util_with(struct rq *rq, unsigned long util, struct task_struct *p) { - unsigned long min_util; - unsigned long max_util; + unsigned long min_util = 0; + unsigned long max_util = 0; if (!static_branch_likely(&sched_uclamp_used)) return util; - min_util = READ_ONCE(rq->uclamp[UCLAMP_MIN].value); - max_util = READ_ONCE(rq->uclamp[UCLAMP_MAX].value); - if (p) { - min_util = max(min_util, uclamp_eff_value(p, UCLAMP_MIN)); - max_util = max(max_util, uclamp_eff_value(p, UCLAMP_MAX)); + min_util = uclamp_eff_value(p, UCLAMP_MIN); + max_util = uclamp_eff_value(p, UCLAMP_MAX); + + /* + * Ignore last runnable task's max clamp, as this task will + * reset it. Similarly, no need to read the rq's min clamp. + */ + if (rq->uclamp_flags & UCLAMP_FLAG_IDLE) + goto out; } + min_util = max_t(unsigned long, min_util, READ_ONCE(rq->uclamp[UCLAMP_MIN].value)); + max_util = max_t(unsigned long, max_util, READ_ONCE(rq->uclamp[UCLAMP_MAX].value)); +out: /* * Since CPU's {min,max}_util clamps are MAX aggregated considering * RUNNABLE tasks with _different_ clamps, we can end up with an diff --git a/kernel/signal.c b/kernel/signal.c index 5c590bc8c403..6aa994db6521 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -426,18 +426,30 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, rcu_read_lock(); ucounts = task_ucounts(t); sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1); - if (sigpending == 1) - ucounts = get_ucounts(ucounts); + switch (sigpending) { + case 1: + if (likely(get_ucounts(ucounts))) + break; + fallthrough; + case LONG_MAX: + /* + * we need to decrease the ucount in the userns tree on any + * failure to avoid counts leaking. + */ + dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1); + rcu_read_unlock(); + return NULL; + } rcu_read_unlock(); - if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) { + if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) { q = kmem_cache_alloc(sigqueue_cachep, gfp_flags); } else { print_dropped_signal(sig); } if (unlikely(q == NULL)) { - if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) + if (dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) put_ucounts(ucounts); } else { INIT_LIST_HEAD(&q->list); diff --git a/kernel/static_call.c b/kernel/static_call.c index 723fcc9d20db..43ba0b1e0edb 100644 --- a/kernel/static_call.c +++ b/kernel/static_call.c @@ -292,13 +292,15 @@ static int addr_conflict(struct static_call_site *site, void *start, void *end) static int __static_call_text_reserved(struct static_call_site *iter_start, struct static_call_site *iter_stop, - void *start, void *end) + void *start, void *end, bool init) { struct static_call_site *iter = iter_start; while (iter < iter_stop) { - if (addr_conflict(iter, start, end)) - return 1; + if (init || !static_call_is_init(iter)) { + if (addr_conflict(iter, start, end)) + return 1; + } iter++; } @@ -324,7 +326,7 @@ static int __static_call_mod_text_reserved(void *start, void *end) ret = __static_call_text_reserved(mod->static_call_sites, mod->static_call_sites + mod->num_static_call_sites, - start, end); + start, end, mod->state == MODULE_STATE_COMING); module_put(mod); @@ -459,8 +461,9 @@ static inline int __static_call_mod_text_reserved(void *start, void *end) int static_call_text_reserved(void *start, void *end) { + bool init = system_state < SYSTEM_RUNNING; int ret = __static_call_text_reserved(__start_static_call_sites, - __stop_static_call_sites, start, end); + __stop_static_call_sites, start, end, init); if (ret) return ret; diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index dad4d994641e..30971b1dd4a9 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -358,6 +358,8 @@ COND_SYSCALL(pkey_mprotect); COND_SYSCALL(pkey_alloc); COND_SYSCALL(pkey_free); +/* memfd_secret */ +COND_SYSCALL(memfd_secret); /* * Architecture specific weak syscall entries. diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 72ef4dccbcc4..e6fb3e6e1ffc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4212,8 +4212,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops, if (!func) /* warn? */ continue; - list_del(&ftrace_mod->list); - list_add(&ftrace_mod->list, &process_mods); + list_move(&ftrace_mod->list, &process_mods); /* Use the newly allocated func, as it may be "*" */ kfree(ftrace_mod->func); diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ba03b7d84fc2..0207aeed31e6 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -1555,6 +1555,13 @@ static int contains_operator(char *str) switch (*op) { case '-': + /* + * Unfortunately, the modifier ".sym-offset" + * can confuse things. + */ + if (op - str >= 4 && !strncmp(op - 4, ".sym-offset", 11)) + return FIELD_OP_NONE; + if (*str == '-') field_op = FIELD_OP_UNARY_MINUS; else diff --git a/lib/Kconfig b/lib/Kconfig index ac3b30697b2b..d241fe476fda 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -102,6 +102,20 @@ config INDIRECT_PIO When in doubt, say N. +config INDIRECT_IOMEM + bool + help + This is selected by other options/architectures to provide the + emulated iomem accessors. + +config INDIRECT_IOMEM_FALLBACK + bool + depends on INDIRECT_IOMEM + help + If INDIRECT_IOMEM is selected, this enables falling back to plain + mmio accesses when the IO memory address is not a registered + emulated region. + config CRC_CCITT tristate "CRC-CCITT functions" help diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8acc01d7d816..831212722924 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -35,6 +35,17 @@ config PRINTK_CALLER no option to enable/disable at the kernel command line parameter or sysfs interface. +config STACKTRACE_BUILD_ID + bool "Show build ID information in stacktraces" + depends on PRINTK + help + Selecting this option adds build ID information for symbols in + stacktraces printed with the printk format '%p[SR]b'. + + This option is intended for distros where debuginfo is not easily + accessible but can be downloaded given the build ID of the vmlinux or + kernel module where the function is located. + config CONSOLE_LOGLEVEL_DEFAULT int "Default console loglevel (1-15)" range 1 15 @@ -313,9 +324,6 @@ config DEBUG_INFO_BTF config PAHOLE_HAS_SPLIT_BTF def_bool $(success, test `$(PAHOLE) --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'` -ge "119") -config PAHOLE_HAS_ZEROSIZE_PERCPU_SUPPORT - def_bool $(success, test `$(PAHOLE) --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'` -ge "122") - config DEBUG_INFO_BTF_MODULES def_bool y depends on DEBUG_INFO_BTF && MODULES && PAHOLE_HAS_SPLIT_BTF @@ -403,8 +411,8 @@ config SECTION_MISMATCH_WARN_ONLY If unsure, say Y. -config DEBUG_FORCE_FUNCTION_ALIGN_32B - bool "Force all function address 32B aligned" if EXPERT +config DEBUG_FORCE_FUNCTION_ALIGN_64B + bool "Force all function address 64B aligned" if EXPERT help There are cases that a commit from one domain changes the function address alignment of other domains, and cause magic performance @@ -1282,7 +1290,7 @@ config PROVE_RAW_LOCK_NESTING option expect lockdep splats until these problems have been fully addressed which is work in progress. This config switch allows to identify and analyze these problems. It will be removed and the - check permanentely enabled once the main issues have been fixed. + check permanently enabled once the main issues have been fixed. If unsure, select N. @@ -1448,7 +1456,7 @@ config DEBUG_LOCKING_API_SELFTESTS Say Y here if you want the kernel to run a short self-test during bootup. The self-test checks whether common types of locking bugs are detected by debugging mechanisms or not. (if you disable - lock debugging then those bugs wont be detected of course.) + lock debugging then those bugs won't be detected of course.) The following locking APIs are covered: spinlocks, rwlocks, mutexes and rwsems. @@ -1928,7 +1936,7 @@ config FAIL_IO_TIMEOUT thus exercising the error handling. Only works with drivers that use the generic timeout handling, - for others it wont do anything. + for others it won't do anything. config FAIL_FUTEX bool "Fault-injection capability for futexes" diff --git a/lib/Makefile b/lib/Makefile index 6d765d5fb8ac..5efd1b435a37 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -148,6 +148,8 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o lib-y += logic_pio.o +lib-$(CONFIG_INDIRECT_IOMEM) += logic_iomem.o + obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_BTREE) += btree.o diff --git a/lib/asn1_encoder.c b/lib/asn1_encoder.c index 41e71aae3ef6..27bbe891714f 100644 --- a/lib/asn1_encoder.c +++ b/lib/asn1_encoder.c @@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(asn1_encode_oid); /** * asn1_encode_length() - encode a length to follow an ASN.1 tag * @data: pointer to encode at - * @data_len: pointer to remaning length (adjusted by routine) + * @data_len: pointer to remaining length (adjusted by routine) * @len: length to encode * * This routine can encode lengths up to 65535 using the ASN.1 rules. diff --git a/lib/buildid.c b/lib/buildid.c index 6156997c3895..dfc62625cae4 100644 --- a/lib/buildid.c +++ b/lib/buildid.c @@ -1,36 +1,31 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include +#include #include #define BUILD_ID 3 + /* * Parse build id from the note segment. This logic can be shared between * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are * identical. */ -static inline int parse_build_id(void *page_addr, - unsigned char *build_id, - __u32 *size, - void *note_start, - Elf32_Word note_size) +static int parse_build_id_buf(unsigned char *build_id, + __u32 *size, + const void *note_start, + Elf32_Word note_size) { Elf32_Word note_offs = 0, new_offs; - /* check for overflow */ - if (note_start < page_addr || note_start + note_size < note_start) - return -EINVAL; - - /* only supports note that fits in the first page */ - if (note_start + note_size > page_addr + PAGE_SIZE) - return -EINVAL; - while (note_offs + sizeof(Elf32_Nhdr) < note_size) { Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs); if (nhdr->n_type == BUILD_ID && nhdr->n_namesz == sizeof("GNU") && + !strcmp((char *)(nhdr + 1), "GNU") && nhdr->n_descsz > 0 && nhdr->n_descsz <= BUILD_ID_SIZE_MAX) { memcpy(build_id, @@ -49,11 +44,29 @@ static inline int parse_build_id(void *page_addr, break; note_offs = new_offs; } + return -EINVAL; } +static inline int parse_build_id(const void *page_addr, + unsigned char *build_id, + __u32 *size, + const void *note_start, + Elf32_Word note_size) +{ + /* check for overflow */ + if (note_start < page_addr || note_start + note_size < note_start) + return -EINVAL; + + /* only supports note that fits in the first page */ + if (note_start + note_size > page_addr + PAGE_SIZE) + return -EINVAL; + + return parse_build_id_buf(build_id, size, note_start, note_size); +} + /* Parse build ID from 32-bit ELF */ -static int get_build_id_32(void *page_addr, unsigned char *build_id, +static int get_build_id_32(const void *page_addr, unsigned char *build_id, __u32 *size) { Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr; @@ -78,7 +91,7 @@ static int get_build_id_32(void *page_addr, unsigned char *build_id, } /* Parse build ID from 64-bit ELF */ -static int get_build_id_64(void *page_addr, unsigned char *build_id, +static int get_build_id_64(const void *page_addr, unsigned char *build_id, __u32 *size) { Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr; @@ -108,7 +121,7 @@ static int get_build_id_64(void *page_addr, unsigned char *build_id, * @build_id: buffer to store build id, at least BUILD_ID_SIZE long * @size: returns actual build id size in case of success * - * Returns 0 on success, otherwise error (< 0). + * Return: 0 on success, -EINVAL otherwise */ int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size) @@ -147,3 +160,32 @@ out: put_page(page); return ret; } + +/** + * build_id_parse_buf - Get build ID from a buffer + * @buf: Elf note section(s) to parse + * @buf_size: Size of @buf in bytes + * @build_id: Build ID parsed from @buf, at least BUILD_ID_SIZE_MAX long + * + * Return: 0 on success, -EINVAL otherwise + */ +int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size) +{ + return parse_build_id_buf(build_id, NULL, buf, buf_size); +} + +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) || IS_ENABLED(CONFIG_CRASH_CORE) +unsigned char vmlinux_build_id[BUILD_ID_SIZE_MAX] __ro_after_init; + +/** + * init_vmlinux_build_id - Compute and stash the running kernel's build ID + */ +void __init init_vmlinux_build_id(void) +{ + extern const void __start_notes __weak; + extern const void __stop_notes __weak; + unsigned int size = &__stop_notes - &__start_notes; + + build_id_parse_buf(&__start_notes, vmlinux_build_id, size); +} +#endif diff --git a/lib/devres.c b/lib/devres.c index bdb06898a977..b0e1c6702c71 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -355,7 +355,7 @@ static void pcim_iomap_release(struct device *gendev, void *res) * detach. * * This function might sleep when the table is first allocated but can - * be safely called without context and guaranteed to succed once + * be safely called without context and guaranteed to succeed once * allocated. */ void __iomem * const *pcim_iomap_table(struct pci_dev *pdev) diff --git a/lib/dump_stack.c b/lib/dump_stack.c index 27f16872320d..cd3387bb34e5 100644 --- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -36,6 +37,14 @@ void __init dump_stack_set_arch_desc(const char *fmt, ...) va_end(args); } +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +#define BUILD_ID_FMT " %20phN" +#define BUILD_ID_VAL vmlinux_build_id +#else +#define BUILD_ID_FMT "%s" +#define BUILD_ID_VAL "" +#endif + /** * dump_stack_print_info - print generic debug info for dump_stack() * @log_lvl: log level @@ -45,13 +54,13 @@ void __init dump_stack_set_arch_desc(const char *fmt, ...) */ void dump_stack_print_info(const char *log_lvl) { - printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s\n", + printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s" BUILD_ID_FMT "\n", log_lvl, raw_smp_processor_id(), current->pid, current->comm, kexec_crash_loaded() ? "Kdump: loaded " : "", print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); + init_utsname()->version, BUILD_ID_VAL); if (dump_stack_arch_desc_str[0] != '\0') printk("%sHardware name: %s\n", diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index d3ce78298832..cb5abb42c16a 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -991,7 +991,7 @@ static int ddebug_dyndbg_param_cb(char *param, char *val, ddebug_exec_queries((val ? val : "+p"), modname); - return 0; /* query failure shouldnt stop module load */ + return 0; /* query failure shouldn't stop module load */ } /* handle both dyndbg and $module.dyndbg params at boot */ diff --git a/lib/fonts/font_pearl_8x8.c b/lib/fonts/font_pearl_8x8.c index b1678ed0017c..ae98ca17982e 100644 --- a/lib/fonts/font_pearl_8x8.c +++ b/lib/fonts/font_pearl_8x8.c @@ -3,7 +3,7 @@ /* */ /* Font file generated by cpi2fnt */ /* ------------------------------ */ -/* Combined with the alpha-numeric */ +/* Combined with the alphanumeric */ /* portion of Greg Harp's old PEARL */ /* font (from earlier versions of */ /* linux-m86k) by John Shifflett */ diff --git a/lib/kfifo.c b/lib/kfifo.c index 70dab9ac7827..12f5a347aa13 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -415,7 +415,7 @@ static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize) ) /* - * __kfifo_poke_n internal helper function for storeing the length of + * __kfifo_poke_n internal helper function for storing the length of * the record into the fifo */ static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize) diff --git a/lib/list_sort.c b/lib/list_sort.c index 1e1e37762799..0fb59e92ca2d 100644 --- a/lib/list_sort.c +++ b/lib/list_sort.c @@ -104,7 +104,7 @@ static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head, * @head: the list to sort * @cmp: the elements comparison function * - * The comparison funtion @cmp must return > 0 if @a should sort after + * The comparison function @cmp must return > 0 if @a should sort after * @b ("@a > @b" if you want an ascending sort), and <= 0 if @a should * sort before @b *or* their original order should be preserved. It is * always called with the element that came first in the input in @a, diff --git a/lib/logic_iomem.c b/lib/logic_iomem.c new file mode 100644 index 000000000000..b76b92dd0f1f --- /dev/null +++ b/lib/logic_iomem.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Intel Corporation + * Author: Johannes Berg + */ +#include +#include +#include + +struct logic_iomem_region { + const struct resource *res; + const struct logic_iomem_region_ops *ops; + struct list_head list; +}; + +struct logic_iomem_area { + const struct logic_iomem_ops *ops; + void *priv; +}; + +#define AREA_SHIFT 24 +#define MAX_AREA_SIZE (1 << AREA_SHIFT) +#define MAX_AREAS ((1ULL<<32) / MAX_AREA_SIZE) +#define AREA_BITS ((MAX_AREAS - 1) << AREA_SHIFT) +#define AREA_MASK (MAX_AREA_SIZE - 1) +#ifdef CONFIG_64BIT +#define IOREMAP_BIAS 0xDEAD000000000000UL +#define IOREMAP_MASK 0xFFFFFFFF00000000UL +#else +#define IOREMAP_BIAS 0 +#define IOREMAP_MASK 0 +#endif + +static DEFINE_MUTEX(regions_mtx); +static LIST_HEAD(regions_list); +static struct logic_iomem_area mapped_areas[MAX_AREAS]; + +int logic_iomem_add_region(struct resource *resource, + const struct logic_iomem_region_ops *ops) +{ + struct logic_iomem_region *rreg; + int err; + + if (WARN_ON(!resource || !ops)) + return -EINVAL; + + if (WARN_ON((resource->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM)) + return -EINVAL; + + rreg = kzalloc(sizeof(*rreg), GFP_KERNEL); + if (!rreg) + return -ENOMEM; + + err = request_resource(&iomem_resource, resource); + if (err) { + kfree(rreg); + return -ENOMEM; + } + + mutex_lock(®ions_mtx); + rreg->res = resource; + rreg->ops = ops; + list_add_tail(&rreg->list, ®ions_list); + mutex_unlock(®ions_mtx); + + return 0; +} +EXPORT_SYMBOL(logic_iomem_add_region); + +#ifndef CONFIG_LOGIC_IOMEM_FALLBACK +static void __iomem *real_ioremap(phys_addr_t offset, size_t size) +{ + WARN(1, "invalid ioremap(0x%llx, 0x%zx)\n", + (unsigned long long)offset, size); + return NULL; +} + +static void real_iounmap(void __iomem *addr) +{ + WARN(1, "invalid iounmap for addr 0x%llx\n", + (unsigned long long)addr); +} +#endif /* CONFIG_LOGIC_IOMEM_FALLBACK */ + +void __iomem *ioremap(phys_addr_t offset, size_t size) +{ + void __iomem *ret = NULL; + struct logic_iomem_region *rreg, *found = NULL; + int i; + + mutex_lock(®ions_mtx); + list_for_each_entry(rreg, ®ions_list, list) { + if (rreg->res->start > offset) + continue; + if (rreg->res->end < offset + size - 1) + continue; + found = rreg; + break; + } + + if (!found) + goto out; + + for (i = 0; i < MAX_AREAS; i++) { + long offs; + + if (mapped_areas[i].ops) + continue; + + offs = rreg->ops->map(offset - found->res->start, + size, &mapped_areas[i].ops, + &mapped_areas[i].priv); + if (offs < 0) { + mapped_areas[i].ops = NULL; + break; + } + + if (WARN_ON(!mapped_areas[i].ops)) { + mapped_areas[i].ops = NULL; + break; + } + + ret = (void __iomem *)(IOREMAP_BIAS + (i << AREA_SHIFT) + offs); + break; + } +out: + mutex_unlock(®ions_mtx); + if (ret) + return ret; + return real_ioremap(offset, size); +} +EXPORT_SYMBOL(ioremap); + +static inline struct logic_iomem_area * +get_area(const volatile void __iomem *addr) +{ + unsigned long a = (unsigned long)addr; + unsigned int idx; + + if (WARN_ON((a & IOREMAP_MASK) != IOREMAP_BIAS)) + return NULL; + + idx = (a & AREA_BITS) >> AREA_SHIFT; + + if (mapped_areas[idx].ops) + return &mapped_areas[idx]; + + return NULL; +} + +void iounmap(void __iomem *addr) +{ + struct logic_iomem_area *area = get_area(addr); + + if (!area) { + real_iounmap(addr); + return; + } + + if (area->ops->unmap) + area->ops->unmap(area->priv); + + mutex_lock(®ions_mtx); + area->ops = NULL; + area->priv = NULL; + mutex_unlock(®ions_mtx); +} +EXPORT_SYMBOL(iounmap); + +#ifndef CONFIG_LOGIC_IOMEM_FALLBACK +#define MAKE_FALLBACK(op, sz) \ +static u##sz real_raw_read ## op(const volatile void __iomem *addr) \ +{ \ + WARN(1, "Invalid read" #op " at address %llx\n", \ + (unsigned long long)addr); \ + return (u ## sz)~0ULL; \ +} \ + \ +void real_raw_write ## op(u ## sz val, volatile void __iomem *addr) \ +{ \ + WARN(1, "Invalid writeq" #op " of 0x%llx at address %llx\n", \ + (unsigned long long)val, (unsigned long long)addr); \ +} \ + +MAKE_FALLBACK(b, 8); +MAKE_FALLBACK(w, 16); +MAKE_FALLBACK(l, 32); +#ifdef CONFIG_64BIT +MAKE_FALLBACK(q, 64); +#endif + +static void real_memset_io(volatile void __iomem *addr, int value, size_t size) +{ + WARN(1, "Invalid memset_io at address 0x%llx\n", + (unsigned long long)addr); +} + +static void real_memcpy_fromio(void *buffer, const volatile void __iomem *addr, + size_t size) +{ + WARN(1, "Invalid memcpy_fromio at address 0x%llx\n", + (unsigned long long)addr); + + memset(buffer, 0xff, size); +} + +static void real_memcpy_toio(volatile void __iomem *addr, const void *buffer, + size_t size) +{ + WARN(1, "Invalid memcpy_toio at address 0x%llx\n", + (unsigned long long)addr); +} +#endif /* CONFIG_LOGIC_IOMEM_FALLBACK */ + +#define MAKE_OP(op, sz) \ +u##sz __raw_read ## op(const volatile void __iomem *addr) \ +{ \ + struct logic_iomem_area *area = get_area(addr); \ + \ + if (!area) \ + return real_raw_read ## op(addr); \ + \ + return (u ## sz) area->ops->read(area->priv, \ + (unsigned long)addr & AREA_MASK,\ + sz / 8); \ +} \ +EXPORT_SYMBOL(__raw_read ## op); \ + \ +void __raw_write ## op(u ## sz val, volatile void __iomem *addr) \ +{ \ + struct logic_iomem_area *area = get_area(addr); \ + \ + if (!area) { \ + real_raw_write ## op(val, addr); \ + return; \ + } \ + \ + area->ops->write(area->priv, \ + (unsigned long)addr & AREA_MASK, \ + sz / 8, val); \ +} \ +EXPORT_SYMBOL(__raw_write ## op) + +MAKE_OP(b, 8); +MAKE_OP(w, 16); +MAKE_OP(l, 32); +#ifdef CONFIG_64BIT +MAKE_OP(q, 64); +#endif + +void memset_io(volatile void __iomem *addr, int value, size_t size) +{ + struct logic_iomem_area *area = get_area(addr); + unsigned long offs, start; + + if (!area) { + real_memset_io(addr, value, size); + return; + } + + start = (unsigned long)addr & AREA_MASK; + + if (area->ops->set) { + area->ops->set(area->priv, start, value, size); + return; + } + + for (offs = 0; offs < size; offs++) + area->ops->write(area->priv, start + offs, 1, value); +} +EXPORT_SYMBOL(memset_io); + +void memcpy_fromio(void *buffer, const volatile void __iomem *addr, + size_t size) +{ + struct logic_iomem_area *area = get_area(addr); + u8 *buf = buffer; + unsigned long offs, start; + + if (!area) { + real_memcpy_fromio(buffer, addr, size); + return; + } + + start = (unsigned long)addr & AREA_MASK; + + if (area->ops->copy_from) { + area->ops->copy_from(area->priv, buffer, start, size); + return; + } + + for (offs = 0; offs < size; offs++) + buf[offs] = area->ops->read(area->priv, start + offs, 1); +} +EXPORT_SYMBOL(memcpy_fromio); + +void memcpy_toio(volatile void __iomem *addr, const void *buffer, size_t size) +{ + struct logic_iomem_area *area = get_area(addr); + const u8 *buf = buffer; + unsigned long offs, start; + + if (!area) { + real_memcpy_toio(addr, buffer, size); + return; + } + + start = (unsigned long)addr & AREA_MASK; + + if (area->ops->copy_to) { + area->ops->copy_to(area->priv, start, buffer, size); + return; + } + + for (offs = 0; offs < size; offs++) + area->ops->write(area->priv, start + offs, 1, buf[offs]); +} +EXPORT_SYMBOL(memcpy_toio); diff --git a/lib/nlattr.c b/lib/nlattr.c index 1d051ef66afe..86029ad5ead4 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -619,7 +619,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, * Validates all attributes in the specified attribute stream against the * specified policy. Validation depends on the validate flags passed, see * &enum netlink_validation for more details on that. - * See documenation of struct nla_policy for more details. + * See documentation of struct nla_policy for more details. * * Returns 0 on success or a negative error code. */ @@ -633,7 +633,7 @@ int __nla_validate(const struct nlattr *head, int len, int maxtype, EXPORT_SYMBOL(__nla_validate); /** - * nla_policy_len - Determin the max. length of a policy + * nla_policy_len - Determine the max. length of a policy * @policy: policy to use * @n: number of policies * diff --git a/lib/oid_registry.c b/lib/oid_registry.c index 3dfaa836e7c5..e592d48b1974 100644 --- a/lib/oid_registry.c +++ b/lib/oid_registry.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(parse_OID); * @bufsize: The size of the buffer * * The OID is rendered into the buffer in "a.b.c.d" format and the number of - * bytes is returned. -EBADMSG is returned if the data could not be intepreted + * bytes is returned. -EBADMSG is returned if the data could not be interpreted * and -ENOBUFS if the buffer was too small. */ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize) diff --git a/lib/pldmfw/pldmfw.c b/lib/pldmfw/pldmfw.c index e5d4b3b2af81..6e77eb6d8e72 100644 --- a/lib/pldmfw/pldmfw.c +++ b/lib/pldmfw/pldmfw.c @@ -82,7 +82,7 @@ pldm_check_fw_space(struct pldmfw_priv *data, size_t offset, size_t length) * @bytes_to_move: number of bytes to move the offset forward by * * Check that there is enough space past the current offset, and then move the - * offset forward by this ammount. + * offset forward by this amount. * * Returns: zero on success, or -EFAULT if the image is too small to fit the * expected length. diff --git a/lib/reed_solomon/test_rslib.c b/lib/reed_solomon/test_rslib.c index 4eb29f365ece..d9d1c33aebda 100644 --- a/lib/reed_solomon/test_rslib.c +++ b/lib/reed_solomon/test_rslib.c @@ -385,7 +385,7 @@ static void test_bc(struct rs_control *rs, int len, int errs, /* * We check that the returned word is actually a - * codeword. The obious way to do this would be to + * codeword. The obvious way to do this would be to * compute the syndrome, but we don't want to replicate * that code here. However, all the codes are in * systematic form, and therefore we can encode the diff --git a/lib/refcount.c b/lib/refcount.c index ebac8b7d15a7..a207a8f22b3c 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -164,7 +164,7 @@ EXPORT_SYMBOL(refcount_dec_and_lock); * @flags: saved IRQ-flags if the is acquired * * Same as refcount_dec_and_lock() above except that the spinlock is acquired - * with disabled interupts. + * with disabled interrupts. * * Return: true and hold spinlock if able to decrement refcount to 0, false * otherwise diff --git a/lib/rhashtable.c b/lib/rhashtable.c index c949c1e3b87c..e12bbfb240b8 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -703,7 +703,7 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_exit); * * Returns zero if successful. * - * Returns -EAGAIN if resize event occured. Note that the iterator + * Returns -EAGAIN if resize event occurred. Note that the iterator * will rewind back to the beginning and you may use it immediately * by calling rhashtable_walk_next. * diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 47b3691058eb..b25db9be938a 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -583,7 +583,7 @@ void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr, /* * Once the clear bit is set, the bit may be allocated out. * - * Orders READ/WRITE on the asssociated instance(such as request + * Orders READ/WRITE on the associated instance(such as request * of blk_mq) by this bit for avoiding race with re-allocation, * and its pair is the memory barrier implied in __sbitmap_get_word. * diff --git a/lib/scatterlist.c b/lib/scatterlist.c index a59778946404..27efa6178153 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -38,7 +38,7 @@ EXPORT_SYMBOL(sg_next); * @sg: The scatterlist * * Description: - * Allows to know how many entries are in sg, taking into acount + * Allows to know how many entries are in sg, taking into account * chaining as well * **/ @@ -59,7 +59,7 @@ EXPORT_SYMBOL(sg_nents); * * Description: * Determines the number of entries in sg that are required to meet - * the supplied length, taking into acount chaining as well + * the supplied length, taking into account chaining as well * * Returns: * the number of sg entries needed, negative error on failure diff --git a/lib/seq_buf.c b/lib/seq_buf.c index 6dafde851333..0a68f7aa85d6 100644 --- a/lib/seq_buf.c +++ b/lib/seq_buf.c @@ -289,7 +289,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) } /** - * seq_buf_to_user - copy the squence buffer to user space + * seq_buf_to_user - copy the sequence buffer to user space * @s: seq_buf descriptor * @ubuf: The userspace memory location to copy to * @cnt: The amount to copy diff --git a/lib/sort.c b/lib/sort.c index 3ad454411997..aa18153864d2 100644 --- a/lib/sort.c +++ b/lib/sort.c @@ -51,7 +51,7 @@ static bool is_aligned(const void *base, size_t size, unsigned char align) * which basically all CPUs have, to minimize loop overhead computations. * * For some reason, on x86 gcc 7.3.0 adds a redundant test of n at the - * bottom of the loop, even though the zero flag is stil valid from the + * bottom of the loop, even though the zero flag is still valid from the * subtract (since the intervening mov instructions don't alter the flags). * Gcc 8.1.0 doesn't have that problem. */ diff --git a/lib/stackdepot.c b/lib/stackdepot.c index df9179f4f441..0a2e417f83cb 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -11,7 +11,7 @@ * Instead, stack depot maintains a hashtable of unique stacktraces. Since alloc * and free stacks repeat a lot, we save about 100x space. * Stacks are never removed from depot, so we store them contiguously one after - * another in a contiguos memory allocation. + * another in a contiguous memory allocation. * * Author: Alexander Potapenko * Copyright (C) 2016 Google, Inc. diff --git a/lib/test_bitops.c b/lib/test_bitops.c index 471141ddd691..3b7bcbee84db 100644 --- a/lib/test_bitops.c +++ b/lib/test_bitops.c @@ -15,7 +15,7 @@ * get_count_order/long */ -/* use an enum because thats the most common BITMAP usage */ +/* use an enum because that's the most common BITMAP usage */ enum bitops_fun { BITOPS_4 = 4, BITOPS_7 = 7, diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 4dc4dcbecd12..d500320778c7 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -1095,7 +1095,7 @@ static struct bpf_test tests[] = { { "RET_A", .u.insns = { - /* check that unitialized X and A contain zeros */ + /* check that uninitialized X and A contain zeros */ BPF_STMT(BPF_MISC | BPF_TXA, 0), BPF_STMT(BPF_RET | BPF_A, 0) }, diff --git a/lib/test_kasan.c b/lib/test_kasan.c index f5f54766cbc2..8f7b0b2f6e11 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -651,7 +651,7 @@ static void kasan_global_oob(struct kunit *test) { /* * Deliberate out-of-bounds access. To prevent CONFIG_UBSAN_LOCAL_BOUNDS - * from failing here and panicing the kernel, access the array via a + * from failing here and panicking the kernel, access the array via a * volatile pointer, which will prevent the compiler from being able to * determine the array bounds. * diff --git a/lib/test_kmod.c b/lib/test_kmod.c index 38c250fbace3..ce1589391413 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -286,7 +286,7 @@ static int tally_work_test(struct kmod_test_device_info *info) * If this ran it means *all* tasks were created fine and we * are now just collecting results. * - * Only propagate errors, do not override with a subsequent sucess case. + * Only propagate errors, do not override with a subsequent success case. */ static void tally_up_work(struct kmod_test_device *test_dev) { @@ -543,7 +543,7 @@ static int trigger_config_run(struct kmod_test_device *test_dev) * wrong with the setup of the test. If the test setup went fine * then userspace must just check the result of config->test_result. * One issue with relying on the return from a call in the kernel - * is if the kernel returns a possitive value using this trigger + * is if the kernel returns a positive value using this trigger * will not return the value to userspace, it would be lost. * * By not relying on capturing the return value of tests we are using @@ -585,7 +585,7 @@ trigger_config_store(struct device *dev, * Note: any return > 0 will be treated as success * and the error value will not be available to userspace. * Do not rely on trying to send to userspace a test value - * return value as possitive return errors will be lost. + * return value as positive return errors will be lost. */ if (WARN_ON(ret > 0)) return -EINVAL; diff --git a/lib/test_scanf.c b/lib/test_scanf.c index 48ff5747a4da..84fe09eaf55e 100644 --- a/lib/test_scanf.c +++ b/lib/test_scanf.c @@ -600,7 +600,7 @@ static void __init numbers_prefix_overflow(void) /* * 0x prefix in a field of width 2 using %i conversion: first field * converts to 0. Next field scan starts at the character after "0x", - * which will convert if can be intepreted as decimal but will fail + * which will convert if can be interpreted as decimal but will fail * if it contains any hex digits (since no 0x prefix). */ test_number_prefix(long long, "0x67", "%2lli%lli", 0, 67, 2, check_ll); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 2926cc27623f..26c83943748a 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -993,8 +993,12 @@ char *symbol_string(char *buf, char *end, void *ptr, value = (unsigned long)ptr; #ifdef CONFIG_KALLSYMS - if (*fmt == 'B') + if (*fmt == 'B' && fmt[1] == 'b') + sprint_backtrace_build_id(sym, value); + else if (*fmt == 'B') sprint_backtrace(sym, value); + else if (*fmt == 'S' && (fmt[1] == 'b' || (fmt[1] == 'R' && fmt[2] == 'b'))) + sprint_symbol_build_id(sym, value); else if (*fmt != 's') sprint_symbol(sym, value); else @@ -2263,9 +2267,11 @@ early_param("no_hash_pointers", no_hash_pointers_enable); * - 'S' For symbolic direct pointers (or function descriptors) with offset * - 's' For symbolic direct pointers (or function descriptors) without offset * - '[Ss]R' as above with __builtin_extract_return_addr() translation + * - 'S[R]b' as above with module build ID (for use in backtraces) * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of * %ps and %pS. Be careful when re-using these specifiers. * - 'B' For backtraced symbolic direct pointers with offset + * - 'Bb' as above with module build ID (for use in backtraces) * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] * - 'b[l]' For a bitmap, the number of bits is determined by the field @@ -3417,7 +3423,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args) while (*fmt) { /* skip any white space in format */ - /* white space in format matchs any amount of + /* white space in format matches any amount of * white space, including none, in the input. */ if (isspace(*fmt)) { diff --git a/mm/Kconfig b/mm/Kconfig index a02498c0e13d..40a9bfcd5062 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -885,4 +885,8 @@ config KMAP_LOCAL # struct io_mapping based helper. Selected by drivers that need them config IO_MAPPING bool + +config SECRETMEM + def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED + endmenu diff --git a/mm/Makefile b/mm/Makefile index 74b47c354682..e3436741d539 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_CMA) += cma.o obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o +obj-$(CONFIG_SECRETMEM) += secretmem.o obj-$(CONFIG_CMA_SYSFS) += cma_sysfs.o obj-$(CONFIG_USERFAULTFD) += userfaultfd.o obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o diff --git a/mm/gup.c b/mm/gup.c index 728d996767cb..42b8b1fa6521 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -855,6 +856,9 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, struct follow_page_context ctx = { NULL }; struct page *page; + if (vma_is_secretmem(vma)) + return NULL; + page = follow_page_mask(vma, address, foll_flags, &ctx); if (ctx.pgmap) put_dev_pagemap(ctx.pgmap); @@ -988,6 +992,9 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) if ((gup_flags & FOLL_LONGTERM) && vma_is_fsdax(vma)) return -EOPNOTSUPP; + if (vma_is_secretmem(vma)) + return -EFAULT; + if (write) { if (!(vm_flags & VM_WRITE)) { if (!(gup_flags & FOLL_FORCE)) @@ -2170,6 +2177,11 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, if (!head) goto pte_unmap; + if (unlikely(page_is_secretmem(page))) { + put_compound_head(head, 1, flags); + goto pte_unmap; + } + if (unlikely(pte_val(pte) != pte_val(*ptep))) { put_compound_head(head, 1, flags); goto pte_unmap; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 8b731d53e9f4..afff3ac87067 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2331,7 +2331,7 @@ static void remap_page(struct page *page, unsigned int nr) { int i; - /* If TTU_SPLIT_FREEZE is ever extended to file, remove this check */ + /* If unmap_page() uses try_to_migrate() on file, remove this check */ if (!PageAnon(page)) return; if (PageTransHuge(page)) { diff --git a/mm/init-mm.c b/mm/init-mm.c index 153162669f80..b4a6f38fb51d 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -40,3 +40,12 @@ struct mm_struct init_mm = { .cpu_bitmap = CPU_BITS_NONE, INIT_MM_CONTEXT(init_mm) }; + +void setup_initial_init_mm(void *start_code, void *end_code, + void *end_data, void *brk) +{ + init_mm.start_code = (unsigned long)start_code; + init_mm.end_code = (unsigned long)end_code; + init_mm.end_data = (unsigned long)end_data; + init_mm.brk = (unsigned long)brk; +} diff --git a/mm/internal.h b/mm/internal.h index 2d7c9a2e0118..31ff935b2547 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -360,6 +360,9 @@ static inline void munlock_vma_pages_all(struct vm_area_struct *vma) extern void mlock_vma_page(struct page *page); extern unsigned int munlock_vma_page(struct page *page); +extern int mlock_future_check(struct mm_struct *mm, unsigned long flags, + unsigned long len); + /* * Clear the page's PageMlocked(). This can be useful in a situation where * we want to unconditionally remove a page from the pagecache -- e.g., diff --git a/mm/mlock.c b/mm/mlock.c index 6e824cb306b1..29a3efb44d11 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "internal.h" @@ -503,7 +504,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) || is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm) || - vma_is_dax(vma)) + vma_is_dax(vma) || vma_is_secretmem(vma)) /* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */ goto out; diff --git a/mm/mmap.c b/mm/mmap.c index 00d9e4b653be..cfd7149b9f8c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1361,9 +1361,8 @@ static inline unsigned long round_hint_to_min(unsigned long hint) return hint; } -static inline int mlock_future_check(struct mm_struct *mm, - unsigned long flags, - unsigned long len) +int mlock_future_check(struct mm_struct *mm, unsigned long flags, + unsigned long len) { unsigned long locked, lock_limit; diff --git a/mm/mremap.c b/mm/mremap.c index a369a6100698..5989d3990020 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -25,7 +25,8 @@ #include #include -#include +#include +#include #include "internal.h" @@ -209,6 +210,15 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, drop_rmap_locks(vma); } +#ifndef arch_supports_page_table_move +#define arch_supports_page_table_move arch_supports_page_table_move +static inline bool arch_supports_page_table_move(void) +{ + return IS_ENABLED(CONFIG_HAVE_MOVE_PMD) || + IS_ENABLED(CONFIG_HAVE_MOVE_PUD); +} +#endif + #ifdef CONFIG_HAVE_MOVE_PMD static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, unsigned long new_addr, pmd_t *old_pmd, pmd_t *new_pmd) @@ -217,6 +227,8 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, struct mm_struct *mm = vma->vm_mm; pmd_t pmd; + if (!arch_supports_page_table_move()) + return false; /* * The destination pmd shouldn't be established, free_pgtables() * should have released it. @@ -258,8 +270,7 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr, VM_BUG_ON(!pmd_none(*new_pmd)); - /* Set the new pmd */ - set_pmd_at(mm, new_addr, new_pmd, pmd); + pmd_populate(mm, new_pmd, pmd_pgtable(pmd)); flush_tlb_range(vma, old_addr, old_addr + PMD_SIZE); if (new_ptl != old_ptl) spin_unlock(new_ptl); @@ -276,7 +287,7 @@ static inline bool move_normal_pmd(struct vm_area_struct *vma, } #endif -#ifdef CONFIG_HAVE_MOVE_PUD +#if CONFIG_PGTABLE_LEVELS > 2 && defined(CONFIG_HAVE_MOVE_PUD) static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr, unsigned long new_addr, pud_t *old_pud, pud_t *new_pud) { @@ -284,6 +295,55 @@ static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr, struct mm_struct *mm = vma->vm_mm; pud_t pud; + if (!arch_supports_page_table_move()) + return false; + /* + * The destination pud shouldn't be established, free_pgtables() + * should have released it. + */ + if (WARN_ON_ONCE(!pud_none(*new_pud))) + return false; + + /* + * We don't have to worry about the ordering of src and dst + * ptlocks because exclusive mmap_lock prevents deadlock. + */ + old_ptl = pud_lock(vma->vm_mm, old_pud); + new_ptl = pud_lockptr(mm, new_pud); + if (new_ptl != old_ptl) + spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING); + + /* Clear the pud */ + pud = *old_pud; + pud_clear(old_pud); + + VM_BUG_ON(!pud_none(*new_pud)); + + pud_populate(mm, new_pud, pud_pgtable(pud)); + flush_tlb_range(vma, old_addr, old_addr + PUD_SIZE); + if (new_ptl != old_ptl) + spin_unlock(new_ptl); + spin_unlock(old_ptl); + + return true; +} +#else +static inline bool move_normal_pud(struct vm_area_struct *vma, + unsigned long old_addr, unsigned long new_addr, pud_t *old_pud, + pud_t *new_pud) +{ + return false; +} +#endif + +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD +static bool move_huge_pud(struct vm_area_struct *vma, unsigned long old_addr, + unsigned long new_addr, pud_t *old_pud, pud_t *new_pud) +{ + spinlock_t *old_ptl, *new_ptl; + struct mm_struct *mm = vma->vm_mm; + pud_t pud; + /* * The destination pud shouldn't be established, free_pgtables() * should have released it. @@ -307,8 +367,9 @@ static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr, VM_BUG_ON(!pud_none(*new_pud)); /* Set the new pud */ + /* mark soft_ditry when we add pud level soft dirty support */ set_pud_at(mm, new_addr, new_pud, pud); - flush_tlb_range(vma, old_addr, old_addr + PUD_SIZE); + flush_pud_tlb_range(vma, old_addr, old_addr + HPAGE_PUD_SIZE); if (new_ptl != old_ptl) spin_unlock(new_ptl); spin_unlock(old_ptl); @@ -316,11 +377,12 @@ static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr, return true; } #else -static inline bool move_normal_pud(struct vm_area_struct *vma, - unsigned long old_addr, unsigned long new_addr, pud_t *old_pud, - pud_t *new_pud) +static bool move_huge_pud(struct vm_area_struct *vma, unsigned long old_addr, + unsigned long new_addr, pud_t *old_pud, pud_t *new_pud) { + WARN_ON_ONCE(1); return false; + } #endif @@ -328,6 +390,7 @@ enum pgt_entry { NORMAL_PMD, HPAGE_PMD, NORMAL_PUD, + HPAGE_PUD, }; /* @@ -347,6 +410,7 @@ static __always_inline unsigned long get_extent(enum pgt_entry entry, mask = PMD_MASK; size = PMD_SIZE; break; + case HPAGE_PUD: case NORMAL_PUD: mask = PUD_MASK; size = PUD_SIZE; @@ -395,6 +459,12 @@ static bool move_pgt_entry(enum pgt_entry entry, struct vm_area_struct *vma, move_huge_pmd(vma, old_addr, new_addr, old_entry, new_entry); break; + case HPAGE_PUD: + moved = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && + move_huge_pud(vma, old_addr, new_addr, old_entry, + new_entry); + break; + default: WARN_ON_ONCE(1); break; @@ -414,6 +484,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma, unsigned long extent, old_end; struct mmu_notifier_range range; pmd_t *old_pmd, *new_pmd; + pud_t *old_pud, *new_pud; old_end = old_addr + len; flush_cache_range(vma, old_addr, old_end); @@ -429,17 +500,24 @@ unsigned long move_page_tables(struct vm_area_struct *vma, * PUD level if possible. */ extent = get_extent(NORMAL_PUD, old_addr, old_end, new_addr); - if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) { - pud_t *old_pud, *new_pud; - old_pud = get_old_pud(vma->vm_mm, old_addr); - if (!old_pud) + old_pud = get_old_pud(vma->vm_mm, old_addr); + if (!old_pud) + continue; + new_pud = alloc_new_pud(vma->vm_mm, vma, new_addr); + if (!new_pud) + break; + if (pud_trans_huge(*old_pud) || pud_devmap(*old_pud)) { + if (extent == HPAGE_PUD_SIZE) { + move_pgt_entry(HPAGE_PUD, vma, old_addr, new_addr, + old_pud, new_pud, need_rmap_locks); + /* We ignore and continue on error? */ continue; - new_pud = alloc_new_pud(vma->vm_mm, vma, new_addr); - if (!new_pud) - break; + } + } else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) { + if (move_pgt_entry(NORMAL_PUD, vma, old_addr, new_addr, - old_pud, new_pud, need_rmap_locks)) + old_pud, new_pud, true)) continue; } @@ -466,7 +544,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma, * moving at the PMD level if possible. */ if (move_pgt_entry(NORMAL_PMD, vma, old_addr, new_addr, - old_pmd, new_pmd, need_rmap_locks)) + old_pmd, new_pmd, true)) continue; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5cff9a1fc043..cdca41179505 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -124,17 +124,6 @@ static DEFINE_MUTEX(pcp_batch_high_lock); struct pagesets { local_lock_t lock; -#if defined(CONFIG_DEBUG_INFO_BTF) && \ - !defined(CONFIG_DEBUG_LOCK_ALLOC) && \ - !defined(CONFIG_PAHOLE_HAS_ZEROSIZE_PERCPU_SUPPORT) - /* - * pahole 1.21 and earlier gets confused by zero-sized per-CPU - * variables and produces invalid BTF. Ensure that - * sizeof(struct pagesets) != 0 for older versions of pahole. - */ - char __pahole_hack; - #warning "pahole too old to support zero-sized struct pagesets" -#endif }; static DEFINE_PER_CPU(struct pagesets, pagesets) = { .lock = INIT_LOCAL_LOCK(lock), diff --git a/mm/percpu-km.c b/mm/percpu-km.c index c9d529dc7651..fe31aa19db81 100644 --- a/mm/percpu-km.c +++ b/mm/percpu-km.c @@ -32,6 +32,12 @@ #include +static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk, + int page_start, int page_end) +{ + /* nothing */ +} + static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int page_start, int page_end, gfp_t gfp) { diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index ee5d89fcd66f..2054c9213c43 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c @@ -303,6 +303,9 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, * For each cpu, depopulate and unmap pages [@page_start,@page_end) * from @chunk. * + * Caller is required to call pcpu_post_unmap_tlb_flush() if not returning the + * region back to vmalloc() which will lazily flush the tlb. + * * CONTEXT: * pcpu_alloc_mutex. */ @@ -324,8 +327,6 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, pcpu_unmap_pages(chunk, pages, page_start, page_end); - /* no need to flush tlb, vmalloc will handle it lazily */ - pcpu_free_pages(chunk, pages, page_start, page_end); } diff --git a/mm/percpu.c b/mm/percpu.c index c9914f9532d6..18068d6ad1bc 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1572,6 +1572,7 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk, * * pcpu_populate_chunk - populate the specified range of a chunk * pcpu_depopulate_chunk - depopulate the specified range of a chunk + * pcpu_post_unmap_tlb_flush - flush tlb for the specified range of a chunk * pcpu_create_chunk - create a new chunk * pcpu_destroy_chunk - destroy a chunk, always preceded by full depop * pcpu_addr_to_page - translate address to physical address @@ -1581,6 +1582,8 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int page_start, int page_end, gfp_t gfp); static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int page_start, int page_end); +static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk, + int page_start, int page_end); static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp); static void pcpu_destroy_chunk(struct pcpu_chunk *chunk); static struct page *pcpu_addr_to_page(void *addr); @@ -2137,11 +2140,12 @@ static void pcpu_reclaim_populated(void) { struct pcpu_chunk *chunk; struct pcpu_block_md *block; + int freed_page_start, freed_page_end; int i, end; + bool reintegrate; lockdep_assert_held(&pcpu_lock); -restart: /* * Once a chunk is isolated to the to_depopulate list, the chunk is no * longer discoverable to allocations whom may populate pages. The only @@ -2157,6 +2161,9 @@ restart: * Scan chunk's pages in the reverse order to keep populated * pages close to the beginning of the chunk. */ + freed_page_start = chunk->nr_pages; + freed_page_end = 0; + reintegrate = false; for (i = chunk->nr_pages - 1, end = -1; i >= 0; i--) { /* no more work to do */ if (chunk->nr_empty_pop_pages == 0) @@ -2164,8 +2171,8 @@ restart: /* reintegrate chunk to prevent atomic alloc failures */ if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_HIGH) { - pcpu_reintegrate_chunk(chunk); - goto restart; + reintegrate = true; + goto end_chunk; } /* @@ -2194,16 +2201,29 @@ restart: spin_lock_irq(&pcpu_lock); pcpu_chunk_depopulated(chunk, i + 1, end + 1); + freed_page_start = min(freed_page_start, i + 1); + freed_page_end = max(freed_page_end, end + 1); /* reset the range and continue */ end = -1; } - if (chunk->free_bytes == pcpu_unit_size) +end_chunk: + /* batch tlb flush per chunk to amortize cost */ + if (freed_page_start < freed_page_end) { + spin_unlock_irq(&pcpu_lock); + pcpu_post_unmap_tlb_flush(chunk, + freed_page_start, + freed_page_end); + cond_resched(); + spin_lock_irq(&pcpu_lock); + } + + if (reintegrate || chunk->free_bytes == pcpu_unit_size) pcpu_reintegrate_chunk(chunk); else - list_move(&chunk->list, - &pcpu_chunk_lists[pcpu_sidelined_slot]); + list_move_tail(&chunk->list, + &pcpu_chunk_lists[pcpu_sidelined_slot]); } } diff --git a/mm/rmap.c b/mm/rmap.c index 37c24672125c..795f9d5f8386 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1439,13 +1439,12 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma, while (page_vma_mapped_walk(&pvmw)) { /* * If the page is mlock()d, we cannot swap it out. - * If it's recently referenced (perhaps page_referenced - * skipped over this mm) then we should reactivate it. */ if (!(flags & TTU_IGNORE_MLOCK)) { if (vma->vm_flags & VM_LOCKED) { - /* PTE-mapped THP are never mlocked */ - if (!PageTransCompound(page)) { + /* PTE-mapped THP are never marked as mlocked */ + if (!PageTransCompound(page) || + (PageHead(page) && !PageDoubleMap(page))) { /* * Holding pte lock, we do *not* need * mmap_lock here @@ -1687,8 +1686,7 @@ void try_to_unmap(struct page *page, enum ttu_flags flags) * @arg: enum ttu_flags will be passed to this argument. * * If TTU_SPLIT_HUGE_PMD is specified any PMD mappings will be split into PTEs - * containing migration entries. This and TTU_RMAP_LOCKED are the only supported - * flags. + * containing migration entries. */ static bool try_to_migrate_one(struct page *page, struct vm_area_struct *vma, unsigned long address, void *arg) @@ -1705,9 +1703,6 @@ static bool try_to_migrate_one(struct page *page, struct vm_area_struct *vma, struct mmu_notifier_range range; enum ttu_flags flags = (enum ttu_flags)(long)arg; - if (is_zone_device_page(page) && !is_device_private_page(page)) - return true; - /* * When racing against e.g. zap_pte_range() on another cpu, * in between its ptep_get_and_clear_full() and page_remove_rmap(), @@ -1928,8 +1923,6 @@ static bool try_to_migrate_one(struct page *page, struct vm_area_struct *vma, * * Tries to remove all the page table entries which are mapping this page and * replace them with special swap entries. Caller must hold the page lock. - * - * If is successful, return true. Otherwise, false. */ void try_to_migrate(struct page *page, enum ttu_flags flags) { @@ -1948,6 +1941,9 @@ void try_to_migrate(struct page *page, enum ttu_flags flags) TTU_SYNC))) return; + if (is_zone_device_page(page) && !is_device_private_page(page)) + return; + /* * During exec, a temporary VMA is setup and later moved. * The VMA is moved under the anon_vma lock but not the @@ -1989,17 +1985,18 @@ static bool page_mlock_one(struct page *page, struct vm_area_struct *vma, * munlock_vma_pages_range(). */ if (vma->vm_flags & VM_LOCKED) { - /* PTE-mapped THP are never mlocked */ - if (!PageTransCompound(page)) - mlock_vma_page(page); + /* + * PTE-mapped THP are never marked as mlocked, but + * this function is never called when PageDoubleMap(). + */ + mlock_vma_page(page); + /* + * No need to scan further once the page is marked + * as mlocked. + */ page_vma_mapped_walk_done(&pvmw); + return false; } - - /* - * no need to continue scanning other vma's if the page has - * been locked. - */ - return false; } return true; diff --git a/mm/secretmem.c b/mm/secretmem.c new file mode 100644 index 000000000000..f77d25467a14 --- /dev/null +++ b/mm/secretmem.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright IBM Corporation, 2021 + * + * Author: Mike Rapoport + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "internal.h" + +#undef pr_fmt +#define pr_fmt(fmt) "secretmem: " fmt + +/* + * Define mode and flag masks to allow validation of the system call + * parameters. + */ +#define SECRETMEM_MODE_MASK (0x0) +#define SECRETMEM_FLAGS_MASK SECRETMEM_MODE_MASK + +static bool secretmem_enable __ro_after_init; +module_param_named(enable, secretmem_enable, bool, 0400); +MODULE_PARM_DESC(secretmem_enable, + "Enable secretmem and memfd_secret(2) system call"); + +static atomic_t secretmem_users; + +bool secretmem_active(void) +{ + return !!atomic_read(&secretmem_users); +} + +static vm_fault_t secretmem_fault(struct vm_fault *vmf) +{ + struct address_space *mapping = vmf->vma->vm_file->f_mapping; + struct inode *inode = file_inode(vmf->vma->vm_file); + pgoff_t offset = vmf->pgoff; + gfp_t gfp = vmf->gfp_mask; + unsigned long addr; + struct page *page; + int err; + + if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode)) + return vmf_error(-EINVAL); + +retry: + page = find_lock_page(mapping, offset); + if (!page) { + page = alloc_page(gfp | __GFP_ZERO); + if (!page) + return VM_FAULT_OOM; + + err = set_direct_map_invalid_noflush(page); + if (err) { + put_page(page); + return vmf_error(err); + } + + __SetPageUptodate(page); + err = add_to_page_cache_lru(page, mapping, offset, gfp); + if (unlikely(err)) { + put_page(page); + /* + * If a split of large page was required, it + * already happened when we marked the page invalid + * which guarantees that this call won't fail + */ + set_direct_map_default_noflush(page); + if (err == -EEXIST) + goto retry; + + return vmf_error(err); + } + + addr = (unsigned long)page_address(page); + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + } + + vmf->page = page; + return VM_FAULT_LOCKED; +} + +static const struct vm_operations_struct secretmem_vm_ops = { + .fault = secretmem_fault, +}; + +static int secretmem_release(struct inode *inode, struct file *file) +{ + atomic_dec(&secretmem_users); + return 0; +} + +static int secretmem_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long len = vma->vm_end - vma->vm_start; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + if (mlock_future_check(vma->vm_mm, vma->vm_flags | VM_LOCKED, len)) + return -EAGAIN; + + vma->vm_flags |= VM_LOCKED | VM_DONTDUMP; + vma->vm_ops = &secretmem_vm_ops; + + return 0; +} + +bool vma_is_secretmem(struct vm_area_struct *vma) +{ + return vma->vm_ops == &secretmem_vm_ops; +} + +static const struct file_operations secretmem_fops = { + .release = secretmem_release, + .mmap = secretmem_mmap, +}; + +static bool secretmem_isolate_page(struct page *page, isolate_mode_t mode) +{ + return false; +} + +static int secretmem_migratepage(struct address_space *mapping, + struct page *newpage, struct page *page, + enum migrate_mode mode) +{ + return -EBUSY; +} + +static void secretmem_freepage(struct page *page) +{ + set_direct_map_default_noflush(page); + clear_highpage(page); +} + +const struct address_space_operations secretmem_aops = { + .freepage = secretmem_freepage, + .migratepage = secretmem_migratepage, + .isolate_page = secretmem_isolate_page, +}; + +static struct vfsmount *secretmem_mnt; + +static struct file *secretmem_file_create(unsigned long flags) +{ + struct file *file = ERR_PTR(-ENOMEM); + struct inode *inode; + + inode = alloc_anon_inode(secretmem_mnt->mnt_sb); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + file = alloc_file_pseudo(inode, secretmem_mnt, "secretmem", + O_RDWR, &secretmem_fops); + if (IS_ERR(file)) + goto err_free_inode; + + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); + mapping_set_unevictable(inode->i_mapping); + + inode->i_mapping->a_ops = &secretmem_aops; + + /* pretend we are a normal file with zero size */ + inode->i_mode |= S_IFREG; + inode->i_size = 0; + + return file; + +err_free_inode: + iput(inode); + return file; +} + +SYSCALL_DEFINE1(memfd_secret, unsigned int, flags) +{ + struct file *file; + int fd, err; + + /* make sure local flags do not confict with global fcntl.h */ + BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC); + + if (!secretmem_enable) + return -ENOSYS; + + if (flags & ~(SECRETMEM_FLAGS_MASK | O_CLOEXEC)) + return -EINVAL; + + fd = get_unused_fd_flags(flags & O_CLOEXEC); + if (fd < 0) + return fd; + + file = secretmem_file_create(flags); + if (IS_ERR(file)) { + err = PTR_ERR(file); + goto err_put_fd; + } + + file->f_flags |= O_LARGEFILE; + + fd_install(fd, file); + atomic_inc(&secretmem_users); + return fd; + +err_put_fd: + put_unused_fd(fd); + return err; +} + +static int secretmem_init_fs_context(struct fs_context *fc) +{ + return init_pseudo(fc, SECRETMEM_MAGIC) ? 0 : -ENOMEM; +} + +static struct file_system_type secretmem_fs = { + .name = "secretmem", + .init_fs_context = secretmem_init_fs_context, + .kill_sb = kill_anon_super, +}; + +static int secretmem_init(void) +{ + int ret = 0; + + if (!secretmem_enable) + return ret; + + secretmem_mnt = kern_mount(&secretmem_fs); + if (IS_ERR(secretmem_mnt)) + ret = PTR_ERR(secretmem_mnt); + + /* prevent secretmem mappings from ever getting PROT_EXEC */ + secretmem_mnt->mnt_flags |= MNT_NOEXEC; + + return ret; +} +fs_initcall(secretmem_init); diff --git a/mm/slub.c b/mm/slub.c index ad9fdb103533..48479119f6f0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -642,22 +643,27 @@ unsigned long get_each_object_track(struct kmem_cache *s, } EXPORT_SYMBOL_GPL(get_each_object_track); +#ifdef CONFIG_STACKDEPOT +static depot_stack_handle_t save_stack_depot_trace(gfp_t flags) +{ + unsigned long entries[TRACK_ADDRS_COUNT]; + depot_stack_handle_t handle; + unsigned int nr_entries; + + nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 4); + handle = stack_depot_save(entries, nr_entries, flags); + return handle; +} +#endif + static void set_track(struct kmem_cache *s, void *object, enum track_item alloc, unsigned long addr) { struct track *p = get_track(s, object, alloc); if (addr) { -#ifdef CONFIG_STACKTRACE - unsigned int nr_entries; - - metadata_access_enable(); - nr_entries = stack_trace_save(kasan_reset_tag(p->addrs), - TRACK_ADDRS_COUNT, 3); - metadata_access_disable(); - - if (nr_entries < TRACK_ADDRS_COUNT) - p->addrs[nr_entries] = 0; +#ifdef CONFIG_STACKDEPOT + p->handle = save_stack_depot_trace(GFP_NOWAIT); #endif p->addr = addr; p->cpu = smp_processor_id(); @@ -684,14 +690,19 @@ static void print_track(const char *s, struct track *t, unsigned long pr_time) pr_err("%s in %pS age=%lu cpu=%u pid=%d\n", s, (void *)t->addr, pr_time - t->when, t->cpu, t->pid); -#ifdef CONFIG_STACKTRACE +#ifdef CONFIG_STACKDEPOT { - int i; - for (i = 0; i < TRACK_ADDRS_COUNT; i++) - if (t->addrs[i]) - pr_err("\t%pS\n", (void *)t->addrs[i]); - else - break; + depot_stack_handle_t handle; + unsigned long *entries; + unsigned int nr_entries; + + handle = READ_ONCE(t->handle); + if (!handle) { + pr_err("object allocation/free stack trace missing\n"); + } else { + nr_entries = stack_depot_fetch(handle, &entries); + stack_trace_print(entries, nr_entries, 0); + } } #endif } @@ -4065,18 +4076,26 @@ void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) objp = fixup_red_left(s, objp); trackp = get_track(s, objp, TRACK_ALLOC); kpp->kp_ret = (void *)trackp->addr; -#ifdef CONFIG_STACKTRACE - for (i = 0; i < KS_ADDRS_COUNT && i < TRACK_ADDRS_COUNT; i++) { - kpp->kp_stack[i] = (void *)trackp->addrs[i]; - if (!kpp->kp_stack[i]) - break; - } +#ifdef CONFIG_STACKDEPOT + { + depot_stack_handle_t handle; + unsigned long *entries; + unsigned int nr_entries; - trackp = get_track(s, objp, TRACK_FREE); - for (i = 0; i < KS_ADDRS_COUNT && i < TRACK_ADDRS_COUNT; i++) { - kpp->kp_free_stack[i] = (void *)trackp->addrs[i]; - if (!kpp->kp_free_stack[i]) - break; + handle = READ_ONCE(trackp->handle); + if (handle) { + nr_entries = stack_depot_fetch(handle, &entries); + for (i = 0; i < KS_ADDRS_COUNT && i < nr_entries; i++) + kpp->kp_stack[i] = (void *)entries[i]; + } + + trackp = get_track(s, objp, TRACK_FREE); + handle = READ_ONCE(trackp->handle); + if (handle) { + nr_entries = stack_depot_fetch(handle, &entries); + for (i = 0; i < KS_ADDRS_COUNT && i < nr_entries; i++) + kpp->kp_free_stack[i] = (void *)entries[i]; + } } #endif #endif diff --git a/net/ceph/auth.c b/net/ceph/auth.c index d2b268a1838e..d38c9eadbe2f 100644 --- a/net/ceph/auth.c +++ b/net/ceph/auth.c @@ -58,12 +58,10 @@ struct ceph_auth_client *ceph_auth_init(const char *name, const int *con_modes) { struct ceph_auth_client *ac; - int ret; - ret = -ENOMEM; ac = kzalloc(sizeof(*ac), GFP_NOFS); if (!ac) - goto out; + return ERR_PTR(-ENOMEM); mutex_init(&ac->mutex); ac->negotiating = true; @@ -78,9 +76,6 @@ struct ceph_auth_client *ceph_auth_init(const char *name, dout("%s name '%s' preferred_mode %d fallback_mode %d\n", __func__, ac->name, ac->preferred_mode, ac->fallback_mode); return ac; - -out: - return ERR_PTR(ret); } void ceph_auth_destroy(struct ceph_auth_client *ac) diff --git a/net/ceph/auth_none.c b/net/ceph/auth_none.c index 097e9f8d87a7..77b5519bc45f 100644 --- a/net/ceph/auth_none.c +++ b/net/ceph/auth_none.c @@ -112,8 +112,8 @@ static int ceph_auth_none_create_authorizer( auth->authorizer = (struct ceph_authorizer *) au; auth->authorizer_buf = au->buf; auth->authorizer_buf_len = au->buf_len; - auth->authorizer_reply_buf = au->reply_buf; - auth->authorizer_reply_buf_len = sizeof (au->reply_buf); + auth->authorizer_reply_buf = NULL; + auth->authorizer_reply_buf_len = 0; return 0; } diff --git a/net/ceph/auth_none.h b/net/ceph/auth_none.h index 4158f064302e..bb121539e796 100644 --- a/net/ceph/auth_none.h +++ b/net/ceph/auth_none.h @@ -16,7 +16,6 @@ struct ceph_none_authorizer { struct ceph_authorizer base; char buf[128]; int buf_len; - char reply_buf[0]; }; struct ceph_auth_none_info { diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c index 17447c19d937..66136a4c1ce7 100644 --- a/net/ceph/cls_lock_client.c +++ b/net/ceph/cls_lock_client.c @@ -10,7 +10,9 @@ /** * ceph_cls_lock - grab rados lock for object - * @oid, @oloc: object to lock + * @osdc: OSD client instance + * @oid: object to lock + * @oloc: object to lock * @lock_name: the name of the lock * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED) * @cookie: user-defined identifier for this instance of the lock @@ -82,7 +84,9 @@ EXPORT_SYMBOL(ceph_cls_lock); /** * ceph_cls_unlock - release rados lock for object - * @oid, @oloc: object to lock + * @osdc: OSD client instance + * @oid: object to lock + * @oloc: object to lock * @lock_name: the name of the lock * @cookie: user-defined identifier for this instance of the lock */ @@ -130,7 +134,9 @@ EXPORT_SYMBOL(ceph_cls_unlock); /** * ceph_cls_break_lock - release rados lock for object for specified client - * @oid, @oloc: object to lock + * @osdc: OSD client instance + * @oid: object to lock + * @oloc: object to lock * @lock_name: the name of the lock * @cookie: user-defined identifier for this instance of the lock * @locker: current lock owner diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 9488600451e8..1c8de397d6ad 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -12,7 +12,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ auth.o auth_null.o auth_unix.o \ svc.o svcsock.o svcauth.o svcauth_unix.o \ addr.o rpcb_clnt.o timer.o xdr.o \ - sunrpc_syms.o cache.o rpc_pipe.o \ + sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \ svc_xprt.o \ xprtmultipath.o sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 6dff64374bfe..a81be45f40d9 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1275,7 +1275,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, long long ctxh; struct gss_api_mech *gm = NULL; time64_t expiry; - int status = -EINVAL; + int status; memset(&rsci, 0, sizeof(rsci)); /* context handle */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 42623d6b8f0e..8b4de70e8ead 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -41,6 +41,7 @@ #include #include "sunrpc.h" +#include "sysfs.h" #include "netns.h" #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) @@ -327,6 +328,7 @@ err_auth: out: if (pipefs_sb) rpc_put_sb_net(net); + rpc_sysfs_client_destroy(clnt); rpc_clnt_debugfs_unregister(clnt); return err; } @@ -410,6 +412,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, } rpc_clnt_set_transport(clnt, xprt, timeout); + xprt->main = true; xprt_iter_init(&clnt->cl_xpi, xps); xprt_switch_put(xps); @@ -423,6 +426,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, /* save the nodename */ rpc_clnt_set_nodename(clnt, nodename); + rpc_sysfs_client_setup(clnt, xps, rpc_net_ns(clnt)); err = rpc_client_register(clnt, args->authflavor, args->client_name); if (err) goto out_no_path; @@ -733,6 +737,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt, rpc_unregister_client(clnt); __rpc_clnt_remove_pipedir(clnt); + rpc_sysfs_client_destroy(clnt); rpc_clnt_debugfs_unregister(clnt); /* @@ -879,6 +884,7 @@ static void rpc_free_client_work(struct work_struct *work) * so they cannot be called in rpciod, so they are handled separately * here. */ + rpc_sysfs_client_destroy(clnt); rpc_clnt_debugfs_unregister(clnt); rpc_free_clid(clnt); rpc_clnt_remove_pipedir(clnt); @@ -2100,6 +2106,30 @@ call_connect_status(struct rpc_task *task) case -ENOTCONN: case -EAGAIN: case -ETIMEDOUT: + if (!(task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) && + (task->tk_flags & RPC_TASK_MOVEABLE) && + test_bit(XPRT_REMOVE, &xprt->state)) { + struct rpc_xprt *saved = task->tk_xprt; + struct rpc_xprt_switch *xps; + + rcu_read_lock(); + xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch)); + rcu_read_unlock(); + if (xps->xps_nxprts > 1) { + long value; + + xprt_release(task); + value = atomic_long_dec_return(&xprt->queuelen); + if (value == 0) + rpc_xprt_switch_remove_xprt(xps, saved); + xprt_put(saved); + task->tk_xprt = NULL; + task->tk_action = call_start; + } + xprt_switch_put(xps); + if (!task->tk_xprt) + return; + } goto out_retry; case -ENOBUFS: rpc_delay(task, HZ >> 2); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 39ed0e0afe6d..c045f63d11fa 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -591,11 +591,21 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q struct list_head *q; struct rpc_task *task; + /* + * Service the privileged queue. + */ + q = &queue->tasks[RPC_NR_PRIORITY - 1]; + if (queue->maxpriority > RPC_PRIORITY_PRIVILEGED && !list_empty(q)) { + task = list_first_entry(q, struct rpc_task, u.tk_wait.list); + goto out; + } + /* * Service a batch of tasks from a single owner. */ q = &queue->tasks[queue->priority]; - if (!list_empty(q) && --queue->nr) { + if (!list_empty(q) && queue->nr) { + queue->nr--; task = list_first_entry(q, struct rpc_task, u.tk_wait.list); goto out; } diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 236fadc4a439..691c0000e9ea 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -24,6 +24,7 @@ #include #include "sunrpc.h" +#include "sysfs.h" #include "netns.h" unsigned int sunrpc_net_id; @@ -103,6 +104,10 @@ init_sunrpc(void) if (err) goto out4; + err = rpc_sysfs_init(); + if (err) + goto out5; + sunrpc_debugfs_init(); #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) rpc_register_sysctl(); @@ -111,6 +116,8 @@ init_sunrpc(void) init_socket_xprt(); /* clnt sock transport */ return 0; +out5: + unregister_rpc_pipefs(); out4: unregister_pernet_subsys(&sunrpc_net_ops); out3: @@ -124,7 +131,10 @@ out: static void __exit cleanup_sunrpc(void) { + rpc_sysfs_exit(); rpc_cleanup_clids(); + xprt_cleanup_ids(); + xprt_multipath_cleanup_ids(); rpcauth_remove_module(); cleanup_socket_xprt(); svc_cleanup_xprt_sock(); diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c new file mode 100644 index 000000000000..64da3bfd28e6 --- /dev/null +++ b/net/sunrpc/sysfs.c @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Anna Schumaker + */ +#include +#include +#include +#include + +#include "sysfs.h" + +struct xprt_addr { + const char *addr; + struct rcu_head rcu; +}; + +static void free_xprt_addr(struct rcu_head *head) +{ + struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu); + + kfree(addr->addr); + kfree(addr); +} + +static struct kset *rpc_sunrpc_kset; +static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj; + +static void rpc_sysfs_object_release(struct kobject *kobj) +{ + kfree(kobj); +} + +static const struct kobj_ns_type_operations * +rpc_sysfs_object_child_ns_type(struct kobject *kobj) +{ + return &net_ns_type_operations; +} + +static struct kobj_type rpc_sysfs_object_type = { + .release = rpc_sysfs_object_release, + .sysfs_ops = &kobj_sysfs_ops, + .child_ns_type = rpc_sysfs_object_child_ns_type, +}; + +static struct kobject *rpc_sysfs_object_alloc(const char *name, + struct kset *kset, + struct kobject *parent) +{ + struct kobject *kobj; + + kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); + if (kobj) { + kobj->kset = kset; + if (kobject_init_and_add(kobj, &rpc_sysfs_object_type, + parent, "%s", name) == 0) + return kobj; + kobject_put(kobj); + } + return NULL; +} + +static inline struct rpc_xprt * +rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj) +{ + struct rpc_sysfs_xprt *x = container_of(kobj, + struct rpc_sysfs_xprt, kobject); + + return xprt_get(x->xprt); +} + +static inline struct rpc_xprt_switch * +rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj) +{ + struct rpc_sysfs_xprt *x = container_of(kobj, + struct rpc_sysfs_xprt, kobject); + + return xprt_switch_get(x->xprt_switch); +} + +static inline struct rpc_xprt_switch * +rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj) +{ + struct rpc_sysfs_xprt_switch *x = container_of(kobj, + struct rpc_sysfs_xprt_switch, kobject); + + return xprt_switch_get(x->xprt_switch); +} + +static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); + ssize_t ret; + + if (!xprt) + return 0; + ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); + xprt_put(xprt); + return ret + 1; +} + +static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); + ssize_t ret; + + if (!xprt) + return 0; + + ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n" + "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" + "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" + "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n" + "tasks_queuelen=%ld\n", + xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, + xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, + xprt->sending.qlen, xprt->pending.qlen, + xprt->backlog.qlen, xprt->main, + (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ? + get_srcport(xprt) : 0, + atomic_long_read(&xprt->queuelen)); + xprt_put(xprt); + return ret + 1; +} + +static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); + ssize_t ret; + int locked, connected, connecting, close_wait, bound, binding, + closing, congested, cwnd_wait, write_space, offline, remove; + + if (!xprt) + return 0; + + if (!xprt->state) { + ret = sprintf(buf, "state=CLOSED\n"); + } else { + locked = test_bit(XPRT_LOCKED, &xprt->state); + connected = test_bit(XPRT_CONNECTED, &xprt->state); + connecting = test_bit(XPRT_CONNECTING, &xprt->state); + close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state); + bound = test_bit(XPRT_BOUND, &xprt->state); + binding = test_bit(XPRT_BINDING, &xprt->state); + closing = test_bit(XPRT_CLOSING, &xprt->state); + congested = test_bit(XPRT_CONGESTED, &xprt->state); + cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state); + write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state); + offline = test_bit(XPRT_OFFLINE, &xprt->state); + remove = test_bit(XPRT_REMOVE, &xprt->state); + + ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n", + locked ? "LOCKED" : "", + connected ? "CONNECTED" : "", + connecting ? "CONNECTING" : "", + close_wait ? "CLOSE_WAIT" : "", + bound ? "BOUND" : "", + binding ? "BOUNDING" : "", + closing ? "CLOSING" : "", + congested ? "CONGESTED" : "", + cwnd_wait ? "CWND_WAIT" : "", + write_space ? "WRITE_SPACE" : "", + offline ? "OFFLINE" : "", + remove ? "REMOVE" : ""); + } + + xprt_put(xprt); + return ret + 1; +} + +static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct rpc_xprt_switch *xprt_switch = + rpc_sysfs_xprt_switch_kobj_get_xprt(kobj); + ssize_t ret; + + if (!xprt_switch) + return 0; + ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n", + xprt_switch->xps_nxprts, xprt_switch->xps_nactive, + atomic_long_read(&xprt_switch->xps_queuelen)); + xprt_switch_put(xprt_switch); + return ret + 1; +} + +static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); + struct sockaddr *saddr; + char *dst_addr; + int port; + struct xprt_addr *saved_addr; + size_t buf_len; + + if (!xprt) + return 0; + if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP || + xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) { + xprt_put(xprt); + return -EOPNOTSUPP; + } + + if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { + count = -EINTR; + goto out_put; + } + saddr = (struct sockaddr *)&xprt->addr; + port = rpc_get_port(saddr); + + /* buf_len is the len until the first occurence of either + * '\n' or '\0' + */ + buf_len = strcspn(buf, "\n"); + + dst_addr = kstrndup(buf, buf_len, GFP_KERNEL); + if (!dst_addr) + goto out_err; + saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL); + if (!saved_addr) + goto out_err_free; + saved_addr->addr = + rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]); + rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr); + call_rcu(&saved_addr->rcu, free_xprt_addr); + xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr, + sizeof(*saddr)); + rpc_set_port(saddr, port); + + xprt_force_disconnect(xprt); +out: + xprt_release_write(xprt, NULL); +out_put: + xprt_put(xprt); + return count; +out_err_free: + kfree(dst_addr); +out_err: + count = -ENOMEM; + goto out; +} + +static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); + int offline = 0, online = 0, remove = 0; + struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj); + + if (!xprt) + return 0; + + if (!strncmp(buf, "offline", 7)) + offline = 1; + else if (!strncmp(buf, "online", 6)) + online = 1; + else if (!strncmp(buf, "remove", 6)) + remove = 1; + else + return -EINVAL; + + if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { + count = -EINTR; + goto out_put; + } + if (xprt->main) { + count = -EINVAL; + goto release_tasks; + } + if (offline) { + set_bit(XPRT_OFFLINE, &xprt->state); + spin_lock(&xps->xps_lock); + xps->xps_nactive--; + spin_unlock(&xps->xps_lock); + } else if (online) { + clear_bit(XPRT_OFFLINE, &xprt->state); + spin_lock(&xps->xps_lock); + xps->xps_nactive++; + spin_unlock(&xps->xps_lock); + } else if (remove) { + if (test_bit(XPRT_OFFLINE, &xprt->state)) { + set_bit(XPRT_REMOVE, &xprt->state); + xprt_force_disconnect(xprt); + if (test_bit(XPRT_CONNECTED, &xprt->state)) { + if (!xprt->sending.qlen && + !xprt->pending.qlen && + !xprt->backlog.qlen && + !atomic_long_read(&xprt->queuelen)) + rpc_xprt_switch_remove_xprt(xps, xprt); + } + } else { + count = -EINVAL; + } + } + +release_tasks: + xprt_release_write(xprt, NULL); +out_put: + xprt_put(xprt); + xprt_switch_put(xps); + return count; +} + +int rpc_sysfs_init(void) +{ + rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj); + if (!rpc_sunrpc_kset) + return -ENOMEM; + rpc_sunrpc_client_kobj = + rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL); + if (!rpc_sunrpc_client_kobj) + goto err_client; + rpc_sunrpc_xprt_switch_kobj = + rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL); + if (!rpc_sunrpc_xprt_switch_kobj) + goto err_switch; + return 0; +err_switch: + kobject_put(rpc_sunrpc_client_kobj); + rpc_sunrpc_client_kobj = NULL; +err_client: + kset_unregister(rpc_sunrpc_kset); + rpc_sunrpc_kset = NULL; + return -ENOMEM; +} + +static void rpc_sysfs_client_release(struct kobject *kobj) +{ + struct rpc_sysfs_client *c; + + c = container_of(kobj, struct rpc_sysfs_client, kobject); + kfree(c); +} + +static void rpc_sysfs_xprt_switch_release(struct kobject *kobj) +{ + struct rpc_sysfs_xprt_switch *xprt_switch; + + xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject); + kfree(xprt_switch); +} + +static void rpc_sysfs_xprt_release(struct kobject *kobj) +{ + struct rpc_sysfs_xprt *xprt; + + xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject); + kfree(xprt); +} + +static const void *rpc_sysfs_client_namespace(struct kobject *kobj) +{ + return container_of(kobj, struct rpc_sysfs_client, kobject)->net; +} + +static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj) +{ + return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net; +} + +static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj) +{ + return container_of(kobj, struct rpc_sysfs_xprt, + kobject)->xprt->xprt_net; +} + +static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr, + 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store); + +static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info, + 0444, rpc_sysfs_xprt_info_show, NULL); + +static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state, + 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change); + +static struct attribute *rpc_sysfs_xprt_attrs[] = { + &rpc_sysfs_xprt_dstaddr.attr, + &rpc_sysfs_xprt_info.attr, + &rpc_sysfs_xprt_change_state.attr, + NULL, +}; + +static struct kobj_attribute rpc_sysfs_xprt_switch_info = + __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL); + +static struct attribute *rpc_sysfs_xprt_switch_attrs[] = { + &rpc_sysfs_xprt_switch_info.attr, + NULL, +}; + +static struct kobj_type rpc_sysfs_client_type = { + .release = rpc_sysfs_client_release, + .sysfs_ops = &kobj_sysfs_ops, + .namespace = rpc_sysfs_client_namespace, +}; + +static struct kobj_type rpc_sysfs_xprt_switch_type = { + .release = rpc_sysfs_xprt_switch_release, + .default_attrs = rpc_sysfs_xprt_switch_attrs, + .sysfs_ops = &kobj_sysfs_ops, + .namespace = rpc_sysfs_xprt_switch_namespace, +}; + +static struct kobj_type rpc_sysfs_xprt_type = { + .release = rpc_sysfs_xprt_release, + .default_attrs = rpc_sysfs_xprt_attrs, + .sysfs_ops = &kobj_sysfs_ops, + .namespace = rpc_sysfs_xprt_namespace, +}; + +void rpc_sysfs_exit(void) +{ + kobject_put(rpc_sunrpc_client_kobj); + kobject_put(rpc_sunrpc_xprt_switch_kobj); + kset_unregister(rpc_sunrpc_kset); +} + +static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent, + struct net *net, + int clid) +{ + struct rpc_sysfs_client *p; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p) { + p->net = net; + p->kobject.kset = rpc_sunrpc_kset; + if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type, + parent, "clnt-%d", clid) == 0) + return p; + kobject_put(&p->kobject); + } + return NULL; +} + +static struct rpc_sysfs_xprt_switch * +rpc_sysfs_xprt_switch_alloc(struct kobject *parent, + struct rpc_xprt_switch *xprt_switch, + struct net *net, + gfp_t gfp_flags) +{ + struct rpc_sysfs_xprt_switch *p; + + p = kzalloc(sizeof(*p), gfp_flags); + if (p) { + p->net = net; + p->kobject.kset = rpc_sunrpc_kset; + if (kobject_init_and_add(&p->kobject, + &rpc_sysfs_xprt_switch_type, + parent, "switch-%d", + xprt_switch->xps_id) == 0) + return p; + kobject_put(&p->kobject); + } + return NULL; +} + +static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent, + struct rpc_xprt *xprt, + gfp_t gfp_flags) +{ + struct rpc_sysfs_xprt *p; + + p = kzalloc(sizeof(*p), gfp_flags); + if (!p) + goto out; + p->kobject.kset = rpc_sunrpc_kset; + if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type, + parent, "xprt-%d-%s", xprt->id, + xprt->address_strings[RPC_DISPLAY_PROTO]) == 0) + return p; + kobject_put(&p->kobject); +out: + return NULL; +} + +void rpc_sysfs_client_setup(struct rpc_clnt *clnt, + struct rpc_xprt_switch *xprt_switch, + struct net *net) +{ + struct rpc_sysfs_client *rpc_client; + + rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj, + net, clnt->cl_clid); + if (rpc_client) { + char name[] = "switch"; + struct rpc_sysfs_xprt_switch *xswitch = + (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; + int ret; + + clnt->cl_sysfs = rpc_client; + rpc_client->clnt = clnt; + rpc_client->xprt_switch = xprt_switch; + kobject_uevent(&rpc_client->kobject, KOBJ_ADD); + ret = sysfs_create_link_nowarn(&rpc_client->kobject, + &xswitch->kobject, name); + if (ret) + pr_warn("can't create link to %s in sysfs (%d)\n", + name, ret); + } +} + +void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch, + struct rpc_xprt *xprt, + gfp_t gfp_flags) +{ + struct rpc_sysfs_xprt_switch *rpc_xprt_switch; + struct net *net; + + if (xprt_switch->xps_net) + net = xprt_switch->xps_net; + else + net = xprt->xprt_net; + rpc_xprt_switch = + rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj, + xprt_switch, net, gfp_flags); + if (rpc_xprt_switch) { + xprt_switch->xps_sysfs = rpc_xprt_switch; + rpc_xprt_switch->xprt_switch = xprt_switch; + rpc_xprt_switch->xprt = xprt; + kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD); + } +} + +void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch, + struct rpc_xprt *xprt, + gfp_t gfp_flags) +{ + struct rpc_sysfs_xprt *rpc_xprt; + struct rpc_sysfs_xprt_switch *switch_obj = + (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; + + rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags); + if (rpc_xprt) { + xprt->xprt_sysfs = rpc_xprt; + rpc_xprt->xprt = xprt; + rpc_xprt->xprt_switch = xprt_switch; + kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD); + } +} + +void rpc_sysfs_client_destroy(struct rpc_clnt *clnt) +{ + struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs; + + if (rpc_client) { + char name[] = "switch"; + + sysfs_remove_link(&rpc_client->kobject, name); + kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE); + kobject_del(&rpc_client->kobject); + kobject_put(&rpc_client->kobject); + clnt->cl_sysfs = NULL; + } +} + +void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch) +{ + struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs; + + if (rpc_xprt_switch) { + kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE); + kobject_del(&rpc_xprt_switch->kobject); + kobject_put(&rpc_xprt_switch->kobject); + xprt_switch->xps_sysfs = NULL; + } +} + +void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt) +{ + struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs; + + if (rpc_xprt) { + kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE); + kobject_del(&rpc_xprt->kobject); + kobject_put(&rpc_xprt->kobject); + xprt->xprt_sysfs = NULL; + } +} diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h new file mode 100644 index 000000000000..6620cebd1037 --- /dev/null +++ b/net/sunrpc/sysfs.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Anna Schumaker + */ +#ifndef __SUNRPC_SYSFS_H +#define __SUNRPC_SYSFS_H + +struct rpc_sysfs_client { + struct kobject kobject; + struct net *net; + struct rpc_clnt *clnt; + struct rpc_xprt_switch *xprt_switch; +}; + +struct rpc_sysfs_xprt_switch { + struct kobject kobject; + struct net *net; + struct rpc_xprt_switch *xprt_switch; + struct rpc_xprt *xprt; +}; + +struct rpc_sysfs_xprt { + struct kobject kobject; + struct rpc_xprt *xprt; + struct rpc_xprt_switch *xprt_switch; +}; + +int rpc_sysfs_init(void); +void rpc_sysfs_exit(void); + +void rpc_sysfs_client_setup(struct rpc_clnt *clnt, + struct rpc_xprt_switch *xprt_switch, + struct net *net); +void rpc_sysfs_client_destroy(struct rpc_clnt *clnt); +void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch, + struct rpc_xprt *xprt, gfp_t gfp_flags); +void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt); +void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch, + struct rpc_xprt *xprt, gfp_t gfp_flags); +void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt); + +#endif diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 3964ff74ee51..ca10ba2626f2 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -1230,10 +1230,9 @@ static unsigned int xdr_set_page_base(struct xdr_stream *xdr, void *kaddr; maxlen = xdr->buf->page_len; - if (base >= maxlen) { - base = maxlen; - maxlen = 0; - } else + if (base >= maxlen) + return 0; + else maxlen -= base; if (len > maxlen) len = maxlen; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 3509a7f139b9..fb6db09725c7 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -55,6 +55,7 @@ #include #include "sunrpc.h" +#include "sysfs.h" /* * Local variables @@ -443,7 +444,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) } EXPORT_SYMBOL_GPL(xprt_release_xprt_cong); -static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) +void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) { if (xprt->snd_task != task) return; @@ -1746,6 +1747,30 @@ static void xprt_free_all_slots(struct rpc_xprt *xprt) } } +static DEFINE_IDA(rpc_xprt_ids); + +void xprt_cleanup_ids(void) +{ + ida_destroy(&rpc_xprt_ids); +} + +static int xprt_alloc_id(struct rpc_xprt *xprt) +{ + int id; + + id = ida_simple_get(&rpc_xprt_ids, 0, 0, GFP_KERNEL); + if (id < 0) + return id; + + xprt->id = id; + return 0; +} + +static void xprt_free_id(struct rpc_xprt *xprt) +{ + ida_simple_remove(&rpc_xprt_ids, xprt->id); +} + struct rpc_xprt *xprt_alloc(struct net *net, size_t size, unsigned int num_prealloc, unsigned int max_alloc) @@ -1758,6 +1783,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size, if (xprt == NULL) goto out; + xprt_alloc_id(xprt); xprt_init(xprt, net); for (i = 0; i < num_prealloc; i++) { @@ -1786,6 +1812,8 @@ void xprt_free(struct rpc_xprt *xprt) { put_net(xprt->xprt_net); xprt_free_all_slots(xprt); + xprt_free_id(xprt); + rpc_sysfs_xprt_destroy(xprt); kfree_rcu(xprt, rcu); } EXPORT_SYMBOL_GPL(xprt_free); diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c index 1b4073131c6f..c60820e45082 100644 --- a/net/sunrpc/xprtmultipath.c +++ b/net/sunrpc/xprtmultipath.c @@ -19,6 +19,8 @@ #include #include +#include "sysfs.h" + typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps, const struct rpc_xprt *cur); @@ -55,6 +57,7 @@ void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps, if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) xprt_switch_add_xprt_locked(xps, xprt); spin_unlock(&xps->xps_lock); + rpc_sysfs_xprt_setup(xps, xprt, GFP_KERNEL); } static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, @@ -62,7 +65,8 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, { if (unlikely(xprt == NULL)) return; - xps->xps_nactive--; + if (!test_bit(XPRT_OFFLINE, &xprt->state)) + xps->xps_nactive--; xps->xps_nxprts--; if (xps->xps_nxprts == 0) xps->xps_net = NULL; @@ -86,6 +90,30 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps, xprt_put(xprt); } +static DEFINE_IDA(rpc_xprtswitch_ids); + +void xprt_multipath_cleanup_ids(void) +{ + ida_destroy(&rpc_xprtswitch_ids); +} + +static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps, gfp_t gfp_flags) +{ + int id; + + id = ida_simple_get(&rpc_xprtswitch_ids, 0, 0, gfp_flags); + if (id < 0) + return id; + + xps->xps_id = id; + return 0; +} + +static void xprt_switch_free_id(struct rpc_xprt_switch *xps) +{ + ida_simple_remove(&rpc_xprtswitch_ids, xps->xps_id); +} + /** * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch * @xprt: pointer to struct rpc_xprt @@ -103,12 +131,15 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, if (xps != NULL) { spin_lock_init(&xps->xps_lock); kref_init(&xps->xps_kref); + xprt_switch_alloc_id(xps, gfp_flags); xps->xps_nxprts = xps->xps_nactive = 0; atomic_long_set(&xps->xps_queuelen, 0); xps->xps_net = NULL; INIT_LIST_HEAD(&xps->xps_xprt_list); xps->xps_iter_ops = &rpc_xprt_iter_singular; + rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags); xprt_switch_add_xprt_locked(xps, xprt); + rpc_sysfs_xprt_setup(xps, xprt, gfp_flags); } return xps; @@ -136,6 +167,8 @@ static void xprt_switch_free(struct kref *kref) struct rpc_xprt_switch, xps_kref); xprt_switch_free_entries(xps); + rpc_sysfs_xprt_switch_destroy(xps); + xprt_switch_free_id(xps); kfree_rcu(xps, xps_rcu); } @@ -198,7 +231,8 @@ void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi) static bool xprt_is_active(const struct rpc_xprt *xprt) { - return kref_read(&xprt->kref) != 0; + return (kref_read(&xprt->kref) != 0 && + !test_bit(XPRT_OFFLINE, &xprt->state)); } static diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 5238bc829235..1e651447dc4e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -483,7 +483,7 @@ out_overflow: * @iov: kvec to write * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred @@ -504,7 +504,7 @@ static int svc_rdma_iov_write(struct svc_rdma_write_info *info, * @length: number of bytes to write * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred @@ -526,7 +526,7 @@ static int svc_rdma_pages_write(struct svc_rdma_write_info *info, * @data: pointer to write arguments * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 19a49d26b1e4..9c2ffc67c0fd 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -73,6 +73,7 @@ unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE; unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE; unsigned int xprt_rdma_memreg_strategy = RPCRDMA_FRWR; int xprt_rdma_pad_optimize; +static struct xprt_class xprt_rdma; #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) @@ -349,6 +350,7 @@ xprt_setup_rdma(struct xprt_create *args) /* Ensure xprt->addr holds valid server TCP (not RDMA) * address, for any side protocols which peek at it */ xprt->prot = IPPROTO_TCP; + xprt->xprt_class = &xprt_rdma; xprt->addrlen = args->addrlen; memcpy(&xprt->addr, sap, xprt->addrlen); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 316d04945587..e573dcecdd66 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -91,6 +91,11 @@ static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; static struct ctl_table_header *sunrpc_table_header; +static struct xprt_class xs_local_transport; +static struct xprt_class xs_udp_transport; +static struct xprt_class xs_tcp_transport; +static struct xprt_class xs_bc_tcp_transport; + /* * FIXME: changing the UDP slot table size should also resize the UDP * socket buffers for existing UDP transports @@ -1648,6 +1653,13 @@ static int xs_get_srcport(struct sock_xprt *transport) return port; } +unsigned short get_srcport(struct rpc_xprt *xprt) +{ + struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt); + return sock->srcport; +} +EXPORT_SYMBOL(get_srcport); + static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port) { if (transport->srcport != 0) @@ -1689,7 +1701,8 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock) err = kernel_bind(sock, (struct sockaddr *)&myaddr, transport->xprt.addrlen); if (err == 0) { - transport->srcport = port; + if (transport->xprt.reuseport) + transport->srcport = port; break; } last = port; @@ -2779,6 +2792,7 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args) transport = container_of(xprt, struct sock_xprt, xprt); xprt->prot = 0; + xprt->xprt_class = &xs_local_transport; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; xprt->bind_timeout = XS_BIND_TO; @@ -2848,6 +2862,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) transport = container_of(xprt, struct sock_xprt, xprt); xprt->prot = IPPROTO_UDP; + xprt->xprt_class = &xs_udp_transport; /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); @@ -2928,6 +2943,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) transport = container_of(xprt, struct sock_xprt, xprt); xprt->prot = IPPROTO_TCP; + xprt->xprt_class = &xs_tcp_transport; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; xprt->bind_timeout = XS_BIND_TO; @@ -3001,6 +3017,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) transport = container_of(xprt, struct sock_xprt, xprt); xprt->prot = IPPROTO_TCP; + xprt->xprt_class = &xs_bc_tcp_transport; xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; xprt->timeout = &xs_tcp_default_timeout; diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 82dd1b65b7a8..f247e691562d 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -90,8 +90,13 @@ clean := -f $(srctree)/scripts/Makefile.clean obj echo-cmd = $(if $($(quiet)cmd_$(1)),\ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) +# sink stdout for 'make -s' + redirect := + quiet_redirect := +silent_redirect := exec >/dev/null; + # printing commands -cmd = @set -e; $(echo-cmd) $(cmd_$(1)) +cmd = @set -e; $(echo-cmd) $($(quiet)redirect) $(cmd_$(1)) ### # if_changed - execute command if any prerequisite is newer than diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 34d257653fb4..10b2f2380d6f 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -219,7 +219,6 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT ifdef CONFIG_STACK_VALIDATION ifndef CONFIG_LTO_CLANG -ifneq ($(SKIP_STACK_VALIDATION),1) __objtool_obj := $(objtree)/tools/objtool/objtool @@ -233,7 +232,6 @@ objtool_obj = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ $(__objtool_obj)) -endif # SKIP_STACK_VALIDATION endif # CONFIG_LTO_CLANG endif # CONFIG_STACK_VALIDATION diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index a7883e455290..5e9b8057fb24 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -39,12 +39,10 @@ prelink-ext := .lto # so let's now process the prelinked binary before we link the module. ifdef CONFIG_STACK_VALIDATION -ifneq ($(SKIP_STACK_VALIDATION),1) cmd_ld_ko_o += \ $(objtree)/tools/objtool/objtool $(objtool_args) \ $(@:.ko=$(prelink-ext).o); -endif # SKIP_STACK_VALIDATION endif # CONFIG_STACK_VALIDATION endif # CONFIG_LTO_CLANG diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index a18b47695f55..b7609958ee36 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -40,6 +40,10 @@ cat << EOF #define __IGNORE_setrlimit /* setrlimit */ #endif +#ifndef __ARCH_WANT_MEMFD_SECRET +#define __IGNORE_memfd_secret +#endif + /* Missing flags argument */ #define __IGNORE_renameat /* renameat2 */ diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 90398347e366..5fbad61fe490 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -3,11 +3,10 @@ # (c) 2014, Sasha Levin #set -x -if [[ $# < 1 ]]; then +usage() { echo "Usage:" - echo " $0 -r | [base path] [modules path]" - exit 1 -fi + echo " $0 -r | [|auto] []" +} if [[ $1 == "-r" ]] ; then vmlinux="" @@ -24,6 +23,7 @@ if [[ $1 == "-r" ]] ; then if [[ $vmlinux == "" ]] ; then echo "ERROR! vmlinux image for release $release is not found" >&2 + usage exit 2 fi else @@ -31,12 +31,35 @@ else basepath=${2-auto} modpath=$3 release="" + debuginfod= + + # Can we use debuginfod-find? + if type debuginfod-find >/dev/null 2>&1 ; then + debuginfod=${1-only} + fi + + if [[ $vmlinux == "" && -z $debuginfod ]] ; then + echo "ERROR! vmlinux image must be specified" >&2 + usage + exit 1 + fi fi declare -A cache declare -A modcache find_module() { + if [[ -n $debuginfod ]] ; then + if [[ -n $modbuildid ]] ; then + debuginfod-find debuginfo $modbuildid && return + fi + + # Only using debuginfod so don't try to find vmlinux module path + if [[ $debuginfod == "only" ]] ; then + return + fi + fi + if [[ "$modpath" != "" ]] ; then for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do if readelf -WS "$fn" | grep -qwF .debug_line ; then @@ -51,7 +74,7 @@ find_module() { find_module && return if [[ $release == "" ]] ; then - release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" | sed -n 's/\$1 = "\(.*\)".*/\1/p') + release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p') fi for dn in {/usr/lib/debug,}/lib/modules/$release ; do @@ -105,7 +128,7 @@ parse_symbol() { if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then local base_addr=${cache[$module,$name]} else - local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') + local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') if [[ $base_addr == "" ]] ; then # address not found return @@ -129,7 +152,7 @@ parse_symbol() { if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then local code=${cache[$module,$address]} else - local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address") + local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null) cache[$module,$address]=$code fi @@ -150,6 +173,27 @@ parse_symbol() { symbol="$segment$name ($code)" } +debuginfod_get_vmlinux() { + local vmlinux_buildid=${1##* } + + if [[ $vmlinux != "" ]]; then + return + fi + + if [[ $vmlinux_buildid =~ ^[0-9a-f]+ ]]; then + vmlinux=$(debuginfod-find debuginfo $vmlinux_buildid) + if [[ $? -ne 0 ]] ; then + echo "ERROR! vmlinux image not found via debuginfod-find" >&2 + usage + exit 2 + fi + return + fi + echo "ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux" >&2 + usage + exit 2 +} + decode_code() { local scripts=`dirname "${BASH_SOURCE[0]}"` @@ -157,6 +201,14 @@ decode_code() { } handle_line() { + if [[ $basepath == "auto" && $vmlinux != "" ]] ; then + module="" + symbol="kernel_init+0x0/0x0" + parse_symbol + basepath=${symbol#kernel_init (} + basepath=${basepath%/init/main.c:*)} + fi + local words # Tokenize @@ -182,16 +234,28 @@ handle_line() { fi done + if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then + words[$last-1]="${words[$last-1]} ${words[$last]}" + unset words[$last] + last=$(( $last - 1 )) + fi + if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then module=${words[$last]} module=${module#\[} module=${module%\]} + modbuildid=${module#* } + module=${module% *} + if [[ $modbuildid == $module ]]; then + modbuildid= + fi symbol=${words[$last-1]} unset words[$last-1] else # The symbol is the last element, process it symbol=${words[$last]} module= + modbuildid= fi unset words[$last] @@ -201,14 +265,6 @@ handle_line() { echo "${words[@]}" "$symbol $module" } -if [[ $basepath == "auto" ]] ; then - module="" - symbol="kernel_init+0x0/0x0" - parse_symbol - basepath=${symbol#kernel_init (} - basepath=${basepath%/init/main.c:*)} -fi - while read line; do # Let's see if we have an address in the line if [[ $line =~ \[\<([^]]+)\>\] ]] || @@ -218,6 +274,9 @@ while read line; do # Is it a code line? elif [[ $line == *Code:* ]]; then decode_code "$line" + # Is it a version line? + elif [[ -n $debuginfod && $line =~ PID:\ [0-9]+\ Comm: ]]; then + debuginfod_get_vmlinux "$line" else # Nothing special in this line, show it as is echo "$line" diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index bfa1ea8f5f98..5d84b44a2a2a 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -678,7 +678,7 @@ static void check_conf(struct menu *menu) check_conf(child); } -static struct option long_opts[] = { +static const struct option long_opts[] = { {"help", no_argument, NULL, 'h'}, {"silent", no_argument, NULL, 's'}, {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig}, diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 475faa15854e..36ef7b37fc5d 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -38,9 +38,7 @@ LDFLAGS_vmlinux="$3" # Will be supressed by "make -s" info() { - if [ "${quiet}" != "silent_" ]; then - printf " %-7s %s\n" "${1}" "${2}" - fi + printf " %-7s %s\n" "${1}" "${2}" } # Generate a linker script to ensure correct ordering of initcalls. diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index a72b154de7b0..6a2a04d92f42 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -9,8 +9,6 @@ PREEMPT_RT=$5 CC_VERSION="$6" LD=$7 -vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; } - # Do not expand names set -f @@ -90,7 +88,7 @@ if [ -r $TARGET ] && \ cmp -s .tmpver.1 .tmpver.2; then rm -f .tmpcompile else - vecho " UPD $TARGET" + echo " UPD $TARGET" mv -f .tmpcompile $TARGET fi rm -f .tmpver.1 .tmpver.2 diff --git a/scripts/mkmakefile b/scripts/mkmakefile deleted file mode 100755 index 1cb174751429..000000000000 --- a/scripts/mkmakefile +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# Generates a small Makefile used in the root of the output -# directory, to allow make to be started from there. -# The Makefile also allow for more convinient build of external modules - -# Usage -# $1 - Kernel src directory - -if [ "${quiet}" != "silent_" ]; then - echo " GEN Makefile" -fi - -cat << EOF > Makefile -# Automatically generated by $0: don't edit -include $1/Makefile -EOF diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ae5b8eb1d79d..7056064d4e6d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -661,8 +661,11 @@ static void handle_modversion(const struct module *mod, unsigned int crc; if (sym->st_shndx == SHN_UNDEF) { - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", - symname, mod->name, mod->is_vmlinux ? "" : ".ko"); + warn("EXPORT symbol \"%s\" [%s%s] version ...\n" + "Is \"%s\" prototyped in ?\n", + symname, mod->name, mod->is_vmlinux ? "" : ".ko", + symname); + return; } diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 1e15fd2b2f30..cacf8b4156af 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -82,32 +82,19 @@ scm_version() fi # If we are past a tagged commit (like # "v2.6.30-rc5-302-g72357d5"), we pretty print it. - # - # Ensure the abbreviated sha1 has exactly 12 - # hex characters, to make the output - # independent of git version, local - # core.abbrev settings and/or total number of - # objects in the current repository - passing - # --abbrev=12 ensures a minimum of 12, and the - # awk substr() then picks the 'g' and first 12 - # hex chars. - if atag="$(git describe --abbrev=12 2>/dev/null)"; then - echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),substr($(NF),0,13))}' - - # If we don't have a tag at all we print -g{commitish}, - # again using exactly 12 hex chars. - else - head="$(echo $head | cut -c1-12)" - printf '%s%s' -g $head + if atag="$(git describe 2>/dev/null)"; then + echo "$atag" | awk -F- '{printf("-%05d", $(NF-1))}' fi - fi - # Is this git on svn? - if git config --get svn-remote.svn.url >/dev/null; then - printf -- '-svn%s' "$(git svn find-rev $head)" + # Add -g and exactly 12 hex chars. + printf '%s%s' -g "$(echo $head | cut -c1-12)" fi # Check for uncommitted changes. + # This script must avoid any write attempt to the source tree, + # which might be read-only. + # You cannot use 'git describe --dirty' because it tries to + # create .git/index.lock . # First, with git-status, but --no-optional-locks is only # supported in git >= 2.14, so fall back to git-diff-index if # it fails. Note that git-diff-index does not refresh the @@ -116,45 +103,9 @@ scm_version() if { git --no-optional-locks status -uno --porcelain 2>/dev/null || git diff-index --name-only HEAD - } | grep -qvE '^(.. )?scripts/package'; then + } | read dummy; then printf '%s' -dirty fi - - # All done with git - return - fi - - # Check for mercurial and a mercurial repo. - if hgid=$(hg id 2>/dev/null); then - # Do we have an tagged version? If so, latesttagdistance == 1 - if [ "$(hg log -r . --template '{latesttagdistance}')" = "1" ]; then - id=$(hg log -r . --template '{latesttag}') - printf '%s%s' -hg "$id" - else - tag=$(printf '%s' "$hgid" | cut -d' ' -f2) - if [ -z "$tag" -o "$tag" = tip ]; then - id=$(printf '%s' "$hgid" | sed 's/[+ ].*//') - printf '%s%s' -hg "$id" - fi - fi - - # Are there uncommitted changes? - # These are represented by + after the changeset id. - case "$hgid" in - *+|*+\ *) printf '%s' -dirty ;; - esac - - # All done with mercurial - return - fi - - # Check for svn and a svn repo. - if rev=$(LC_ALL=C svn info 2>/dev/null | grep '^Last Changed Rev'); then - rev=$(echo $rev | awk '{print $NF}') - printf -- '-svn%s' "$rev" - - # All done with svn - return fi } @@ -203,15 +154,13 @@ res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then # full scm version string res="$res$(scm_version)" -else +elif [ -z "${LOCALVERSION}" ]; then # append a plus sign if the repository is not in a clean # annotated or signed tagged state (as git describe only # looks at signed or annotated tags - git tag -a/-s) and # LOCALVERSION= is not specified - if test "${LOCALVERSION+set}" != "set"; then - scm=$(scm_version --short) - res="$res${scm:++}" - fi + scm=$(scm_version --short) + res="$res${scm:++}" fi echo "$res" diff --git a/scripts/syscallhdr.sh b/scripts/syscallhdr.sh index 848ac2735115..22e34cd46b9b 100755 --- a/scripts/syscallhdr.sh +++ b/scripts/syscallhdr.sh @@ -69,7 +69,7 @@ guard=_UAPI_ASM_$(basename "$outfile" | sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g') -grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | sort -n | { +grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | { echo "#ifndef $guard" echo "#define $guard" echo diff --git a/scripts/syscallnr.sh b/scripts/syscallnr.sh new file mode 100644 index 000000000000..3aa29e0dcc52 --- /dev/null +++ b/scripts/syscallnr.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Generate a syscall number header. +# +# Each line of the syscall table should have the following format: +# +# NR ABI NAME [NATIVE] [COMPAT] +# +# NR syscall number +# ABI ABI name +# NAME syscall name +# NATIVE native entry point (optional) +# COMPAT compat entry point (optional) +set -e + +usage() { + echo >&2 "usage: $0 [--abis ABIS] [--prefix PREFIX] INFILE OUTFILE" >&2 + echo >&2 + echo >&2 " INFILE input syscall table" + echo >&2 " OUTFILE output header file" + echo >&2 + echo >&2 "options:" + echo >&2 " --abis ABIS ABI(s) to handle (By default, all lines are handled)" + echo >&2 " --prefix PREFIX The prefix to the macro like __NR_" + exit 1 +} + +# default unless specified by options +abis= +prefix= + +while [ $# -gt 0 ] +do + case $1 in + --abis) + abis=$(echo "($2)" | tr ',' '|') + shift 2;; + --prefix) + prefix=$2 + shift 2;; + -*) + echo "$1: unknown option" >&2 + usage;; + *) + break;; + esac +done + +if [ $# -ne 2 ]; then + usage +fi + +infile="$1" +outfile="$2" + +guard=_ASM_$(basename "$outfile" | + sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g') + +grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | sort -n | { + echo "#ifndef $guard" + echo "#define $guard" + echo + + max=0 + while read nr abi name native compat ; do + max=$nr + done + + echo "#define __NR_${prefix}syscalls $(($max + 1))" + echo + echo "#endif /* $guard */" +} > "$outfile" diff --git a/scripts/syscalltbl.sh b/scripts/syscalltbl.sh index aa6ab156301c..6abe143889ef 100755 --- a/scripts/syscalltbl.sh +++ b/scripts/syscalltbl.sh @@ -52,10 +52,15 @@ outfile="$2" nxt=0 -grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n | { +grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | { while read nr abi name native compat ; do + if [ $nxt -gt $nr ]; then + echo "error: $infile: syscall table is not sorted or duplicates the same syscall number" >&2 + exit 1 + fi + while [ $nxt -lt $nr ]; do echo "__SYSCALL($nxt, sys_ni_syscall)" nxt=$((nxt + 1)) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 42980da45fbf..06a7ced218e2 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -403,8 +403,6 @@ static const struct ieee1394_device_id bebob_id_table[] = { SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal), /* ESI, Quatafire610 */ SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal), - // AcousticReality, eARMasterOne. Terratec OEM. - SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal), /* CME, MatrixKFW */ SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal), // Phonic Helix Board 12 FireWire MkII. @@ -434,7 +432,8 @@ static const struct ieee1394_device_id bebob_id_table[] = { SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000007, &yamaha_terratec_spec), /* TerraTec Electronic GmbH, EWS MIC2/MIC8 */ SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000005, &spec_normal), - /* Terratec Electronic GmbH, Aureon 7.1 Firewire */ + // Terratec Electronic GmbH, Aureon 7.1 Firewire. + // AcousticReality, eAR Master One, Eroica, Figaro, and Ciaccona. Perhaps Terratec OEM. SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal), /* Yamaha, GO44 */ SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_terratec_spec), diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 6c59a3eec59b..ef6d0a20efd8 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -551,7 +551,7 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev) } if (acard->sb->hardware != SB_HW_16) { snd_printk(KERN_ERR PFX "SB16 not found during probe\n"); - return err; + return -ENODEV; } snd_wss_out(acard->wss, CS4231_MISC_INFO, 0x40); /* switch on MODE2 */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 493d8ee2642a..1389cfd5e0db 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8442,6 +8442,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 2d1bfbcba933..df3ba5c70de9 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -694,7 +694,7 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich int status, civ, i, step; int ack = 0; - if (!ichdev->prepared || ichdev->suspended) + if (!(ichdev->prepared || chip->in_measurement) || ichdev->suspended) return; spin_lock_irqsave(&chip->reg_lock, flags); diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c index 7eed5791972c..8056422ed7c5 100644 --- a/sound/synth/emux/emux_nrpn.c +++ b/sound/synth/emux/emux_nrpn.c @@ -69,7 +69,7 @@ static const int gs_sense[] = DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY }; -/* effect sensitivies for XG controls: +/* effect sensitivities for XG controls: * adjusted for chaos 8MB soundfonts */ static const int xg_sense[] = diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index da3cf8912463..16f00097cb95 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -108,7 +108,7 @@ snd_soundfont_close_check(struct snd_sf_list *sflist, int client) * Deal with a soundfont patch. Any driver could use these routines * although it was designed for the AWE64. * - * The sample_write and callargs pararameters allow a callback into + * The sample_write and callargs parameters allow a callback into * the actual driver to write sample data to the board or whatever * it wants to do with it. */ @@ -799,7 +799,7 @@ snd_sf_linear_to_log(unsigned int amount, int offset, int ratio) amount <<= 1; s = (amount >> 24) & 0x7f; low = (amount >> 16) & 0xff; - /* linear approxmimation by lower 8 bit */ + /* linear approximation by lower 8 bit */ v = (log_tbl[s + 1] * low + log_tbl[s] * (0x100 - low)) >> 8; v -= offset; v = (v * ratio) >> 16; @@ -1433,7 +1433,7 @@ snd_sf_free(struct snd_sf_list *sflist) /* * Remove all samples - * The soundcard should be silet before calling this function. + * The soundcard should be silent before calling this function. */ int snd_soundfont_remove_samples(struct snd_sf_list *sflist) diff --git a/sound/usb/card.h b/sound/usb/card.h index 5577a776561b..6c0a052a28f9 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -19,7 +19,7 @@ struct audioformat { unsigned char iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ unsigned char ep_idx; /* endpoint array index */ - unsigned char altset_idx; /* array index of altenate setting */ + unsigned char altset_idx; /* array index of alternate setting */ unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ @@ -158,6 +158,7 @@ struct snd_usb_substream { unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */ unsigned int running: 1; /* running status */ + unsigned int period_elapsed_pending; /* delay period handling */ unsigned int buffer_bytes; /* buffer size in bytes */ unsigned int inflight_bytes; /* in-flight data bytes on buffer (for playback) */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index da649211bff3..4f856771216b 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -645,7 +645,7 @@ static bool endpoint_compatible(struct snd_usb_endpoint *ep, } /* - * Check whether the given fp and hw params are compatbile with the current + * Check whether the given fp and hw params are compatible with the current * setup of the target EP for implicit feedback sync */ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, @@ -1245,7 +1245,7 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, * * This function sets up the EP to be fully usable state. * It's called either from hw_params or prepare callback. - * The function checks need_setup flag, and perfoms nothing unless needed, + * The function checks need_setup flag, and performs nothing unless needed, * so it's safe to call this multiple times. * * This returns zero if unchanged, 1 if the configuration has changed, diff --git a/sound/usb/media.c b/sound/usb/media.c index 812017eacbcf..840f42cb9272 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -285,7 +285,7 @@ snd_mixer_init: ret); if (!media_devnode_is_registered(mdev->devnode)) { - /* dont'register if snd_media_mixer_init() failed */ + /* don't register if snd_media_mixer_init() failed */ if (ret) goto create_fail; diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index c53a9773f310..0255089c9efb 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -163,7 +163,7 @@ snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, } /* - * When opening Universal Control the program periodicaly + * When opening Universal Control the program periodically * sends and receives state packets for syncinc state between * the device and the host. * diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index 691b95466d0f..0d6e4f15bf77 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -21,7 +21,7 @@ * Auto-detection via UAC2 is not feasible to properly discover the vast * majority of features. It's related to both Linux/ALSA's UAC2 as well as * Focusrite's implementation of it. Eventually quirks may be sufficient but - * right now it's a major headache to work arount these things. + * right now it's a major headache to work around these things. * * NB. Neither the OSX nor the win driver provided by Focusrite performs * discovery, they seem to operate the same as this driver. diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e26d37365f02..4e5031a68064 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -611,13 +611,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->last_frame_number = 0; + subs->period_elapsed_pending = 0; runtime->delay = 0; - /* for playback, submit the URBs now; otherwise, the first hwptr_done - * updates for all URBs would happen at the same time when starting */ - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - ret = start_endpoints(subs); - unlock: snd_usb_unlock_shutdown(chip); return ret; @@ -1398,6 +1394,10 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, subs->trigger_tstamp_pending_update = false; } + if (period_elapsed && !subs->running) { + subs->period_elapsed_pending = 1; + period_elapsed = 0; + } spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = bytes; if (period_elapsed) @@ -1413,6 +1413,7 @@ static void retire_playback_urb(struct snd_usb_substream *subs, { unsigned long flags; struct snd_urb_ctx *ctx = urb->context; + bool period_elapsed = false; spin_lock_irqsave(&subs->lock, flags); if (ctx->queued) { @@ -1423,13 +1424,20 @@ static void retire_playback_urb(struct snd_usb_substream *subs, } subs->last_frame_number = usb_get_current_frame_number(subs->dev); + if (subs->running) { + period_elapsed = subs->period_elapsed_pending; + subs->period_elapsed_pending = 0; + } spin_unlock_irqrestore(&subs->lock, flags); + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); } static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_usb_substream *subs = substream->runtime->private_data; + int err; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1440,6 +1448,14 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea prepare_playback_urb, retire_playback_urb, subs); + if (cmd == SNDRV_PCM_TRIGGER_START) { + err = start_endpoints(subs); + if (err < 0) { + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, NULL, NULL); + return err; + } + } subs->running = 1; dev_dbg(&subs->dev->dev, "%d:%d Start Playback PCM\n", subs->cur_audiofmt->iface, diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 6154662d3097..c39cc6851e2d 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -526,7 +526,7 @@ static int usx2y_urbs_start(struct snd_usx2y_substream *subs) cleanup: if (err) { usx2y_subs_startup_finish(usx2y); - usx2y_clients_stop(usx2y); // something is completely wroong > stop evrything + usx2y_clients_stop(usx2y); // something is completely wrong > stop everything } return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index da643c2dbb12..db83522c1b49 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -480,7 +480,7 @@ static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs) cleanup: if (err) { usx2y_subs_startup_finish(usx2y); // Call it now - usx2y_clients_stop(usx2y); // something is completely wroong > stop evrything + usx2y_clients_stop(usx2y); // something is completely wrong > stop everything } return err; } diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 33b12aa67cf5..a34d7d9c2a57 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -236,7 +236,7 @@ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) * updating AUD_CONFIG register. * This is because: * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 - * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always + * HDMI IP. As a result a read-modify of AUD_CONFIG register will always * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the * register. This field should be 1xy binary for configuration with 6 or * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio) @@ -342,7 +342,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, /* * function to initialize audio - * registers and buffer confgiuration registers + * registers and buffer configuration registers * This function is called in the prepare callback */ static int had_init_audio_ctrl(struct snd_pcm_substream *substream, @@ -1790,7 +1790,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pcm->private_data = ctx; pcm->info_flags = 0; strscpy(pcm->name, card->shortname, strlen(card->shortname)); - /* setup the ops for playabck */ + /* setup the ops for playback */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops); /* allocate dma pages; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 0d91bb5dbab7..bb3853195922 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -96,7 +96,7 @@ struct pcm_stream_info { * @had_spinlock: driver lock * @aes_bits: IEC958 status bits * @buff_done: id of current buffer done intr - * @dev: platoform device handle + * @dev: platform device handle * @chmap: holds channel map info */ struct snd_intelhad { diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index f94f65d429be..1567a3294c3d 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -72,6 +72,9 @@ #define MADV_COLD 20 /* deactivate these pages */ #define MADV_PAGEOUT 21 /* reclaim these pages */ +#define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */ +#define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index d2a942086fcb..f211961ce1da 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -863,7 +863,8 @@ __SYSCALL(__NR_process_madvise, sys_process_madvise) __SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2) #define __NR_mount_setattr 442 __SYSCALL(__NR_mount_setattr, sys_mount_setattr) -/* 443 is reserved for quotactl_path */ +#define __NR_quotactl_fd 443 +__SYSCALL(__NR_quotactl_fd, sys_quotactl_fd) #define __NR_landlock_create_ruleset 444 __SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset) diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 67b94bc3c885..d043752a74cf 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -777,9 +777,12 @@ struct drm_get_cap { /** * DRM_CLIENT_CAP_STEREO_3D * - * if set to 1, the DRM core will expose the stereo 3D capabilities of the + * If set to 1, the DRM core will expose the stereo 3D capabilities of the * monitor by advertising the supported 3D layouts in the flags of struct - * drm_mode_modeinfo. + * drm_mode_modeinfo. See ``DRM_MODE_FLAG_3D_*``. + * + * This capability is always supported for all drivers starting from kernel + * version 3.13. */ #define DRM_CLIENT_CAP_STEREO_3D 1 @@ -788,6 +791,9 @@ struct drm_get_cap { * * If set to 1, the DRM core will expose all planes (overlay, primary, and * cursor) to userspace. + * + * This capability has been introduced in kernel version 3.15. Starting from + * kernel version 3.17, this capability is always supported for all drivers. */ #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 @@ -797,6 +803,13 @@ struct drm_get_cap { * If set to 1, the DRM core will expose atomic properties to userspace. This * implicitly enables &DRM_CLIENT_CAP_UNIVERSAL_PLANES and * &DRM_CLIENT_CAP_ASPECT_RATIO. + * + * If the driver doesn't support atomic mode-setting, enabling this capability + * will fail with -EOPNOTSUPP. + * + * This capability has been introduced in kernel version 4.0. Starting from + * kernel version 4.2, this capability is always supported for atomic-capable + * drivers. */ #define DRM_CLIENT_CAP_ATOMIC 3 @@ -804,6 +817,10 @@ struct drm_get_cap { * DRM_CLIENT_CAP_ASPECT_RATIO * * If set to 1, the DRM core will provide aspect ratio information in modes. + * See ``DRM_MODE_FLAG_PIC_AR_*``. + * + * This capability is always supported for all drivers starting from kernel + * version 4.18. */ #define DRM_CLIENT_CAP_ASPECT_RATIO 4 @@ -811,8 +828,11 @@ struct drm_get_cap { * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS * * If set to 1, the DRM core will expose special connectors to be used for - * writing back to memory the scene setup in the commit. Depends on client - * also supporting DRM_CLIENT_CAP_ATOMIC + * writing back to memory the scene setup in the commit. The client must enable + * &DRM_CLIENT_CAP_ATOMIC first. + * + * This capability is always supported for atomic-capable drivers starting from + * kernel version 4.19. */ #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index ddc47bbf48b6..c2c7759b7d2e 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -62,8 +62,8 @@ extern "C" { #define I915_ERROR_UEVENT "ERROR" #define I915_RESET_UEVENT "RESET" -/* - * i915_user_extension: Base class for defining a chain of extensions +/** + * struct i915_user_extension - Base class for defining a chain of extensions * * Many interfaces need to grow over time. In most cases we can simply * extend the struct and have userspace pass in more data. Another option, @@ -76,12 +76,58 @@ extern "C" { * increasing complexity, and for large parts of that interface to be * entirely optional. The downside is more pointer chasing; chasing across * the __user boundary with pointers encapsulated inside u64. + * + * Example chaining: + * + * .. code-block:: C + * + * struct i915_user_extension ext3 { + * .next_extension = 0, // end + * .name = ..., + * }; + * struct i915_user_extension ext2 { + * .next_extension = (uintptr_t)&ext3, + * .name = ..., + * }; + * struct i915_user_extension ext1 { + * .next_extension = (uintptr_t)&ext2, + * .name = ..., + * }; + * + * Typically the struct i915_user_extension would be embedded in some uAPI + * struct, and in this case we would feed it the head of the chain(i.e ext1), + * which would then apply all of the above extensions. + * */ struct i915_user_extension { + /** + * @next_extension: + * + * Pointer to the next struct i915_user_extension, or zero if the end. + */ __u64 next_extension; + /** + * @name: Name of the extension. + * + * Note that the name here is just some integer. + * + * Also note that the name space for this is not global for the whole + * driver, but rather its scope/meaning is limited to the specific piece + * of uAPI which has embedded the struct i915_user_extension. + */ __u32 name; - __u32 flags; /* All undefined bits must be zero. */ - __u32 rsvd[4]; /* Reserved for future use; must be zero. */ + /** + * @flags: MBZ + * + * All undefined bits must be zero. + */ + __u32 flags; + /** + * @rsvd: MBZ + * + * Reserved for future use; must be zero. + */ + __u32 rsvd[4]; }; /* @@ -360,6 +406,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_QUERY 0x39 #define DRM_I915_GEM_VM_CREATE 0x3a #define DRM_I915_GEM_VM_DESTROY 0x3b +#define DRM_I915_GEM_CREATE_EXT 0x3c /* Must be kept compact -- no holes */ #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) @@ -392,6 +439,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) #define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) #define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) +#define DRM_IOCTL_I915_GEM_CREATE_EXT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE_EXT, struct drm_i915_gem_create_ext) #define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) #define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) #define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) @@ -1054,12 +1102,12 @@ struct drm_i915_gem_exec_fence { __u32 flags; }; -/** +/* * See drm_i915_gem_execbuffer_ext_timeline_fences. */ #define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0 -/** +/* * This structure describes an array of drm_syncobj and associated points for * timeline variants of drm_syncobj. It is invalid to append this structure to * the execbuf if I915_EXEC_FENCE_ARRAY is set. @@ -1700,7 +1748,7 @@ struct drm_i915_gem_context_param { __u64 value; }; -/** +/* * Context SSEU programming * * It may be necessary for either functional or performance reason to configure @@ -2067,7 +2115,7 @@ struct drm_i915_perf_open_param { __u64 properties_ptr; }; -/** +/* * Enable data capture for a stream that was either opened in a disabled state * via I915_PERF_FLAG_DISABLED or was later disabled via * I915_PERF_IOCTL_DISABLE. @@ -2081,7 +2129,7 @@ struct drm_i915_perf_open_param { */ #define I915_PERF_IOCTL_ENABLE _IO('i', 0x0) -/** +/* * Disable data capture for a stream. * * It is an error to try and read a stream that is disabled. @@ -2090,7 +2138,7 @@ struct drm_i915_perf_open_param { */ #define I915_PERF_IOCTL_DISABLE _IO('i', 0x1) -/** +/* * Change metrics_set captured by a stream. * * If the stream is bound to a specific context, the configuration change @@ -2103,7 +2151,7 @@ struct drm_i915_perf_open_param { */ #define I915_PERF_IOCTL_CONFIG _IO('i', 0x2) -/** +/* * Common to all i915 perf records */ struct drm_i915_perf_record_header { @@ -2151,7 +2199,7 @@ enum drm_i915_perf_record_type { DRM_I915_PERF_RECORD_MAX /* non-ABI */ }; -/** +/* * Structure to upload perf dynamic configuration into the kernel. */ struct drm_i915_perf_oa_config { @@ -2172,53 +2220,95 @@ struct drm_i915_perf_oa_config { __u64 flex_regs_ptr; }; +/** + * struct drm_i915_query_item - An individual query for the kernel to process. + * + * The behaviour is determined by the @query_id. Note that exactly what + * @data_ptr is also depends on the specific @query_id. + */ struct drm_i915_query_item { + /** @query_id: The id for this query */ __u64 query_id; #define DRM_I915_QUERY_TOPOLOGY_INFO 1 #define DRM_I915_QUERY_ENGINE_INFO 2 #define DRM_I915_QUERY_PERF_CONFIG 3 +#define DRM_I915_QUERY_MEMORY_REGIONS 4 /* Must be kept compact -- no holes and well documented */ - /* + /** + * @length: + * * When set to zero by userspace, this is filled with the size of the - * data to be written at the data_ptr pointer. The kernel sets this + * data to be written at the @data_ptr pointer. The kernel sets this * value to a negative value to signal an error on a particular query * item. */ __s32 length; - /* + /** + * @flags: + * * When query_id == DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. * * When query_id == DRM_I915_QUERY_PERF_CONFIG, must be one of the - * following : - * - DRM_I915_QUERY_PERF_CONFIG_LIST - * - DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID - * - DRM_I915_QUERY_PERF_CONFIG_FOR_UUID + * following: + * + * - DRM_I915_QUERY_PERF_CONFIG_LIST + * - DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID + * - DRM_I915_QUERY_PERF_CONFIG_FOR_UUID */ __u32 flags; #define DRM_I915_QUERY_PERF_CONFIG_LIST 1 #define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID 2 #define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID 3 - /* - * Data will be written at the location pointed by data_ptr when the - * value of length matches the length of the data to be written by the + /** + * @data_ptr: + * + * Data will be written at the location pointed by @data_ptr when the + * value of @length matches the length of the data to be written by the * kernel. */ __u64 data_ptr; }; +/** + * struct drm_i915_query - Supply an array of struct drm_i915_query_item for the + * kernel to fill out. + * + * Note that this is generally a two step process for each struct + * drm_i915_query_item in the array: + * + * 1. Call the DRM_IOCTL_I915_QUERY, giving it our array of struct + * drm_i915_query_item, with &drm_i915_query_item.length set to zero. The + * kernel will then fill in the size, in bytes, which tells userspace how + * memory it needs to allocate for the blob(say for an array of properties). + * + * 2. Next we call DRM_IOCTL_I915_QUERY again, this time with the + * &drm_i915_query_item.data_ptr equal to our newly allocated blob. Note that + * the &drm_i915_query_item.length should still be the same as what the + * kernel previously set. At this point the kernel can fill in the blob. + * + * Note that for some query items it can make sense for userspace to just pass + * in a buffer/blob equal to or larger than the required size. In this case only + * a single ioctl call is needed. For some smaller query items this can work + * quite well. + * + */ struct drm_i915_query { + /** @num_items: The number of elements in the @items_ptr array */ __u32 num_items; - /* - * Unused for now. Must be cleared to zero. + /** + * @flags: Unused for now. Must be cleared to zero. */ __u32 flags; - /* - * This points to an array of num_items drm_i915_query_item structures. + /** + * @items_ptr: + * + * Pointer to an array of struct drm_i915_query_item. The number of + * array elements is @num_items. */ __u64 items_ptr; }; @@ -2292,21 +2382,21 @@ struct drm_i915_query_topology_info { * Describes one engine and it's capabilities as known to the driver. */ struct drm_i915_engine_info { - /** Engine class and instance. */ + /** @engine: Engine class and instance. */ struct i915_engine_class_instance engine; - /** Reserved field. */ + /** @rsvd0: Reserved field. */ __u32 rsvd0; - /** Engine flags. */ + /** @flags: Engine flags. */ __u64 flags; - /** Capabilities of this engine. */ + /** @capabilities: Capabilities of this engine. */ __u64 capabilities; #define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) #define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) - /** Reserved fields. */ + /** @rsvd1: Reserved fields. */ __u64 rsvd1[4]; }; @@ -2317,13 +2407,13 @@ struct drm_i915_engine_info { * an array of struct drm_i915_engine_info structures. */ struct drm_i915_query_engine_info { - /** Number of struct drm_i915_engine_info structs following. */ + /** @num_engines: Number of struct drm_i915_engine_info structs following. */ __u32 num_engines; - /** MBZ */ + /** @rsvd: MBZ */ __u32 rsvd[3]; - /** Marker for drm_i915_engine_info structures. */ + /** @engines: Marker for drm_i915_engine_info structures. */ struct drm_i915_engine_info engines[]; }; @@ -2377,6 +2467,241 @@ struct drm_i915_query_perf_config { __u8 data[]; }; +/** + * enum drm_i915_gem_memory_class - Supported memory classes + */ +enum drm_i915_gem_memory_class { + /** @I915_MEMORY_CLASS_SYSTEM: System memory */ + I915_MEMORY_CLASS_SYSTEM = 0, + /** @I915_MEMORY_CLASS_DEVICE: Device local-memory */ + I915_MEMORY_CLASS_DEVICE, +}; + +/** + * struct drm_i915_gem_memory_class_instance - Identify particular memory region + */ +struct drm_i915_gem_memory_class_instance { + /** @memory_class: See enum drm_i915_gem_memory_class */ + __u16 memory_class; + + /** @memory_instance: Which instance */ + __u16 memory_instance; +}; + +/** + * struct drm_i915_memory_region_info - Describes one region as known to the + * driver. + * + * Note that we reserve some stuff here for potential future work. As an example + * we might want expose the capabilities for a given region, which could include + * things like if the region is CPU mappable/accessible, what are the supported + * mapping types etc. + * + * Note that to extend struct drm_i915_memory_region_info and struct + * drm_i915_query_memory_regions in the future the plan is to do the following: + * + * .. code-block:: C + * + * struct drm_i915_memory_region_info { + * struct drm_i915_gem_memory_class_instance region; + * union { + * __u32 rsvd0; + * __u32 new_thing1; + * }; + * ... + * union { + * __u64 rsvd1[8]; + * struct { + * __u64 new_thing2; + * __u64 new_thing3; + * ... + * }; + * }; + * }; + * + * With this things should remain source compatible between versions for + * userspace, even as we add new fields. + * + * Note this is using both struct drm_i915_query_item and struct drm_i915_query. + * For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS + * at &drm_i915_query_item.query_id. + */ +struct drm_i915_memory_region_info { + /** @region: The class:instance pair encoding */ + struct drm_i915_gem_memory_class_instance region; + + /** @rsvd0: MBZ */ + __u32 rsvd0; + + /** @probed_size: Memory probed by the driver (-1 = unknown) */ + __u64 probed_size; + + /** @unallocated_size: Estimate of memory remaining (-1 = unknown) */ + __u64 unallocated_size; + + /** @rsvd1: MBZ */ + __u64 rsvd1[8]; +}; + +/** + * struct drm_i915_query_memory_regions + * + * The region info query enumerates all regions known to the driver by filling + * in an array of struct drm_i915_memory_region_info structures. + * + * Example for getting the list of supported regions: + * + * .. code-block:: C + * + * struct drm_i915_query_memory_regions *info; + * struct drm_i915_query_item item = { + * .query_id = DRM_I915_QUERY_MEMORY_REGIONS; + * }; + * struct drm_i915_query query = { + * .num_items = 1, + * .items_ptr = (uintptr_t)&item, + * }; + * int err, i; + * + * // First query the size of the blob we need, this needs to be large + * // enough to hold our array of regions. The kernel will fill out the + * // item.length for us, which is the number of bytes we need. + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * info = calloc(1, item.length); + * // Now that we allocated the required number of bytes, we call the ioctl + * // again, this time with the data_ptr pointing to our newly allocated + * // blob, which the kernel can then populate with the all the region info. + * item.data_ptr = (uintptr_t)&info, + * + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * // We can now access each region in the array + * for (i = 0; i < info->num_regions; i++) { + * struct drm_i915_memory_region_info mr = info->regions[i]; + * u16 class = mr.region.class; + * u16 instance = mr.region.instance; + * + * .... + * } + * + * free(info); + */ +struct drm_i915_query_memory_regions { + /** @num_regions: Number of supported regions */ + __u32 num_regions; + + /** @rsvd: MBZ */ + __u32 rsvd[3]; + + /** @regions: Info about each supported region */ + struct drm_i915_memory_region_info regions[]; +}; + +/** + * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added + * extension support using struct i915_user_extension. + * + * Note that in the future we want to have our buffer flags here, at least for + * the stuff that is immutable. Previously we would have two ioctls, one to + * create the object with gem_create, and another to apply various parameters, + * however this creates some ambiguity for the params which are considered + * immutable. Also in general we're phasing out the various SET/GET ioctls. + */ +struct drm_i915_gem_create_ext { + /** + * @size: Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + * + * Note that for some devices we have might have further minimum + * page-size restrictions(larger than 4K), like for device local-memory. + * However in general the final size here should always reflect any + * rounding up, if for example using the I915_GEM_CREATE_EXT_MEMORY_REGIONS + * extension to place the object in device local-memory. + */ + __u64 size; + /** + * @handle: Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; + /** @flags: MBZ */ + __u32 flags; + /** + * @extensions: The chain of extensions to apply to this object. + * + * This will be useful in the future when we need to support several + * different extensions, and we need to apply more than one when + * creating the object. See struct i915_user_extension. + * + * If we don't supply any extensions then we get the same old gem_create + * behaviour. + * + * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see + * struct drm_i915_gem_create_ext_memory_regions. + */ +#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0 + __u64 extensions; +}; + +/** + * struct drm_i915_gem_create_ext_memory_regions - The + * I915_GEM_CREATE_EXT_MEMORY_REGIONS extension. + * + * Set the object with the desired set of placements/regions in priority + * order. Each entry must be unique and supported by the device. + * + * This is provided as an array of struct drm_i915_gem_memory_class_instance, or + * an equivalent layout of class:instance pair encodings. See struct + * drm_i915_query_memory_regions and DRM_I915_QUERY_MEMORY_REGIONS for how to + * query the supported regions for a device. + * + * As an example, on discrete devices, if we wish to set the placement as + * device local-memory we can do something like: + * + * .. code-block:: C + * + * struct drm_i915_gem_memory_class_instance region_lmem = { + * .memory_class = I915_MEMORY_CLASS_DEVICE, + * .memory_instance = 0, + * }; + * struct drm_i915_gem_create_ext_memory_regions regions = { + * .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS }, + * .regions = (uintptr_t)®ion_lmem, + * .num_regions = 1, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = 16 * PAGE_SIZE, + * .extensions = (uintptr_t)®ions, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + * + * At which point we get the object handle in &drm_i915_gem_create_ext.handle, + * along with the final object size in &drm_i915_gem_create_ext.size, which + * should account for any rounding up, if required. + */ +struct drm_i915_gem_create_ext_memory_regions { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** @pad: MBZ */ + __u32 pad; + /** @num_regions: Number of elements in the @regions array. */ + __u32 num_regions; + /** + * @regions: The regions/placements array. + * + * An array of struct drm_i915_gem_memory_class_instance. + */ + __u64 regions; +}; + #if defined(__cplusplus) } #endif diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h index 535a7229e1d9..d17c061950df 100644 --- a/tools/include/uapi/sound/asound.h +++ b/tools/include/uapi/sound/asound.h @@ -710,7 +710,7 @@ enum { * Raw MIDI section - /dev/snd/midi?? */ -#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1) +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) enum { SNDRV_RAWMIDI_STREAM_OUTPUT = 0, @@ -736,12 +736,38 @@ struct snd_rawmidi_info { unsigned char reserved[64]; /* reserved for future use */ }; +#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0) +#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0 +#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0) +#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0) +#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3 +#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3) + +#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16 + +struct snd_rawmidi_framing_tstamp { + /* For now, frame_type is always 0. Midi 2.0 is expected to add new + * types here. Applications are expected to skip unknown frame types. + */ + __u8 frame_type; + __u8 length; /* number of valid bytes in data field */ + __u8 reserved[2]; + __u32 tv_nsec; /* nanoseconds */ + __u64 tv_sec; /* seconds */ + __u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH]; +} __packed; + struct snd_rawmidi_params { int stream; size_t buffer_size; /* queue size in bytes */ size_t avail_min; /* minimum avail bytes for wakeup */ unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */ - unsigned char reserved[16]; /* reserved for future use */ + unsigned int mode; /* For input data only, frame incoming data */ + unsigned char reserved[12]; /* reserved for future use */ }; #ifndef __KERNEL__ diff --git a/tools/lib/perf/Build b/tools/lib/perf/Build index 2ef9a4ec6d99..e8f5b7fb9973 100644 --- a/tools/lib/perf/Build +++ b/tools/lib/perf/Build @@ -11,3 +11,5 @@ libperf-y += lib.o $(OUTPUT)zalloc.o: ../../lib/zalloc.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) + +tests-y += tests/ diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile index 3718d65cffac..08fe6e3c4089 100644 --- a/tools/lib/perf/Makefile +++ b/tools/lib/perf/Makefile @@ -52,6 +52,8 @@ else Q = @ endif +TEST_ARGS := $(if $(V),-v) + # Set compile option CFLAGS ifdef EXTRA_CFLAGS CFLAGS := $(EXTRA_CFLAGS) @@ -136,12 +138,30 @@ all: fixdep clean: $(LIBAPI)-clean $(call QUIET_CLEAN, libperf) $(RM) $(LIBPERF_A) \ - *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd LIBPERF-CFLAGS $(LIBPERF_PC) - $(Q)$(MAKE) -C tests clean + *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd tests/*.o LIBPERF-CFLAGS $(LIBPERF_PC) \ + $(TESTS_STATIC) $(TESTS_SHARED) -tests: libs - $(Q)$(MAKE) -C tests - $(Q)$(MAKE) -C tests run +TESTS_IN = tests-in.o + +TESTS_STATIC = $(OUTPUT)tests-static +TESTS_SHARED = $(OUTPUT)tests-shared + +$(TESTS_IN): FORCE + $(Q)$(MAKE) $(build)=tests + +$(TESTS_STATIC): $(TESTS_IN) $(LIBPERF_A) $(LIBAPI) + $(QUIET_LINK)$(CC) -o $@ $^ + +$(TESTS_SHARED): $(TESTS_IN) $(LIBAPI) + $(QUIET_LINK)$(CC) -o $@ -L$(if $(OUTPUT),$(OUTPUT),.) $^ -lperf + +make-tests: libs $(TESTS_SHARED) $(TESTS_STATIC) + +tests: make-tests + @echo "running static:" + @./$(TESTS_STATIC) $(TEST_ARGS) + @echo "running dynamic:" + @LD_LIBRARY_PATH=. ./$(TESTS_SHARED) $(TEST_ARGS) $(LIBPERF_PC): $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c index a0aaf385cbb5..e37dfad31383 100644 --- a/tools/lib/perf/evlist.c +++ b/tools/lib/perf/evlist.c @@ -66,6 +66,7 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *evsel) { + evsel->idx = evlist->nr_entries; list_add_tail(&evsel->node, &evlist->entries); evlist->nr_entries += 1; __perf_evlist__propagate_maps(evlist, evsel); @@ -641,3 +642,24 @@ perf_evlist__next_mmap(struct perf_evlist *evlist, struct perf_mmap *map, return overwrite ? evlist->mmap_ovw_first : evlist->mmap_first; } + +void __perf_evlist__set_leader(struct list_head *list) +{ + struct perf_evsel *evsel, *leader; + + leader = list_entry(list->next, struct perf_evsel, node); + evsel = list_entry(list->prev, struct perf_evsel, node); + + leader->nr_members = evsel->idx - leader->idx + 1; + + __perf_evlist__for_each_entry(list, evsel) + evsel->leader = leader; +} + +void perf_evlist__set_leader(struct perf_evlist *evlist) +{ + if (evlist->nr_entries) { + evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; + __perf_evlist__set_leader(&evlist->entries); + } +} diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c index bd8c2f19ef74..d8886720e83d 100644 --- a/tools/lib/perf/evsel.c +++ b/tools/lib/perf/evsel.c @@ -17,11 +17,15 @@ #include #include #include +#include -void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr) +void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, + int idx) { INIT_LIST_HEAD(&evsel->node); evsel->attr = *attr; + evsel->idx = idx; + evsel->leader = evsel; } struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) @@ -29,7 +33,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) struct perf_evsel *evsel = zalloc(sizeof(*evsel)); if (evsel != NULL) - perf_evsel__init(evsel, attr); + perf_evsel__init(evsel, attr, 0); return evsel; } @@ -73,6 +77,32 @@ sys_perf_event_open(struct perf_event_attr *attr, return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); } +static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd) +{ + struct perf_evsel *leader = evsel->leader; + int fd; + + if (evsel == leader) { + *group_fd = -1; + return 0; + } + + /* + * Leader must be already processed/open, + * if not it's a bug. + */ + if (!leader->fd) + return -ENOTCONN; + + fd = FD(leader, cpu, thread); + if (fd == -1) + return -EBADF; + + *group_fd = fd; + + return 0; +} + int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, struct perf_thread_map *threads) { @@ -108,11 +138,15 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, for (cpu = 0; cpu < cpus->nr; cpu++) { for (thread = 0; thread < threads->nr; thread++) { - int fd; + int fd, group_fd; + + err = get_group_fd(evsel, cpu, thread, &group_fd); + if (err < 0) + return err; fd = sys_perf_event_open(&evsel->attr, threads->map[thread].pid, - cpus->map[cpu], -1, 0); + cpus->map[cpu], group_fd, 0); if (fd < 0) return -errno; diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h index 212c29063ad4..f366dbad6a88 100644 --- a/tools/lib/perf/include/internal/evlist.h +++ b/tools/lib/perf/include/internal/evlist.h @@ -16,6 +16,7 @@ struct perf_mmap_param; struct perf_evlist { struct list_head entries; int nr_entries; + int nr_groups; bool has_user_cpus; struct perf_cpu_map *cpus; struct perf_cpu_map *all_cpus; @@ -126,4 +127,5 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, void perf_evlist__reset_id_hash(struct perf_evlist *evlist); +void __perf_evlist__set_leader(struct list_head *list); #endif /* __LIBPERF_INTERNAL_EVLIST_H */ diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h index 1c067d088bc6..1f3eacbad2e8 100644 --- a/tools/lib/perf/include/internal/evsel.h +++ b/tools/lib/perf/include/internal/evsel.h @@ -45,13 +45,16 @@ struct perf_evsel { struct xyarray *sample_id; u64 *id; u32 ids; + struct perf_evsel *leader; /* parse modifier helper */ int nr_members; bool system_wide; + int idx; }; -void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr); +void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, + int idx); int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); void perf_evsel__close_fd(struct perf_evsel *evsel); void perf_evsel__free_fd(struct perf_evsel *evsel); diff --git a/tools/lib/perf/include/internal/tests.h b/tools/lib/perf/include/internal/tests.h index 29425c2dabe1..61052099225b 100644 --- a/tools/lib/perf/include/internal/tests.h +++ b/tools/lib/perf/include/internal/tests.h @@ -5,8 +5,8 @@ #include #include -int tests_failed; -int tests_verbose; +extern int tests_failed; +extern int tests_verbose; static inline int get_verbose(char **argv, int argc) { diff --git a/tools/lib/perf/include/perf/evlist.h b/tools/lib/perf/include/perf/evlist.h index 0a7479dc13bf..9ca399d49bb4 100644 --- a/tools/lib/perf/include/perf/evlist.h +++ b/tools/lib/perf/include/perf/evlist.h @@ -46,4 +46,5 @@ LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist, (pos) != NULL; \ (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite)) +LIBPERF_API void perf_evlist__set_leader(struct perf_evlist *evlist); #endif /* __LIBPERF_EVLIST_H */ diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map index c0c7ceb11060..71468606e8a7 100644 --- a/tools/lib/perf/libperf.map +++ b/tools/lib/perf/libperf.map @@ -45,6 +45,7 @@ LIBPERF_0.0.1 { perf_evlist__munmap; perf_evlist__filter_pollfd; perf_evlist__next_mmap; + perf_evlist__set_leader; perf_mmap__consume; perf_mmap__read_init; perf_mmap__read_done; diff --git a/tools/lib/perf/tests/Build b/tools/lib/perf/tests/Build new file mode 100644 index 000000000000..56e81378d443 --- /dev/null +++ b/tools/lib/perf/tests/Build @@ -0,0 +1,5 @@ +tests-y += main.o +tests-y += test-evsel.o +tests-y += test-evlist.o +tests-y += test-cpumap.o +tests-y += test-threadmap.o diff --git a/tools/lib/perf/tests/Makefile b/tools/lib/perf/tests/Makefile deleted file mode 100644 index b536cc9a26dd..000000000000 --- a/tools/lib/perf/tests/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) - -TESTS = test-cpumap test-threadmap test-evlist test-evsel - -TESTS_SO := $(addsuffix -so,$(TESTS)) -TESTS_A := $(addsuffix -a,$(TESTS)) - -TEST_ARGS := $(if $(V),-v) - -# Set compile option CFLAGS -ifdef EXTRA_CFLAGS - CFLAGS := $(EXTRA_CFLAGS) -else - CFLAGS := -g -Wall -endif - -all: - -include $(srctree)/tools/scripts/Makefile.include - -INCLUDE = -I$(srctree)/tools/lib/perf/include -I$(srctree)/tools/include -I$(srctree)/tools/lib - -$(TESTS_A): FORCE - $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI) - -$(TESTS_SO): FORCE - $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) $(LIBAPI) -lperf - -all: $(TESTS_A) $(TESTS_SO) - -run: - @echo "running static:" - @for i in $(TESTS_A); do ./$$i $(TEST_ARGS); done - @echo "running dynamic:" - @for i in $(TESTS_SO); do LD_LIBRARY_PATH=../ ./$$i $(TEST_ARGS); done - -clean: - $(call QUIET_CLEAN, tests)$(RM) $(TESTS_A) $(TESTS_SO) - -.PHONY: all clean FORCE diff --git a/tools/lib/perf/tests/main.c b/tools/lib/perf/tests/main.c new file mode 100644 index 000000000000..56423fd4db19 --- /dev/null +++ b/tools/lib/perf/tests/main.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "tests.h" + +int tests_failed; +int tests_verbose; + +int main(int argc, char **argv) +{ + __T("test cpumap", !test_cpumap(argc, argv)); + __T("test threadmap", !test_threadmap(argc, argv)); + __T("test evlist", !test_evlist(argc, argv)); + __T("test evsel", !test_evsel(argc, argv)); + return 0; +} diff --git a/tools/lib/perf/tests/test-cpumap.c b/tools/lib/perf/tests/test-cpumap.c index c70e9e03af3e..d39378eaf897 100644 --- a/tools/lib/perf/tests/test-cpumap.c +++ b/tools/lib/perf/tests/test-cpumap.c @@ -3,6 +3,7 @@ #include #include #include +#include "tests.h" static int libperf_print(enum libperf_print_level level, const char *fmt, va_list ap) @@ -10,7 +11,7 @@ static int libperf_print(enum libperf_print_level level, return vfprintf(stderr, fmt, ap); } -int main(int argc, char **argv) +int test_cpumap(int argc, char **argv) { struct perf_cpu_map *cpus; diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c index e2ac0b7f432e..c67c83399170 100644 --- a/tools/lib/perf/tests/test-evlist.c +++ b/tools/lib/perf/tests/test-evlist.c @@ -18,6 +18,8 @@ #include #include #include +#include "tests.h" +#include static int libperf_print(enum libperf_print_level level, const char *fmt, va_list ap) @@ -29,7 +31,7 @@ static int test_stat_cpu(void) { struct perf_cpu_map *cpus; struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct perf_evsel *evsel, *leader; struct perf_event_attr attr1 = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, @@ -46,7 +48,7 @@ static int test_stat_cpu(void) evlist = perf_evlist__new(); __T("failed to create evlist", evlist); - evsel = perf_evsel__new(&attr1); + evsel = leader = perf_evsel__new(&attr1); __T("failed to create evsel1", evsel); perf_evlist__add(evlist, evsel); @@ -56,6 +58,10 @@ static int test_stat_cpu(void) perf_evlist__add(evlist, evsel); + perf_evlist__set_leader(evlist); + __T("failed to set leader", leader->leader == leader); + __T("failed to set leader", evsel->leader == leader); + perf_evlist__set_maps(evlist, cpus, NULL); err = perf_evlist__open(evlist); @@ -84,7 +90,7 @@ static int test_stat_thread(void) struct perf_counts_values counts = { .val = 0 }; struct perf_thread_map *threads; struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct perf_evsel *evsel, *leader; struct perf_event_attr attr1 = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, @@ -103,7 +109,7 @@ static int test_stat_thread(void) evlist = perf_evlist__new(); __T("failed to create evlist", evlist); - evsel = perf_evsel__new(&attr1); + evsel = leader = perf_evsel__new(&attr1); __T("failed to create evsel1", evsel); perf_evlist__add(evlist, evsel); @@ -113,6 +119,10 @@ static int test_stat_thread(void) perf_evlist__add(evlist, evsel); + perf_evlist__set_leader(evlist); + __T("failed to set leader", leader->leader == leader); + __T("failed to set leader", evsel->leader == leader); + perf_evlist__set_maps(evlist, NULL, threads); err = perf_evlist__open(evlist); @@ -135,7 +145,7 @@ static int test_stat_thread_enable(void) struct perf_counts_values counts = { .val = 0 }; struct perf_thread_map *threads; struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct perf_evsel *evsel, *leader; struct perf_event_attr attr1 = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, @@ -156,7 +166,7 @@ static int test_stat_thread_enable(void) evlist = perf_evlist__new(); __T("failed to create evlist", evlist); - evsel = perf_evsel__new(&attr1); + evsel = leader = perf_evsel__new(&attr1); __T("failed to create evsel1", evsel); perf_evlist__add(evlist, evsel); @@ -166,6 +176,10 @@ static int test_stat_thread_enable(void) perf_evlist__add(evlist, evsel); + perf_evlist__set_leader(evlist); + __T("failed to set leader", leader->leader == leader); + __T("failed to set leader", evsel->leader == leader); + perf_evlist__set_maps(evlist, NULL, threads); err = perf_evlist__open(evlist); @@ -253,6 +267,7 @@ static int test_mmap_thread(void) evsel = perf_evsel__new(&attr); __T("failed to create evsel1", evsel); + __T("failed to set leader", evsel->leader == evsel); perf_evlist__add(evlist, evsel); @@ -338,6 +353,7 @@ static int test_mmap_cpus(void) evsel = perf_evsel__new(&attr); __T("failed to create evsel1", evsel); + __T("failed to set leader", evsel->leader == evsel); perf_evlist__add(evlist, evsel); @@ -397,7 +413,7 @@ static int test_mmap_cpus(void) return 0; } -int main(int argc, char **argv) +int test_evlist(int argc, char **argv) { __T_START; diff --git a/tools/lib/perf/tests/test-evsel.c b/tools/lib/perf/tests/test-evsel.c index 288b5feaefe2..a184e4861627 100644 --- a/tools/lib/perf/tests/test-evsel.c +++ b/tools/lib/perf/tests/test-evsel.c @@ -6,6 +6,7 @@ #include #include #include +#include "tests.h" static int libperf_print(enum libperf_print_level level, const char *fmt, va_list ap) @@ -184,7 +185,7 @@ static int test_stat_user_read(int event) return 0; } -int main(int argc, char **argv) +int test_evsel(int argc, char **argv) { __T_START; diff --git a/tools/lib/perf/tests/test-threadmap.c b/tools/lib/perf/tests/test-threadmap.c index 384471441b48..5e2a0291e94c 100644 --- a/tools/lib/perf/tests/test-threadmap.c +++ b/tools/lib/perf/tests/test-threadmap.c @@ -3,6 +3,7 @@ #include #include #include +#include "tests.h" static int libperf_print(enum libperf_print_level level, const char *fmt, va_list ap) @@ -10,7 +11,7 @@ static int libperf_print(enum libperf_print_level level, return vfprintf(stderr, fmt, ap); } -int main(int argc, char **argv) +int test_threadmap(int argc, char **argv) { struct perf_thread_map *threads; diff --git a/tools/lib/perf/tests/tests.h b/tools/lib/perf/tests/tests.h new file mode 100644 index 000000000000..604838f21b2b --- /dev/null +++ b/tools/lib/perf/tests/tests.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef TESTS_H +#define TESTS_H + +int test_cpumap(int argc, char **argv); +int test_threadmap(int argc, char **argv); +int test_evlist(int argc, char **argv); +int test_evsel(int argc, char **argv); + +#endif /* TESTS_H */ diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index b0872c801866..3bb75c1f25e8 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -706,6 +706,12 @@ intel-pt.*:: If set, Intel PT decoder will set the mispred flag on all branches. + intel-pt.max-loops:: + If set and non-zero, the maximum number of unconditional + branches decoded without consuming any trace packets. If + the maximum is exceeded there will be a "Never-ending loop" + error. The default is 100000. + auxtrace.*:: auxtrace.dumpdir:: diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index c9e0de5b00c1..77e7f18c0bd0 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -923,7 +923,7 @@ install-tools: all install-gtk $(call QUIET_INSTALL, binaries) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ - $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(dir_SQ)/trace'; \ + $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'; \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(includedir_SQ)/perf'; \ $(INSTALL) util/perf_dlfilter.h -t '$(DESTDIR_SQ)$(includedir_SQ)/perf' ifndef NO_PERF_READ_VDSO32 @@ -1017,6 +1017,7 @@ SKEL_OUT := $(abspath $(OUTPUT)util/bpf_skel) SKEL_TMP_OUT := $(abspath $(SKEL_OUT)/.tmp) SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h +SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h ifdef BUILD_BPF_SKEL BPFTOOL := $(SKEL_TMP_OUT)/bootstrap/bpftool @@ -1030,7 +1031,21 @@ $(BPFTOOL): | $(SKEL_TMP_OUT) CFLAGS= $(MAKE) -C ../bpf/bpftool \ OUTPUT=$(SKEL_TMP_OUT)/ bootstrap -$(SKEL_TMP_OUT)/%.bpf.o: util/bpf_skel/%.bpf.c $(LIBBPF) | $(SKEL_TMP_OUT) +VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ + $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ + ../../vmlinux \ + /sys/kernel/btf/vmlinux \ + /boot/vmlinux-$(shell uname -r) +VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) + +$(SKEL_OUT)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) +ifeq ($(VMLINUX_H),) + $(QUIET_GEN)$(BPFTOOL) btf dump file $< format c > $@ +else + $(Q)cp "$(VMLINUX_H)" $@ +endif + +$(SKEL_TMP_OUT)/%.bpf.o: util/bpf_skel/%.bpf.c $(LIBBPF) $(SKEL_OUT)/vmlinux.h | $(SKEL_TMP_OUT) $(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -Wall -Werror $(BPF_INCLUDE) \ -c $(filter util/bpf_skel/%.bpf.c,$^) -o $@ && $(LLVM_STRIP) -g $@ diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl index 9cd1c34f31b5..ac653d08b1ea 100644 --- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl +++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl @@ -357,7 +357,7 @@ 440 n64 process_madvise sys_process_madvise 441 n64 epoll_pwait2 sys_epoll_pwait2 442 n64 mount_setattr sys_mount_setattr -# 443 reserved for quotactl_path +443 n64 quotactl_fd sys_quotactl_fd 444 n64 landlock_create_ruleset sys_landlock_create_ruleset 445 n64 landlock_add_rule sys_landlock_add_rule 446 n64 landlock_restrict_self sys_landlock_restrict_self diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index 8f052ff4058c..aef2a290e71a 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -522,7 +522,7 @@ 440 common process_madvise sys_process_madvise 441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 442 common mount_setattr sys_mount_setattr -# 443 reserved for quotactl_path +443 common quotactl_fd sys_quotactl_fd 444 common landlock_create_ruleset sys_landlock_create_ruleset 445 common landlock_add_rule sys_landlock_add_rule 446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl index 0690263df1dd..64d51ab5a8b4 100644 --- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl @@ -445,7 +445,7 @@ 440 common process_madvise sys_process_madvise sys_process_madvise 441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2 442 common mount_setattr sys_mount_setattr sys_mount_setattr -# 443 reserved for quotactl_path +443 common quotactl_fd sys_quotactl_fd sys_quotactl_fd 444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset 445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule 446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index ce18119ea0d0..af973e400053 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -364,7 +364,7 @@ 440 common process_madvise sys_process_madvise 441 common epoll_pwait2 sys_epoll_pwait2 442 common mount_setattr sys_mount_setattr -# 443 reserved for quotactl_path +443 common quotactl_fd sys_quotactl_fd 444 common landlock_create_ruleset sys_landlock_create_ruleset 445 common landlock_add_rule sys_landlock_add_rule 446 common landlock_restrict_self sys_landlock_restrict_self diff --git a/tools/perf/arch/x86/util/evlist.c b/tools/perf/arch/x86/util/evlist.c index 8c6732cc7794..0b0951030a2f 100644 --- a/tools/perf/arch/x86/util/evlist.c +++ b/tools/perf/arch/x86/util/evlist.c @@ -5,11 +5,15 @@ #include "util/parse-events.h" #define TOPDOWN_L1_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound}" +#define TOPDOWN_L2_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound,topdown-heavy-ops,topdown-br-mispredict,topdown-fetch-lat,topdown-mem-bound}" int arch_evlist__add_default_attrs(struct evlist *evlist) { if (!pmu_have_event("cpu", "slots")) return 0; - return parse_events(evlist, TOPDOWN_L1_EVENTS, NULL); + if (pmu_have_event("cpu", "topdown-heavy-ops")) + return parse_events(evlist, TOPDOWN_L2_EVENTS, NULL); + else + return parse_events(evlist, TOPDOWN_L1_EVENTS, NULL); } diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c index d63acb782b63..eeafe97b8105 100644 --- a/tools/perf/arch/x86/util/iostat.c +++ b/tools/perf/arch/x86/util/iostat.c @@ -322,7 +322,7 @@ static int iostat_event_group(struct evlist *evl, } evlist__for_each_entry(evl, evsel) { - evsel->priv = list->rps[evsel->idx / metrics_count]; + evsel->priv = list->rps[evsel->core.idx / metrics_count]; } list->nr_entries = 0; err: @@ -428,7 +428,7 @@ void iostat_print_metric(struct perf_stat_config *config, struct evsel *evsel, { double iostat_value = 0; u64 prev_count_val = 0; - const char *iostat_metric = iostat_metric_by_idx(evsel->idx); + const char *iostat_metric = iostat_metric_by_idx(evsel->core.idx); u8 die = ((struct iio_root_port *)evsel->priv)->die; struct perf_counts_values *count = perf_counts(evsel->counts, die, 0); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index f52b3a799e76..80450c0e8f36 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1031,12 +1031,12 @@ static int process_base_stream(struct data__file *data_base, continue; es_base = evsel_streams__entry(data_base->evlist_streams, - evsel_base->idx); + evsel_base->core.idx); if (!es_base) return -1; es_pair = evsel_streams__entry(data_pair->evlist_streams, - evsel_pair->idx); + evsel_pair->core.idx); if (!es_pair) return -1; diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 2bfd41df621c..e1dd51f2874b 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -31,7 +31,7 @@ #include #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" -#define DEFAULT_FUNC_FILTER "!_*" +#define DEFAULT_FUNC_FILTER "!_* & !*@plt" #define DEFAULT_LIST_FILTER "*" /* Session management structure */ diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 71efe6573ee7..671a21c9ee4d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -891,11 +891,12 @@ static int record__open(struct record *rec) int rc = 0; /* - * For initial_delay or system wide, we need to add a dummy event so - * that we can track PERF_RECORD_MMAP to cover the delay of waiting or - * event synthesis. + * For initial_delay, system wide or a hybrid system, we need to add a + * dummy event so that we can track PERF_RECORD_MMAP to cover the delay + * of waiting or event synthesis. */ - if (opts->initial_delay || target__has_cpu(&opts->target)) { + if (opts->initial_delay || target__has_cpu(&opts->target) || + perf_pmu__has_hybrid()) { pos = evlist__get_tracking_event(evlist); if (!evsel__is_dummy_event(pos)) { /* Set up dummy event. */ @@ -926,7 +927,7 @@ try_again: goto try_again; } if ((errno == EINVAL || errno == EBADF) && - pos->leader != pos && + pos->core.leader != &pos->core && pos->weak_group) { pos = evlist__reset_weak_group(evlist, pos, true); goto try_again; @@ -1776,7 +1777,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) rec->tool.ordered_events = false; } - if (!rec->evlist->nr_groups) + if (!rec->evlist->core.nr_groups) perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); if (data->is_pipe) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bc5c393021dc..6386af6a2612 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -332,7 +332,7 @@ static int process_read_event(struct perf_tool *tool, const char *name = evsel__name(evsel); int err = perf_read_values_add_value(&rep->show_threads_values, event->read.pid, event->read.tid, - evsel->idx, + evsel->core.idx, name, event->read.value); @@ -666,7 +666,7 @@ static int report__collapse_hists(struct report *rep) evlist__for_each_entry(rep->session->evlist, pos) { struct hists *hists = evsel__hists(pos); - if (pos->idx == 0) + if (pos->core.idx == 0) hists->symbol_filter_str = rep->symbol_filter_str; hists->socket_filter = rep->socket_filter; @@ -677,7 +677,7 @@ static int report__collapse_hists(struct report *rep) /* Non-group events are considered as leader */ if (symbol_conf.event_group && !evsel__is_group_leader(pos)) { - struct hists *leader_hists = evsel__hists(pos->leader); + struct hists *leader_hists = evsel__hists(evsel__leader(pos)); hists__match(leader_hists, hists); hists__link(leader_hists, hists); @@ -729,9 +729,14 @@ static int count_sample_event(struct perf_tool *tool __maybe_unused, return 0; } +static int process_attr(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct evlist **pevlist); + static void stats_setup(struct report *rep) { memset(&rep->tool, 0, sizeof(rep->tool)); + rep->tool.attr = process_attr; rep->tool.sample = count_sample_event; rep->tool.no_warn = true; } @@ -753,6 +758,7 @@ static void tasks_setup(struct report *rep) rep->tool.mmap = perf_event__process_mmap; rep->tool.mmap2 = perf_event__process_mmap2; } + rep->tool.attr = process_attr; rep->tool.comm = perf_event__process_comm; rep->tool.exit = perf_event__process_exit; rep->tool.fork = perf_event__process_fork; @@ -1426,7 +1432,7 @@ repeat: setup_forced_leader(&report, session->evlist); - if (symbol_conf.group_sort_idx && !session->evlist->nr_groups) { + if (symbol_conf.group_sort_idx && !session->evlist->core.nr_groups) { parse_options_usage(NULL, options, "group-sort-idx", 0); ret = -EINVAL; goto error; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2030936cc891..8c03a9862872 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1899,6 +1899,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, struct perf_sample *sample, FILE *fp) { + struct evsel *leader = evsel__leader(evsel); struct perf_stat_output_ctx ctx = { .print_metric = script_print_metric, .new_line = script_new_line, @@ -1915,7 +1916,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, if (!evsel->stats) evlist__alloc_stats(script->session->evlist, false); - if (evsel_script(evsel->leader)->gnum++ == 0) + if (evsel_script(leader)->gnum++ == 0) perf_stat__reset_shadow_stats(); val = sample->period * evsel->scale; perf_stat__update_shadow_stats(evsel, @@ -1923,8 +1924,8 @@ static void perf_sample__fprint_metric(struct perf_script *script, sample->cpu, &rt_stat); evsel_script(evsel)->val = val; - if (evsel_script(evsel->leader)->gnum == evsel->leader->core.nr_members) { - for_each_group_member (ev2, evsel->leader) { + if (evsel_script(leader)->gnum == leader->core.nr_members) { + for_each_group_member (ev2, leader) { perf_stat__print_shadow_stats(&stat_config, ev2, evsel_script(ev2)->val, sample->cpu, @@ -1932,7 +1933,7 @@ static void perf_sample__fprint_metric(struct perf_script *script, NULL, &rt_stat); } - evsel_script(evsel->leader)->gnum = 0; + evsel_script(leader)->gnum = 0; } } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f9f74a514315..d25cb8088e8c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -154,6 +154,8 @@ static const char *topdown_metric_L2_attrs[] = { NULL, }; +#define TOPDOWN_MAX_LEVEL 2 + static const char *smi_cost_attrs = { "{" "msr/aperf/," @@ -248,7 +250,7 @@ static void evlist__check_cpu_maps(struct evlist *evlist) evlist__warn_hybrid_group(evlist); evlist__for_each_entry(evlist, evsel) { - leader = evsel->leader; + leader = evsel__leader(evsel); /* Check that leader matches cpus with each member. */ if (leader == evsel) @@ -269,10 +271,10 @@ static void evlist__check_cpu_maps(struct evlist *evlist) } for_each_group_evsel(pos, leader) { - pos->leader = pos; + evsel__set_leader(pos, pos); pos->core.nr_members = 0; } - evsel->leader->core.nr_members = 0; + evsel->core.leader->nr_members = 0; } } @@ -745,8 +747,8 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) */ counter->errored = true; - if ((counter->leader != counter) || - !(counter->leader->core.nr_members > 1)) + if ((evsel__leader(counter) != counter) || + !(counter->core.leader->nr_members > 1)) return COUNTER_SKIP; } else if (evsel__fallback(counter, errno, msg, sizeof(msg))) { if (verbose > 0) @@ -839,7 +841,7 @@ try_again: * Don't close here because we're in the wrong affinity. */ if ((errno == EINVAL || errno == EBADF) && - counter->leader != counter && + evsel__leader(counter) != counter && counter->weak_group) { evlist__reset_weak_group(evsel_list, counter, false); assert(counter->reset_group); @@ -1931,6 +1933,7 @@ setup_metrics: if (evlist__add_default_attrs(evsel_list, default_attrs1) < 0) return -1; + stat_config.topdown_level = TOPDOWN_MAX_LEVEL; if (arch_evlist__add_default_attrs(evsel_list) < 0) return -1; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2d570bfe7a56..02f8bb5dbc0f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -264,9 +264,9 @@ static void perf_top__show_details(struct perf_top *top) if (top->evlist->enabled) { if (top->zero) - symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); + symbol__annotate_zero_histogram(symbol, top->sym_evsel->core.idx); else - symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); + symbol__annotate_decay_histogram(symbol, top->sym_evsel->core.idx); } if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); @@ -301,7 +301,7 @@ static void perf_top__resort_hists(struct perf_top *t) /* Non-group events are considered as leader */ if (symbol_conf.event_group && !evsel__is_group_leader(pos)) { - struct hists *leader_hists = evsel__hists(pos->leader); + struct hists *leader_hists = evsel__hists(evsel__leader(pos)); hists__match(leader_hists, hists); hists__link(leader_hists, hists); @@ -530,7 +530,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) fprintf(stderr, "\nAvailable events:"); evlist__for_each_entry(top->evlist, top->sym_evsel) - fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, evsel__name(top->sym_evsel)); + fprintf(stderr, "\n\t%d %s", top->sym_evsel->core.idx, evsel__name(top->sym_evsel)); prompt_integer(&counter, "Enter details event counter"); @@ -541,7 +541,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) break; } evlist__for_each_entry(top->evlist, top->sym_evsel) - if (top->sym_evsel->idx == counter) + if (top->sym_evsel->core.idx == counter) break; } else top->sym_evsel = evlist__first(top->evlist); diff --git a/tools/perf/pmu-events/arch/powerpc/power10/nest_metrics.json b/tools/perf/pmu-events/arch/powerpc/power10/nest_metrics.json new file mode 100644 index 000000000000..8ba3e81c9808 --- /dev/null +++ b/tools/perf/pmu-events/arch/powerpc/power10/nest_metrics.json @@ -0,0 +1,424 @@ +[ + { + "MetricName": "VEC_GROUP_PUMP_RETRY_RATIO_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_VG_PUMP01\\,chip\\=?@ / hv_24x7@PM_PB_VG_PUMP01\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "VEC_GROUP_PUMP_RETRY_RATIO_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_VG_PUMP23\\,chip\\=?@ / hv_24x7@PM_PB_VG_PUMP23\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "LOCAL_NODE_PUMP_RETRY_RATIO_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_LNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PB_LNS_PUMP01\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "LOCAL_NODE_PUMP_RETRY_RATIO_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_LNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PB_LNS_PUMP23\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "GROUP_PUMP_RETRY_RATIO_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_GROUP_PUMP01\\,chip\\=?@ / hv_24x7@PM_PB_GROUP_PUMP01\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "GROUP_PUMP_RETRY_RATIO_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_GROUP_PUMP23\\,chip\\=?@ / hv_24x7@PM_PB_GROUP_PUMP23\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_GROUP_PUMPS_P01", + "MetricExpr": "(hv_24x7@PM_PB_GROUP_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_GROUP_PUMPS_P23", + "MetricExpr": "(hv_24x7@PM_PB_GROUP_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_GROUP_PUMPS_RETRIES_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_GROUP_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_GROUP_PUMPS_RETRIES_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_GROUP_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "REMOTE_NODE_PUMPS_RETRIES_RATIO_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_RNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PB_RNS_PUMP01\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "REMOTE_NODE_PUMPS_RETRIES_RATIO_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_RNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PB_RNS_PUMP23\\,chip\\=?@) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_VECTOR_GROUP_PUMPS_P01", + "MetricExpr": "(hv_24x7@PM_PB_VG_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_VECTOR_GROUP_PUMPS_P23", + "MetricExpr": "(hv_24x7@PM_PB_VG_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_LOCAL_NODE_PUMPS_P01", + "MetricExpr": "(hv_24x7@PM_PB_LNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_LOCAL_NODE_PUMPS_P23", + "MetricExpr": "(hv_24x7@PM_PB_LNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_VECTOR_GROUP_PUMPS_RETRIES_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_VG_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_VECTOR_GROUP_PUMPS_RETRIES_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_VG_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_LOCAL_NODE_PUMPS_RETRIES_P01", + "MetricExpr": "(hv_24x7@PM_PB_RTY_LNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_LOCAL_NODE_PUMPS_RETRIES_P23", + "MetricExpr": "(hv_24x7@PM_PB_RTY_LNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_REMOTE_NODE_PUMPS_P01", + "MetricExpr": "(hv_24x7@PM_PB_RNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_REMOTE_NODE_PUMPS_P23", + "MetricExpr": "(hv_24x7@PM_PB_RNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_NEAR_NODE_PUMPS_P01", + "MetricExpr": "(hv_24x7@PM_PB_NNS_PUMP01\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_NEAR_NODE_PUMPS_P23", + "MetricExpr": "(hv_24x7@PM_PB_NNS_PUMP23\\,chip\\=?@ / hv_24x7@PM_PAU_CYC\\,chip\\=?@)", + "ScaleUnit": "4", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_INT_PB_BW", + "MetricExpr": "(hv_24x7@PM_PB_INT_DATA_XFER\\,chip\\=?@)", + "ScaleUnit": "2.09MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK0_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK0_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK0_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK0_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK0_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK1_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK1_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK1_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK1_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK1_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK2_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK2_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK2_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK2_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK2_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK3_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK3_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK3_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK3_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK3_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK4_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK4_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK4_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK4_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK4_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK5_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK5_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK5_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK5_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK5_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK6_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK6_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK6_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK6_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK6_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK7_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK7_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_XLINK7_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_XLINK7_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK7_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK0_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK0_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK0_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK0_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK0_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK1_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK1_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK1_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK1_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK1_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK2_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK2_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK2_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK2_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK2_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK3_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK3_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK3_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK3_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK3_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK4_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK4_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK4_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK4_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK4_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK5_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK5_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK5_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK5_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK5_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK6_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK6_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK6_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK6_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK6_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "XLINK7_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_XLINK7_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_XLINK7_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_XLINK7_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_XLINK7_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK0_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK0_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK0_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK0_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK0_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK1_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK1_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK1_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK1_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK1_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK2_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK2_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK2_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK2_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK2_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK3_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK3_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK3_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK3_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK3_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK4_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK4_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK4_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK4_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK4_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK5_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK5_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK5_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK5_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK5_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK6_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK6_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK6_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK6_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK6_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK7_OUT_TOTAL_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK7_OUT_ODD_TOTAL_UTIL\\,chip\\=?@ + hv_24x7@PM_ALINK7_OUT_EVEN_TOTAL_UTIL\\,chip\\=?@) / (hv_24x7@PM_ALINK7_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK7_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK0_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK0_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK0_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK0_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK0_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK1_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK1_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK1_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK1_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK1_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK2_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK2_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK2_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK2_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK2_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK3_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK3_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK3_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK3_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK3_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK4_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK4_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK4_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK4_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK4_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK5_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK5_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK5_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK5_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK5_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK6_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK6_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK6_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK6_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK6_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "ALINK7_OUT_DATA_UTILIZATION", + "MetricExpr": "((hv_24x7@PM_ALINK7_OUT_ODD_DATA\\,chip\\=?@ + hv_24x7@PM_ALINK7_OUT_EVEN_DATA\\,chip\\=?@) / (hv_24x7@PM_ALINK7_OUT_ODD_AVLBL_CYCLES\\,chip\\=?@ + hv_24x7@PM_ALINK7_OUT_EVEN_AVLBL_CYCLES\\,chip\\=?@)) * 100", + "ScaleUnit": "1.063%", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_DATA_BANDWIDTH_TRANSFERRED_OVER_PB_PCI1", + "MetricExpr": "(hv_24x7@PM_PCI1_32B_INOUT\\,chip\\=?@)", + "ScaleUnit": "3.28e-2MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_DATA_BANDWIDTH_TRANSFERRED_OVER_PB_PCI0", + "MetricExpr": "(hv_24x7@PM_PCI0_32B_INOUT\\,chip\\=?@)", + "ScaleUnit": "3.28e-2MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_READ_BW_MC0_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC0_CHAN01\\,chip\\=?@)", + "ScaleUnit": "5.24e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_READ_BW_MC1_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC1_CHAN01\\,chip\\=?@)", + "ScaleUnit": "5.24e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_READ_BW_MC2_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC2_CHAN01\\,chip\\=?@)", + "ScaleUnit": "5.24e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_READ_BW_MC3_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC3_CHAN01\\,chip\\=?@)", + "ScaleUnit": "5.24e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_WRITE_BW_MC0_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC0_CHAN01\\,chip\\=?@)", + "ScaleUnit": "2.6e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_WRITE_BW_MC1_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC1_CHAN01\\,chip\\=?@)", + "ScaleUnit": "2.6e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_WRITE_BW_MC2_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC2_CHAN01\\,chip\\=?@)", + "ScaleUnit": "2.6e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "TOTAL_MCS_WRITE_BW_MC3_CHAN01", + "MetricExpr": "(hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC3_CHAN01\\,chip\\=?@)", + "ScaleUnit": "2.6e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "Memory_RD_BW_Chip", + "MetricExpr": "(hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC0_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC1_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC2_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_128B_RD_DATA_BLOCKS_MC3_CHAN01\\,chip\\=?@)", + "MetricGroup": "Memory_BW", + "ScaleUnit": "5.24e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "Memory_WR_BW_Chip", + "MetricExpr": "(hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC0_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC1_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC2_CHAN01\\,chip\\=?@ + hv_24x7@PM_MCS_64B_WR_DATA_BLOCKS_MC3_CHAN01\\,chip\\=?@ )", + "MetricGroup": "Memory_BW", + "ScaleUnit": "2.6e-1MB", + "AggregationMode": "PerChip" + }, + { + "MetricName": "PowerBUS_Frequency", + "MetricExpr": "(hv_24x7@PM_PAU_CYC\\,chip\\=?@ )", + "ScaleUnit": "2.56e-7GHz", + "AggregationMode": "PerChip" + } +] diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index c72adbd67386..33bda9c26542 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -151,7 +151,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), } evlist__splice_list_tail(evlist, &parse_state.list); - evlist->nr_groups = parse_state.nr_groups; + evlist->core.nr_groups = parse_state.nr_groups; evlist__config(evlist, &opts, NULL); diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 41e3cf6bb66c..5e6242576236 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -26,6 +26,7 @@ #include #include #include +#include static bool dont_fork; @@ -540,7 +541,7 @@ static int shell_tests__max_desc_width(void) { struct dirent **entlist; struct dirent *ent; - int n_dirs; + int n_dirs, e; char path_dir[PATH_MAX]; const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); int width = 0; @@ -564,8 +565,9 @@ static int shell_tests__max_desc_width(void) } } + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); free(entlist); - return width; } @@ -596,7 +598,7 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width) { struct dirent **entlist; struct dirent *ent; - int n_dirs; + int n_dirs, e; char path_dir[PATH_MAX]; struct shell_test st = { .dir = shell_tests__dir(path_dir, sizeof(path_dir)), @@ -629,6 +631,8 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width) test_and_print(&test, false, -1); } + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); free(entlist); return 0; } @@ -730,7 +734,7 @@ static int perf_test__list_shell(int argc, const char **argv, int i) { struct dirent **entlist; struct dirent *ent; - int n_dirs; + int n_dirs, e; char path_dir[PATH_MAX]; const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); @@ -752,8 +756,11 @@ static int perf_test__list_shell(int argc, const char **argv, int i) continue; pr_info("%2d: %s\n", i, t.desc); + } + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); free(entlist); return 0; } diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index b74cf80d1f10..5ebf56331904 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -44,7 +44,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); - if (evsel->idx != idx) + if (evsel->core.idx != idx) continue; ++idx; @@ -84,9 +84,9 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names, err = 0; evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel__name(evsel), names[evsel->idx / distance])) { + if (strcmp(evsel__name(evsel), names[evsel->core.idx / distance])) { --err; - pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->idx / distance]); + pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->core.idx / distance]); } } diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 73ae8f7aa066..d38757db2dc2 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -139,7 +139,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse " doesn't map to an evsel\n", sample.id); goto out_delete_evlist; } - nr_events[evsel->idx]++; + nr_events[evsel->core.idx]++; perf_mmap__consume(&md->core); } perf_mmap__read_done(&md->core); @@ -147,10 +147,10 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse out_init: err = 0; evlist__for_each_entry(evlist, evsel) { - if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { + if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) { pr_debug("expected %d %s events, got %d\n", - expected_nr_events[evsel->idx], - evsel__name(evsel), nr_events[evsel->idx]); + expected_nr_events[evsel->core.idx], + evsel__name(evsel), nr_events[evsel->core.idx]); err = -1; goto out_delete_evlist; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0f113b2b36a3..56a7b6a14195 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -49,7 +49,7 @@ static int test__checkevent_tracepoint(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); @@ -62,7 +62,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", @@ -668,7 +668,7 @@ static int test__group1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* instructions:k */ evsel = leader = evlist__first(evlist); @@ -698,7 +698,7 @@ static int test__group1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -710,7 +710,7 @@ static int test__group2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* faults + :ku modifier */ evsel = leader = evlist__first(evlist); @@ -739,7 +739,7 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -765,7 +765,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); /* group1 syscalls:sys_enter_openat:H */ evsel = leader = evlist__first(evlist); @@ -798,7 +798,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 3); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -831,7 +831,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -857,7 +857,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:u + p */ evsel = leader = evlist__first(evlist); @@ -889,7 +889,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -901,7 +901,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); /* cycles + G */ evsel = leader = evlist__first(evlist); @@ -931,7 +931,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -963,7 +963,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); /* cycles */ @@ -987,7 +987,7 @@ static int test__group_gh1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles + :H group modifier */ evsel = leader = evlist__first(evlist); @@ -1016,7 +1016,7 @@ static int test__group_gh1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1027,7 +1027,7 @@ static int test__group_gh2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles + :G group modifier */ evsel = leader = evlist__first(evlist); @@ -1056,7 +1056,7 @@ static int test__group_gh2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1067,7 +1067,7 @@ static int test__group_gh3(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:G + :u group modifier */ evsel = leader = evlist__first(evlist); @@ -1096,7 +1096,7 @@ static int test__group_gh3(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1107,7 +1107,7 @@ static int test__group_gh4(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:G + :uG group modifier */ evsel = leader = evlist__first(evlist); @@ -1136,7 +1136,7 @@ static int test__group_gh4(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1160,7 +1160,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* cache-misses - not sampling */ @@ -1174,7 +1174,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ @@ -1189,7 +1189,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); return 0; @@ -1213,7 +1213,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ @@ -1228,7 +1228,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); return 0; @@ -1259,7 +1259,7 @@ static int test__pinned_group(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); /* cache-misses - can not be pinned, but will go on with the leader */ @@ -1303,7 +1303,7 @@ static int test__exclusive_group(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclusive", evsel->core.attr.exclusive); /* cache-misses - can not be pinned, but will go on with the leader */ @@ -1530,12 +1530,12 @@ static int test__hybrid_hw_group_event(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1546,12 +1546,12 @@ static int test__hybrid_sw_hw_group_event(struct evlist *evlist) evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1563,11 +1563,11 @@ static int test__hybrid_hw_sw_group_event(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1579,14 +1579,14 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); return 0; diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index acd50944f6af..e8fd0da0762b 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -96,7 +96,7 @@ static int test__pfm_events(void) count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->nr_groups, + evlist->core.nr_groups, 0); evlist__delete(evlist); @@ -180,7 +180,7 @@ static int test__pfm_group(void) count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->nr_groups, + evlist->core.nr_groups, table[i].nr_groups); evlist__delete(evlist); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index f5509a958e38..701130ad43a2 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -350,14 +350,14 @@ static struct annotation_line *annotate_browser__find_next_asm_line( struct annotation_line *it = al; /* find next asm line */ - list_for_each_entry_continue(it, browser->b.top, node) { + list_for_each_entry_continue(it, browser->b.entries, node) { if (it->idx_asm >= 0) return it; } /* no asm line found forwards, try backwards */ it = al; - list_for_each_entry_continue_reverse(it, browser->b.top, node) { + list_for_each_entry_continue_reverse(it, browser->b.entries, node) { if (it->idx_asm >= 0) return it; } @@ -749,7 +749,7 @@ static int annotate_browser__run(struct annotate_browser *browser, hbt->timer(hbt->arg); if (delay_secs != 0) { - symbol__annotate_decay_histogram(sym, evsel->idx); + symbol__annotate_decay_histogram(sym, evsel->core.idx); hists__scnprintf_title(hists, title, sizeof(title)); annotate_browser__show(&browser->b, title, help); } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index a7dff77f2018..94167bfed722 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -135,12 +135,12 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct map_symbol *ms, ret += perf_gtk__get_percent(s + ret, sizeof(s) - ret, sym, pos, - evsel->idx + i); + evsel->core.idx + i); ret += scnprintf(s + ret, sizeof(s) - ret, " "); } } else { ret = perf_gtk__get_percent(s, sizeof(s), sym, pos, - evsel->idx); + evsel->core.idx); } if (ret) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 1a909b53dc15..2d4fa1304178 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -141,6 +141,7 @@ perf-y += clockid.o perf-$(CONFIG_LIBBPF) += bpf-loader.o perf-$(CONFIG_LIBBPF) += bpf_map.o perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter.o +perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter_cgroup.o perf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o perf-$(CONFIG_LIBELF) += symbol-elf.o perf-$(CONFIG_LIBELF) += probe-file.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index abe1499a9164..aa04a3655236 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -961,7 +961,7 @@ static int symbol__inc_addr_samples(struct map_symbol *ms, if (sym == NULL) return 0; src = symbol__hists(sym, evsel->evlist->core.nr_entries); - return src ? __symbol__inc_addr_samples(ms, src, evsel->idx, addr, sample) : 0; + return src ? __symbol__inc_addr_samples(ms, src, evsel->core.idx, addr, sample) : 0; } static int symbol__account_cycles(u64 addr, u64 start, @@ -2159,7 +2159,7 @@ static void annotation__calc_percent(struct annotation *notes, BUG_ON(i >= al->data_nr); - sym_hist = annotation__histogram(notes, evsel->idx); + sym_hist = annotation__histogram(notes, evsel->core.idx); data = &al->data[i++]; calc_percent(sym_hist, hists, data, al->offset, end); @@ -2340,7 +2340,7 @@ static void print_summary(struct rb_root *root, const char *filename) static void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel) { struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evsel->idx); + struct sym_hist *h = annotation__histogram(notes, evsel->core.idx); u64 len = symbol__size(sym), offset; for (offset = 0; offset < len; ++offset) @@ -2373,7 +2373,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, const char *d_filename; const char *evsel_name = evsel__name(evsel); struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evsel->idx); + struct sym_hist *h = annotation__histogram(notes, evsel->core.idx); struct annotation_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0, addr_fmt_width; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 9350eeb3a3fc..cb19669d2a5b 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -73,8 +73,8 @@ static int evlist__regroup(struct evlist *evlist, struct evsel *leader, struct e grp = false; evlist__for_each_entry(evlist, evsel) { if (grp) { - if (!(evsel->leader == leader || - (evsel->leader == evsel && + if (!(evsel__leader(evsel) == leader || + (evsel__leader(evsel) == evsel && evsel->core.nr_members <= 1))) return -EINVAL; } else if (evsel == leader) { @@ -87,8 +87,8 @@ static int evlist__regroup(struct evlist *evlist, struct evsel *leader, struct e grp = false; evlist__for_each_entry(evlist, evsel) { if (grp) { - if (evsel->leader != leader) { - evsel->leader = leader; + if (!evsel__has_leader(evsel, leader)) { + evsel__set_leader(evsel, leader); if (leader->core.nr_members < 1) leader->core.nr_members = 1; leader->core.nr_members += 1; @@ -1231,11 +1231,11 @@ static void unleader_evsel(struct evlist *evlist, struct evsel *leader) /* Find new leader for the group */ evlist__for_each_entry(evlist, evsel) { - if (evsel->leader != leader || evsel == leader) + if (!evsel__has_leader(evsel, leader) || evsel == leader) continue; if (!new_leader) new_leader = evsel; - evsel->leader = new_leader; + evsel__set_leader(evsel, new_leader); } /* Update group information */ diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index 21c8e71162b1..8150e03367bb 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -18,6 +18,7 @@ #include "evsel.h" #include "evlist.h" #include "target.h" +#include "cgroup.h" #include "cpumap.h" #include "thread_map.h" @@ -352,7 +353,7 @@ static int bperf_check_target(struct evsel *evsel, enum bperf_filter_type *filter_type, __u32 *filter_entry_cnt) { - if (evsel->leader->core.nr_members > 1) { + if (evsel->core.leader->nr_members > 1) { pr_err("bpf managed perf events do not yet support groups.\n"); return -1; } @@ -742,6 +743,8 @@ struct bpf_counter_ops bperf_ops = { .destroy = bperf__destroy, }; +extern struct bpf_counter_ops bperf_cgrp_ops; + static inline bool bpf_counter_skip(struct evsel *evsel) { return list_empty(&evsel->bpf_counter_list) && @@ -759,6 +762,8 @@ int bpf_counter__load(struct evsel *evsel, struct target *target) { if (target->bpf_str) evsel->bpf_counter_ops = &bpf_program_profiler_ops; + else if (cgrp_event_expanded && target->use_bpf) + evsel->bpf_counter_ops = &bperf_cgrp_ops; else if (target->use_bpf || evsel->bpf_counter || evsel__match_bpf_counter_events(evsel->name)) evsel->bpf_counter_ops = &bperf_ops; diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c new file mode 100644 index 000000000000..89aa5e71db1a --- /dev/null +++ b/tools/perf/util/bpf_counter_cgroup.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Copyright (c) 2021 Facebook */ +/* Copyright (c) 2021 Google */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "affinity.h" +#include "bpf_counter.h" +#include "cgroup.h" +#include "counts.h" +#include "debug.h" +#include "evsel.h" +#include "evlist.h" +#include "target.h" +#include "cpumap.h" +#include "thread_map.h" + +#include "bpf_skel/bperf_cgroup.skel.h" + +static struct perf_event_attr cgrp_switch_attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CGROUP_SWITCHES, + .size = sizeof(cgrp_switch_attr), + .sample_period = 1, + .disabled = 1, +}; + +static struct evsel *cgrp_switch; +static struct bperf_cgroup_bpf *skel; + +#define FD(evt, cpu) (*(int *)xyarray__entry(evt->core.fd, cpu, 0)) + +static int bperf_load_program(struct evlist *evlist) +{ + struct bpf_link *link; + struct evsel *evsel; + struct cgroup *cgrp, *leader_cgrp; + __u32 i, cpu; + __u32 nr_cpus = evlist->core.all_cpus->nr; + int total_cpus = cpu__max_cpu(); + int map_size, map_fd; + int prog_fd, err; + + skel = bperf_cgroup_bpf__open(); + if (!skel) { + pr_err("Failed to open cgroup skeleton\n"); + return -1; + } + + skel->rodata->num_cpus = total_cpus; + skel->rodata->num_events = evlist->core.nr_entries / nr_cgroups; + + BUG_ON(evlist->core.nr_entries % nr_cgroups != 0); + + /* we need one copy of events per cpu for reading */ + map_size = total_cpus * evlist->core.nr_entries / nr_cgroups; + bpf_map__resize(skel->maps.events, map_size); + bpf_map__resize(skel->maps.cgrp_idx, nr_cgroups); + /* previous result is saved in a per-cpu array */ + map_size = evlist->core.nr_entries / nr_cgroups; + bpf_map__resize(skel->maps.prev_readings, map_size); + /* cgroup result needs all events (per-cpu) */ + map_size = evlist->core.nr_entries; + bpf_map__resize(skel->maps.cgrp_readings, map_size); + + set_max_rlimit(); + + err = bperf_cgroup_bpf__load(skel); + if (err) { + pr_err("Failed to load cgroup skeleton\n"); + goto out; + } + + if (cgroup_is_v2("perf_event") > 0) + skel->bss->use_cgroup_v2 = 1; + + err = -1; + + cgrp_switch = evsel__new(&cgrp_switch_attr); + if (evsel__open_per_cpu(cgrp_switch, evlist->core.all_cpus, -1) < 0) { + pr_err("Failed to open cgroup switches event\n"); + goto out; + } + + for (i = 0; i < nr_cpus; i++) { + link = bpf_program__attach_perf_event(skel->progs.on_cgrp_switch, + FD(cgrp_switch, i)); + if (IS_ERR(link)) { + pr_err("Failed to attach cgroup program\n"); + err = PTR_ERR(link); + goto out; + } + } + + /* + * Update cgrp_idx map from cgroup-id to event index. + */ + cgrp = NULL; + i = 0; + + evlist__for_each_entry(evlist, evsel) { + if (cgrp == NULL || evsel->cgrp == leader_cgrp) { + leader_cgrp = evsel->cgrp; + evsel->cgrp = NULL; + + /* open single copy of the events w/o cgroup */ + err = evsel__open_per_cpu(evsel, evlist->core.all_cpus, -1); + if (err) { + pr_err("Failed to open first cgroup events\n"); + goto out; + } + + map_fd = bpf_map__fd(skel->maps.events); + for (cpu = 0; cpu < nr_cpus; cpu++) { + int fd = FD(evsel, cpu); + __u32 idx = evsel->core.idx * total_cpus + + evlist->core.all_cpus->map[cpu]; + + err = bpf_map_update_elem(map_fd, &idx, &fd, + BPF_ANY); + if (err < 0) { + pr_err("Failed to update perf_event fd\n"); + goto out; + } + } + + evsel->cgrp = leader_cgrp; + } + evsel->supported = true; + + if (evsel->cgrp == cgrp) + continue; + + cgrp = evsel->cgrp; + + if (read_cgroup_id(cgrp) < 0) { + pr_err("Failed to get cgroup id\n"); + err = -1; + goto out; + } + + map_fd = bpf_map__fd(skel->maps.cgrp_idx); + err = bpf_map_update_elem(map_fd, &cgrp->id, &i, BPF_ANY); + if (err < 0) { + pr_err("Failed to update cgroup index map\n"); + goto out; + } + + i++; + } + + /* + * bperf uses BPF_PROG_TEST_RUN to get accurate reading. Check + * whether the kernel support it + */ + prog_fd = bpf_program__fd(skel->progs.trigger_read); + err = bperf_trigger_reading(prog_fd, 0); + if (err) { + pr_warning("The kernel does not support test_run for raw_tp BPF programs.\n" + "Therefore, --for-each-cgroup might show inaccurate readings\n"); + err = 0; + } + +out: + return err; +} + +static int bperf_cgrp__load(struct evsel *evsel, + struct target *target __maybe_unused) +{ + static bool bperf_loaded = false; + + evsel->bperf_leader_prog_fd = -1; + evsel->bperf_leader_link_fd = -1; + + if (!bperf_loaded && bperf_load_program(evsel->evlist)) + return -1; + + bperf_loaded = true; + /* just to bypass bpf_counter_skip() */ + evsel->follower_skel = (struct bperf_follower_bpf *)skel; + + return 0; +} + +static int bperf_cgrp__install_pe(struct evsel *evsel __maybe_unused, + int cpu __maybe_unused, int fd __maybe_unused) +{ + /* nothing to do */ + return 0; +} + +/* + * trigger the leader prog on each cpu, so the cgrp_reading map could get + * the latest results. + */ +static int bperf_cgrp__sync_counters(struct evlist *evlist) +{ + int i, cpu; + int nr_cpus = evlist->core.all_cpus->nr; + int prog_fd = bpf_program__fd(skel->progs.trigger_read); + + for (i = 0; i < nr_cpus; i++) { + cpu = evlist->core.all_cpus->map[i]; + bperf_trigger_reading(prog_fd, cpu); + } + + return 0; +} + +static int bperf_cgrp__enable(struct evsel *evsel) +{ + if (evsel->core.idx) + return 0; + + bperf_cgrp__sync_counters(evsel->evlist); + + skel->bss->enabled = 1; + return 0; +} + +static int bperf_cgrp__disable(struct evsel *evsel) +{ + if (evsel->core.idx) + return 0; + + bperf_cgrp__sync_counters(evsel->evlist); + + skel->bss->enabled = 0; + return 0; +} + +static int bperf_cgrp__read(struct evsel *evsel) +{ + struct evlist *evlist = evsel->evlist; + int i, cpu, nr_cpus = evlist->core.all_cpus->nr; + int total_cpus = cpu__max_cpu(); + struct perf_counts_values *counts; + struct bpf_perf_event_value *values; + int reading_map_fd, err = 0; + __u32 idx; + + if (evsel->core.idx) + return 0; + + bperf_cgrp__sync_counters(evsel->evlist); + + values = calloc(total_cpus, sizeof(*values)); + if (values == NULL) + return -ENOMEM; + + reading_map_fd = bpf_map__fd(skel->maps.cgrp_readings); + + evlist__for_each_entry(evlist, evsel) { + idx = evsel->core.idx; + err = bpf_map_lookup_elem(reading_map_fd, &idx, values); + if (err) { + pr_err("bpf map lookup falied: idx=%u, event=%s, cgrp=%s\n", + idx, evsel__name(evsel), evsel->cgrp->name); + goto out; + } + + for (i = 0; i < nr_cpus; i++) { + cpu = evlist->core.all_cpus->map[i]; + + counts = perf_counts(evsel->counts, i, 0); + counts->val = values[cpu].counter; + counts->ena = values[cpu].enabled; + counts->run = values[cpu].running; + } + } + +out: + free(values); + return err; +} + +static int bperf_cgrp__destroy(struct evsel *evsel) +{ + if (evsel->core.idx) + return 0; + + bperf_cgroup_bpf__destroy(skel); + evsel__delete(cgrp_switch); // it'll destroy on_switch progs too + + return 0; +} + +struct bpf_counter_ops bperf_cgrp_ops = { + .load = bperf_cgrp__load, + .enable = bperf_cgrp__enable, + .disable = bperf_cgrp__disable, + .read = bperf_cgrp__read, + .install_pe = bperf_cgrp__install_pe, + .destroy = bperf_cgrp__destroy, +}; diff --git a/tools/perf/util/bpf_skel/bperf_cgroup.bpf.c b/tools/perf/util/bpf_skel/bperf_cgroup.bpf.c new file mode 100644 index 000000000000..292c430768b5 --- /dev/null +++ b/tools/perf/util/bpf_skel/bperf_cgroup.bpf.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (c) 2021 Facebook +// Copyright (c) 2021 Google +#include "vmlinux.h" +#include +#include +#include + +#define MAX_LEVELS 10 // max cgroup hierarchy level: arbitrary +#define MAX_EVENTS 32 // max events per cgroup: arbitrary + +// NOTE: many of map and global data will be modified before loading +// from the userspace (perf tool) using the skeleton helpers. + +// single set of global perf events to measure +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1); +} events SEC(".maps"); + +// from cgroup id to event index +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u64)); + __uint(value_size, sizeof(__u32)); + __uint(max_entries, 1); +} cgrp_idx SEC(".maps"); + +// per-cpu event snapshots to calculate delta +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(struct bpf_perf_event_value)); +} prev_readings SEC(".maps"); + +// aggregated event values for each cgroup (per-cpu) +// will be read from the user-space +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(struct bpf_perf_event_value)); +} cgrp_readings SEC(".maps"); + +const volatile __u32 num_events = 1; +const volatile __u32 num_cpus = 1; + +int enabled = 0; +int use_cgroup_v2 = 0; + +static inline int get_cgroup_v1_idx(__u32 *cgrps, int size) +{ + struct task_struct *p = (void *)bpf_get_current_task(); + struct cgroup *cgrp; + register int i = 0; + __u32 *elem; + int level; + int cnt; + + cgrp = BPF_CORE_READ(p, cgroups, subsys[perf_event_cgrp_id], cgroup); + level = BPF_CORE_READ(cgrp, level); + + for (cnt = 0; i < MAX_LEVELS; i++) { + __u64 cgrp_id; + + if (i > level) + break; + + // convert cgroup-id to a map index + cgrp_id = BPF_CORE_READ(cgrp, ancestor_ids[i]); + elem = bpf_map_lookup_elem(&cgrp_idx, &cgrp_id); + if (!elem) + continue; + + cgrps[cnt++] = *elem; + if (cnt == size) + break; + } + + return cnt; +} + +static inline int get_cgroup_v2_idx(__u32 *cgrps, int size) +{ + register int i = 0; + __u32 *elem; + int cnt; + + for (cnt = 0; i < MAX_LEVELS; i++) { + __u64 cgrp_id = bpf_get_current_ancestor_cgroup_id(i); + + if (cgrp_id == 0) + break; + + // convert cgroup-id to a map index + elem = bpf_map_lookup_elem(&cgrp_idx, &cgrp_id); + if (!elem) + continue; + + cgrps[cnt++] = *elem; + if (cnt == size) + break; + } + + return cnt; +} + +static int bperf_cgroup_count(void) +{ + register __u32 idx = 0; // to have it in a register to pass BPF verifier + register int c = 0; + struct bpf_perf_event_value val, delta, *prev_val, *cgrp_val; + __u32 cpu = bpf_get_smp_processor_id(); + __u32 cgrp_idx[MAX_LEVELS]; + int cgrp_cnt; + __u32 key, cgrp; + long err; + + if (use_cgroup_v2) + cgrp_cnt = get_cgroup_v2_idx(cgrp_idx, MAX_LEVELS); + else + cgrp_cnt = get_cgroup_v1_idx(cgrp_idx, MAX_LEVELS); + + for ( ; idx < MAX_EVENTS; idx++) { + if (idx == num_events) + break; + + // XXX: do not pass idx directly (for verifier) + key = idx; + // this is per-cpu array for diff + prev_val = bpf_map_lookup_elem(&prev_readings, &key); + if (!prev_val) { + val.counter = val.enabled = val.running = 0; + bpf_map_update_elem(&prev_readings, &key, &val, BPF_ANY); + + prev_val = bpf_map_lookup_elem(&prev_readings, &key); + if (!prev_val) + continue; + } + + // read from global perf_event array + key = idx * num_cpus + cpu; + err = bpf_perf_event_read_value(&events, key, &val, sizeof(val)); + if (err) + continue; + + if (enabled) { + delta.counter = val.counter - prev_val->counter; + delta.enabled = val.enabled - prev_val->enabled; + delta.running = val.running - prev_val->running; + + for (c = 0; c < MAX_LEVELS; c++) { + if (c == cgrp_cnt) + break; + + cgrp = cgrp_idx[c]; + + // aggregate the result by cgroup + key = cgrp * num_events + idx; + cgrp_val = bpf_map_lookup_elem(&cgrp_readings, &key); + if (cgrp_val) { + cgrp_val->counter += delta.counter; + cgrp_val->enabled += delta.enabled; + cgrp_val->running += delta.running; + } else { + bpf_map_update_elem(&cgrp_readings, &key, + &delta, BPF_ANY); + } + } + } + + *prev_val = val; + } + return 0; +} + +// This will be attached to cgroup-switches event for each cpu +SEC("perf_events") +int BPF_PROG(on_cgrp_switch) +{ + return bperf_cgroup_count(); +} + +SEC("raw_tp/sched_switch") +int BPF_PROG(trigger_read) +{ + return bperf_cgroup_count(); +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index e819a4f30fc2..e99b41f9be45 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -18,6 +18,7 @@ #include int nr_cgroups; +bool cgrp_event_expanded; /* used to match cgroup name with patterns */ struct cgroup_name { @@ -458,7 +459,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, if (evsel__is_group_leader(pos)) leader = evsel; - evsel->leader = leader; + evsel__set_leader(evsel, leader); evlist__add(tmp_list, evsel); } @@ -484,6 +485,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, } ret = 0; + cgrp_event_expanded = true; out_err: evlist__delete(orig_list); diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h index de5b272560ab..12256b78608c 100644 --- a/tools/perf/util/cgroup.h +++ b/tools/perf/util/cgroup.h @@ -18,6 +18,7 @@ struct cgroup { }; extern int nr_cgroups; /* number of explicit cgroups defined */ +extern bool cgrp_event_expanded; struct cgroup *cgroup__get(struct cgroup *cgroup); void cgroup__put(struct cgroup *cgroup); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 6ba9664089bd..47581a237c7a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -165,11 +165,9 @@ void evlist__delete(struct evlist *evlist) void evlist__add(struct evlist *evlist, struct evsel *entry) { - entry->evlist = evlist; - entry->idx = evlist->core.nr_entries; - entry->tracking = !entry->idx; - perf_evlist__add(&evlist->core, &entry->core); + entry->evlist = evlist; + entry->tracking = !entry->core.idx; if (evlist->core.nr_entries == 1) evlist__set_id_pos(evlist); @@ -194,7 +192,7 @@ void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list) } __evlist__for_each_entry_safe(list, temp, evsel) { - if (evsel->leader == leader) { + if (evsel__has_leader(evsel, leader)) { list_del_init(&evsel->core.node); evlist__add(evlist, evsel); } @@ -225,26 +223,9 @@ out: return err; } -void __evlist__set_leader(struct list_head *list) -{ - struct evsel *evsel, *leader; - - leader = list_entry(list->next, struct evsel, core.node); - evsel = list_entry(list->prev, struct evsel, core.node); - - leader->core.nr_members = evsel->idx - leader->idx + 1; - - __evlist__for_each_entry(list, evsel) { - evsel->leader = leader; - } -} - void evlist__set_leader(struct evlist *evlist) { - if (evlist->core.nr_entries) { - evlist->nr_groups = evlist->core.nr_entries > 1 ? 1 : 0; - __evlist__set_leader(&evlist->core.entries); - } + perf_evlist__set_leader(&evlist->core); } int __evlist__add_default(struct evlist *evlist, bool precise) @@ -1626,7 +1607,7 @@ void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel) return; evlist__for_each_entry_safe(evlist, n, evsel) { - if (evsel->leader == move_evsel->leader) + if (evsel__leader(evsel) == evsel__leader(move_evsel)) list_move_tail(&evsel->core.node, &move); } @@ -1750,7 +1731,7 @@ bool evlist__exclude_kernel(struct evlist *evlist) */ void evlist__force_leader(struct evlist *evlist) { - if (!evlist->nr_groups) { + if (!evlist->core.nr_groups) { struct evsel *leader = evlist__first(evlist); evlist__set_leader(evlist); @@ -1763,7 +1744,8 @@ struct evsel *evlist__reset_weak_group(struct evlist *evsel_list, struct evsel * struct evsel *c2, *leader; bool is_open = true; - leader = evsel->leader; + leader = evsel__leader(evsel); + pr_debug("Weak group for %s/%d failed\n", leader->name, leader->core.nr_members); @@ -1774,10 +1756,10 @@ struct evsel *evlist__reset_weak_group(struct evlist *evsel_list, struct evsel * evlist__for_each_entry(evsel_list, c2) { if (c2 == evsel) is_open = false; - if (c2->leader == leader) { + if (evsel__has_leader(c2, leader)) { if (is_open && close) perf_evsel__close(&c2->core); - c2->leader = c2; + evsel__set_leader(c2, c2); c2->core.nr_members = 0; /* * Set this for all former members of the group @@ -2137,7 +2119,7 @@ struct evsel *evlist__find_evsel(struct evlist *evlist, int idx) struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->idx == idx) + if (evsel->core.idx == idx) return evsel; } return NULL; @@ -2174,13 +2156,13 @@ void evlist__check_mem_load_aux(struct evlist *evlist) * any valid memory load information. */ evlist__for_each_entry(evlist, evsel) { - leader = evsel->leader; + leader = evsel__leader(evsel); if (leader == evsel) continue; if (leader->name && strstr(leader->name, "mem-loads-aux")) { for_each_group_evsel(pos, leader) { - pos->leader = pos; + evsel__set_leader(pos, pos); pos->core.nr_members = 0; } } diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2073cfa79f79..5c22383489ae 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -50,7 +50,6 @@ enum bkw_mmap_state { struct evlist { struct perf_evlist core; - int nr_groups; bool enabled; int id_pos; int is_pos; @@ -202,7 +201,6 @@ void evlist__set_selected(struct evlist *evlist, struct evsel *evsel); int evlist__create_maps(struct evlist *evlist, struct target *target); int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel); -void __evlist__set_leader(struct list_head *list); void evlist__set_leader(struct evlist *evlist); u64 __evlist__combined_sample_type(struct evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b1c930eca40f..f61e5dd53f5d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -239,10 +239,8 @@ bool evsel__is_function_event(struct evsel *evsel) void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx) { - perf_evsel__init(&evsel->core, attr); - evsel->idx = idx; + perf_evsel__init(&evsel->core, attr, idx); evsel->tracking = !idx; - evsel->leader = evsel; evsel->unit = ""; evsel->scale = 1.0; evsel->max_events = ULONG_MAX; @@ -410,7 +408,7 @@ struct evsel *evsel__clone(struct evsel *orig) evsel->cgrp = cgroup__get(orig->cgrp); evsel->tp_format = orig->tp_format; evsel->handler = orig->handler; - evsel->leader = orig->leader; + evsel->core.leader = orig->core.leader; evsel->max_events = orig->max_events; evsel->tool_event = orig->tool_event; @@ -1075,7 +1073,7 @@ void __weak arch_evsel__set_sample_weight(struct evsel *evsel) void evsel__config(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain) { - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); struct perf_event_attr *attr = &evsel->core.attr; int track = evsel->tracking; bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; @@ -1593,7 +1591,7 @@ static int evsel__match_other_cpu(struct evsel *evsel, struct evsel *other, static int evsel__hybrid_group_cpu(struct evsel *evsel, int cpu) { - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); if ((evsel__is_hybrid(evsel) && !evsel__is_hybrid(leader)) || (!evsel__is_hybrid(evsel) && evsel__is_hybrid(leader))) { @@ -1605,7 +1603,7 @@ static int evsel__hybrid_group_cpu(struct evsel *evsel, int cpu) static int get_group_fd(struct evsel *evsel, int cpu, int thread) { - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); int fd; if (evsel__is_group_leader(evsel)) @@ -2851,3 +2849,23 @@ bool evsel__is_hybrid(struct evsel *evsel) { return evsel->pmu_name && perf_pmu__is_hybrid(evsel->pmu_name); } + +struct evsel *evsel__leader(struct evsel *evsel) +{ + return container_of(evsel->core.leader, struct evsel, core); +} + +bool evsel__has_leader(struct evsel *evsel, struct evsel *leader) +{ + return evsel->core.leader == &leader->core; +} + +bool evsel__is_leader(struct evsel *evsel) +{ + return evsel__has_leader(evsel, evsel); +} + +void evsel__set_leader(struct evsel *evsel, struct evsel *leader) +{ + evsel->core.leader = &leader->core; +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index bdad52a06438..80383096d51c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -49,7 +49,6 @@ struct evsel { struct perf_evsel core; struct evlist *evlist; off_t id_offset; - int idx; int id_pos; int is_pos; unsigned int sample_size; @@ -119,7 +118,6 @@ struct evsel { bool reset_group; bool errored; struct hashmap *per_pkg_mask; - struct evsel *leader; int err; int cpu_iter; struct { @@ -368,7 +366,7 @@ static inline struct evsel *evsel__prev(struct evsel *evsel) */ static inline bool evsel__is_group_leader(const struct evsel *evsel) { - return evsel->leader == evsel; + return evsel->core.leader == &evsel->core; } /** @@ -406,19 +404,19 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, static inline int evsel__group_idx(struct evsel *evsel) { - return evsel->idx - evsel->leader->idx; + return evsel->core.idx - evsel->core.leader->idx; } /* Iterates group WITHOUT the leader. */ #define for_each_group_member(_evsel, _leader) \ for ((_evsel) = list_entry((_leader)->core.node.next, struct evsel, core.node); \ - (_evsel) && (_evsel)->leader == (_leader); \ + (_evsel) && (_evsel)->core.leader == (&_leader->core); \ (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) /* Iterates group WITH the leader. */ #define for_each_group_evsel(_evsel, _leader) \ for ((_evsel) = _leader; \ - (_evsel) && (_evsel)->leader == (_leader); \ + (_evsel) && (_evsel)->core.leader == (&_leader->core); \ (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) static inline bool evsel__has_branch_callstack(const struct evsel *evsel) @@ -463,4 +461,8 @@ int evsel__store_ids(struct evsel *evsel, struct evlist *evlist); void evsel__zero_per_pkg(struct evsel *evsel); bool evsel__is_hybrid(struct evsel *evsel); +struct evsel *evsel__leader(struct evsel *evsel); +bool evsel__has_leader(struct evsel *evsel, struct evsel *leader); +bool evsel__is_leader(struct evsel *evsel); +void evsel__set_leader(struct evsel *evsel, struct evsel *leader); #endif /* __PERF_EVSEL_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 0158d2945bab..44249027507a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -778,7 +778,7 @@ static int write_pmu_mappings(struct feat_fd *ff, static int write_group_desc(struct feat_fd *ff, struct evlist *evlist) { - u32 nr_groups = evlist->nr_groups; + u32 nr_groups = evlist->core.nr_groups; struct evsel *evsel; int ret; @@ -789,7 +789,7 @@ static int write_group_desc(struct feat_fd *ff, evlist__for_each_entry(evlist, evsel) { if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) { const char *name = evsel->group_name ?: "{anon_group}"; - u32 leader_idx = evsel->idx; + u32 leader_idx = evsel->core.idx; u32 nr_members = evsel->core.nr_members; ret = do_write_string(ff, name); @@ -1844,7 +1844,7 @@ static struct evsel *read_event_desc(struct feat_fd *ff) msz = sz; for (i = 0, evsel = events; i < nre; evsel++, i++) { - evsel->idx = i; + evsel->core.idx = i; /* * must read entire on-file attr struct to @@ -2379,7 +2379,7 @@ static struct evsel *evlist__find_by_index(struct evlist *evlist, int idx) struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->idx == idx) + if (evsel->core.idx == idx) return evsel; } @@ -2393,7 +2393,7 @@ static void evlist__set_event_name(struct evlist *evlist, struct evsel *event) if (!event->name) return; - evsel = evlist__find_by_index(evlist, event->idx); + evsel = evlist__find_by_index(evlist, event->core.idx); if (!evsel) return; @@ -2735,12 +2735,12 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) * Rebuild group relationship based on the group_desc */ session = container_of(ff->ph, struct perf_session, header); - session->evlist->nr_groups = nr_groups; + session->evlist->core.nr_groups = nr_groups; i = nr = 0; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->idx == (int) desc[i].leader_idx) { - evsel->leader = evsel; + if (evsel->core.idx == (int) desc[i].leader_idx) { + evsel__set_leader(evsel, evsel); /* {anon_group} is a dummy name */ if (strcmp(desc[i].name, "{anon_group}")) { evsel->group_name = desc[i].name; @@ -2758,7 +2758,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) i++; } else if (nr) { /* This is a group member */ - evsel->leader = leader; + evsel__set_leader(evsel, leader); nr--; } diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index cb2520abf261..5ab631702769 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -41,8 +41,11 @@ #define INTEL_PT_RETURN 1 -/* Maximum number of loops with no packets consumed i.e. stuck in a loop */ -#define INTEL_PT_MAX_LOOPS 10000 +/* + * Default maximum number of loops with no packets consumed i.e. stuck in a + * loop. + */ +#define INTEL_PT_MAX_LOOPS 100000 struct intel_pt_blk { struct intel_pt_blk *prev; @@ -220,6 +223,7 @@ struct intel_pt_decoder { uint64_t timestamp_insn_cnt; uint64_t sample_insn_cnt; uint64_t stuck_ip; + int max_loops; int no_progress; int stuck_ip_prd; int stuck_ip_cnt; @@ -315,6 +319,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) decoder->vm_tm_corr_dry_run = params->vm_tm_corr_dry_run; decoder->first_timestamp = params->first_timestamp; decoder->last_reliable_timestamp = params->first_timestamp; + decoder->max_loops = params->max_loops ? params->max_loops : INTEL_PT_MAX_LOOPS; decoder->flags = params->flags; @@ -483,7 +488,7 @@ static const char *intel_pt_err_msgs[] = { [INTEL_PT_ERR_OVR] = "Overflow packet", [INTEL_PT_ERR_LOST] = "Lost trace data", [INTEL_PT_ERR_UNK] = "Unknown error!", - [INTEL_PT_ERR_NELOOP] = "Never-ending loop", + [INTEL_PT_ERR_NELOOP] = "Never-ending loop (refer perf config intel-pt.max-loops)", }; int intel_pt__strerror(int code, char *buf, size_t buflen) @@ -1168,7 +1173,7 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, decoder->stuck_ip = decoder->state.to_ip; decoder->stuck_ip_prd = 1; decoder->stuck_ip_cnt = 1; - } else if (cnt > INTEL_PT_MAX_LOOPS || + } else if (cnt > decoder->max_loops || decoder->state.to_ip == decoder->stuck_ip) { intel_pt_log_at("ERROR: Never-ending loop", decoder->state.to_ip); diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 714c475808c0..4b5e79fcf557 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -270,6 +270,7 @@ struct intel_pt_params { uint32_t tsc_ctc_ratio_d; enum intel_pt_param_flags flags; unsigned int quick; + int max_loops; }; struct intel_pt_decoder; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 154a1077f22e..6f852b305e92 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -123,6 +123,7 @@ struct intel_pt { u64 noretcomp_bit; unsigned max_non_turbo_ratio; unsigned cbr2khz; + int max_loops; unsigned long num_events; @@ -1200,6 +1201,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, params.vm_time_correlation = pt->synth_opts.vm_time_correlation; params.vm_tm_corr_dry_run = pt->synth_opts.vm_tm_corr_dry_run; params.first_timestamp = pt->first_timestamp; + params.max_loops = pt->max_loops; if (pt->filts.cnt > 0) params.pgd_ip = intel_pt_pgd_ip; @@ -3431,6 +3433,9 @@ static int intel_pt_perf_config(const char *var, const char *value, void *data) if (!strcmp(var, "intel-pt.mispred-all")) pt->mispred_all = perf_config_bool(var, value); + if (!strcmp(var, "intel-pt.max-loops")) + perf_config_int(&pt->max_loops, var, value); + return 0; } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index d3cf2dee36c8..99d047c5ead0 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -219,9 +219,9 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, if (has_constraint && ev->weak_group) continue; /* Ignore event if already used and merging is disabled. */ - if (metric_no_merge && test_bit(ev->idx, evlist_used)) + if (metric_no_merge && test_bit(ev->core.idx, evlist_used)) continue; - if (!has_constraint && ev->leader != current_leader) { + if (!has_constraint && !evsel__has_leader(ev, current_leader)) { /* * Start of a new group, discard the whole match and * start again. @@ -229,7 +229,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, matched_events = 0; memset(metric_events, 0, sizeof(struct evsel *) * idnum); - current_leader = ev->leader; + current_leader = evsel__leader(ev); } /* * Check for duplicate events with the same name. For example, @@ -269,7 +269,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, for (i = 0; i < idnum; i++) { ev = metric_events[i]; /* Don't free the used events. */ - set_bit(ev->idx, evlist_used); + set_bit(ev->core.idx, evlist_used); /* * The metric leader points to the identically named event in * metric_events. @@ -287,11 +287,11 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, * when then group is left. */ if (!has_constraint && - ev->leader != metric_events[i]->leader && - evsel_same_pmu_or_none(ev->leader, metric_events[i]->leader)) + ev->core.leader != metric_events[i]->core.leader && + evsel_same_pmu_or_none(evsel__leader(ev), evsel__leader(metric_events[i]))) break; if (!strcmp(metric_events[i]->name, ev->name)) { - set_bit(ev->idx, evlist_used); + set_bit(ev->core.idx, evlist_used); ev->metric_leader = metric_events[i]; } } @@ -391,7 +391,7 @@ static int metricgroup__setup_events(struct list_head *groups, } evlist__for_each_entry_safe(perf_evlist, tmp, evsel) { - if (!test_bit(evsel->idx, evlist_used)) { + if (!test_bit(evsel->core.idx, evlist_used)) { evlist__remove(perf_evlist, evsel); evsel__delete(evsel); } @@ -1312,7 +1312,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, nd = rblist__entry(old_metric_events, i); old_me = container_of(nd, struct metric_event, nd); - evsel = evlist__find_evsel(evlist, old_me->evsel->idx); + evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx); if (!evsel) return -EINVAL; new_me = metricgroup__lookup(new_metric_events, evsel, true); @@ -1320,7 +1320,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, return -ENOMEM; pr_debug("copying metric event for cgroup '%s': %s (idx=%d)\n", - cgrp ? cgrp->name : "root", evsel->name, evsel->idx); + cgrp ? cgrp->name : "root", evsel->name, evsel->core.idx); list_for_each_entry(old_expr, &old_me->head, nd) { new_expr = malloc(sizeof(*new_expr)); @@ -1363,7 +1363,7 @@ int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp, /* copy evsel in the same position */ for (idx = 0; idx < nr; idx++) { evsel = old_expr->metric_events[idx]; - evsel = evlist__find_evsel(evlist, evsel->idx); + evsel = evlist__find_evsel(evlist, evsel->core.idx); if (evsel == NULL) { free(new_expr->metric_events); free(new_expr->metric_refs); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 84108c17f48d..e5eae23cfceb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1740,7 +1740,7 @@ parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, leader = list_first_entry(list, struct evsel, core.node); evsel = list_last_entry(list, struct evsel, core.node); - total_members = evsel->idx - leader->idx + 1; + total_members = evsel->core.idx - leader->core.idx + 1; leaders = calloc(total_members, sizeof(uintptr_t)); if (WARN_ON(!leaders)) @@ -1800,7 +1800,7 @@ parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, __evlist__for_each_entry(list, evsel) { if (i >= nr_pmu) i = 0; - evsel->leader = (struct evsel *) leaders[i++]; + evsel__set_leader(evsel, (struct evsel *) leaders[i++]); } /* The number of members and group name are same for each group */ @@ -1833,7 +1833,7 @@ void parse_events__set_leader(char *name, struct list_head *list, if (parse_events__set_leader_for_uncore_aliase(name, list, parse_state)) return; - __evlist__set_leader(list); + __perf_evlist__set_leader(list); leader = list_entry(list->next, struct evsel, core.node); leader->group_name = name ? strdup(name) : NULL; } @@ -2285,7 +2285,7 @@ int __parse_events(struct evlist *evlist, const char *str, if (!ret) { struct evsel *last; - evlist->nr_groups += parse_state.nr_groups; + evlist->core.nr_groups += parse_state.nr_groups; last = evlist__last(evlist); last->cmdline_group_boundary = true; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index aba12a4d488e..9321bd0e2f76 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -316,7 +316,7 @@ event_pmu_name opt_pmu_config if (!strncmp(name, "uncore_", 7) && strncmp($1, "uncore_", 7)) name += 7; - if (!fnmatch(pattern, name, 0)) { + if (!perf_pmu__match(pattern, name, $1)) { if (parse_events_copy_term_list(orig_terms, &terms)) CLEANUP_YYABORT; if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, true, false)) diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c index 6eef6dfeaa57..dd9ed56e0504 100644 --- a/tools/perf/util/pfm.c +++ b/tools/perf/util/pfm.c @@ -110,7 +110,7 @@ int parse_libpfm_events_option(const struct option *opt, const char *str, "cannot close a non-existing event group\n"); goto error; } - evlist->nr_groups++; + evlist->core.nr_groups++; grp_leader = NULL; grp_evt = -1; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 88c8ecdc60b0..44b90d638ad5 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include "debug.h" #include "evsel.h" #include "pmu.h" @@ -740,6 +742,27 @@ struct pmu_events_map *__weak pmu_events_map__find(void) return perf_pmu__find_map(NULL); } +static bool perf_pmu__valid_suffix(char *pmu_name, char *tok) +{ + char *p; + + if (strncmp(pmu_name, tok, strlen(tok))) + return false; + + p = pmu_name + strlen(tok); + if (*p == 0) + return true; + + if (*p != '_') + return false; + + ++p; + if (*p == 0 || !isdigit(*p)) + return false; + + return true; +} + bool pmu_uncore_alias_match(const char *pmu_name, const char *name) { char *tmp = NULL, *tok, *str; @@ -768,7 +791,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name) */ for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) { name = strstr(name, tok); - if (!name) { + if (!name || !perf_pmu__valid_suffix((char *)name, tok)) { res = false; goto out; } @@ -1872,3 +1895,14 @@ bool perf_pmu__has_hybrid(void) return !list_empty(&perf_pmu__hybrid_pmus); } + +int perf_pmu__match(char *pattern, char *name, char *tok) +{ + if (fnmatch(pattern, name, 0)) + return -1; + + if (tok && !perf_pmu__valid_suffix(name, tok)) + return -1; + + return 0; +} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index a790ef758171..926da483a141 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -133,5 +133,6 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, char *name); bool perf_pmu__has_hybrid(void); +int perf_pmu__match(char *pattern, char *name, char *tok); #endif /* __PMU_H */ diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index b029c29ce227..02ef0d78053b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -118,12 +118,17 @@ struct debuginfo *debuginfo__new(const char *path) char buf[PATH_MAX], nil = '\0'; struct dso *dso; struct debuginfo *dinfo = NULL; + struct build_id bid; /* Try to open distro debuginfo files */ dso = dso__new(path); if (!dso) goto out; + /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */ + if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0) + dso__set_build_id(dso, &bid); + for (type = distro_dwarf_types; !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; type++) { diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 412f8e79e409..8feef3a05af7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1032,7 +1032,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, Py_INCREF(pevsel); evsel = &((struct pyrf_evsel *)pevsel)->evsel; - evsel->idx = evlist->core.nr_entries; + evsel->core.idx = evlist->core.nr_entries; evlist__add(evlist, evsel); return Py_BuildValue("i", evlist->core.nr_entries); diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 43e5b563dee8..bff669b615ee 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -25,12 +25,12 @@ */ static struct evsel *evsel__read_sampler(struct evsel *evsel, struct evlist *evlist) { - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); if (evsel__is_aux_event(leader) || arch_topdown_sample_read(leader) || is_mem_loads_aux_event(leader)) { evlist__for_each_entry(evlist, evsel) { - if (evsel->leader == leader && evsel != evsel->leader) + if (evsel__leader(evsel) == leader && evsel != evsel__leader(evsel)) return evsel; } } @@ -53,7 +53,7 @@ static u64 evsel__config_term_mask(struct evsel *evsel) static void evsel__config_leader_sampling(struct evsel *evsel, struct evlist *evlist) { struct perf_event_attr *attr = &evsel->core.attr; - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); struct evsel *read_sampler; u64 term_types, freq_mask; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 164d2f45028c..69129e2aa7a1 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -687,7 +687,7 @@ static void set_sample_datasrc_in_dict(PyObject *dict, _PyUnicode_FromString(decode)); } -static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) +static void regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) { unsigned int i = 0, r; int printed = 0; @@ -695,7 +695,7 @@ static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) bf[0] = 0; if (!regs || !regs->regs) - return 0; + return; for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { u64 val = regs->regs[i++]; @@ -704,8 +704,6 @@ static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) "%5s:0x%" PRIx64 " ", perf_reg_name(r), val); } - - return printed; } static void set_regs_in_dict(PyObject *dict, @@ -713,7 +711,16 @@ static void set_regs_in_dict(PyObject *dict, struct evsel *evsel) { struct perf_event_attr *attr = &evsel->core.attr; - char bf[512]; + + /* + * Here value 28 is a constant size which can be used to print + * one register value and its corresponds to: + * 16 chars is to specify 64 bit register in hexadecimal. + * 2 chars is for appending "0x" to the hexadecimal value and + * 10 chars is for register name. + */ + int size = __sw_hweight64(attr->sample_regs_intr) * 28; + char bf[size]; regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index c588a6b7a8db..83a2bc02df15 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -19,6 +19,7 @@ #include "util.h" #include "iostat.h" #include "pmu-hybrid.h" +#include "evlist-hybrid.h" #define CNTR_NOT_SUPPORTED "" #define CNTR_NOT_COUNTED "" @@ -465,9 +466,11 @@ static void printout(struct perf_stat_config *config, struct aggr_cpu_id id, int config->csv_sep); if (counter->supported) { - config->print_free_counters_hint = 1; - if (is_mixed_hw_group(counter)) - config->print_mixed_hw_group_error = 1; + if (!evlist__has_hybrid(counter->evlist)) { + config->print_free_counters_hint = 1; + if (is_mixed_hw_group(counter)) + config->print_mixed_hw_group_error = 1; + } } fprintf(config->output, "%-*s%s", diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 39967a45f55b..34a7f5c1fff7 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -379,7 +379,7 @@ void perf_stat__collect_metric_expr(struct evlist *evsel_list) evlist__for_each_entry(evsel_list, counter) { bool invalid = false; - leader = counter->leader; + leader = evsel__leader(counter); if (!counter->metric_expr) continue; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index d3ec2624e036..09ea334586f2 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -534,7 +534,7 @@ int create_perf_stat_counter(struct evsel *evsel, int cpu) { struct perf_event_attr *attr = &evsel->core.attr; - struct evsel *leader = evsel->leader; + struct evsel *leader = evsel__leader(evsel); attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; diff --git a/tools/perf/util/stream.c b/tools/perf/util/stream.c index 4bd5e5a00aa5..545e44981a27 100644 --- a/tools/perf/util/stream.c +++ b/tools/perf/util/stream.c @@ -139,7 +139,7 @@ static int evlist__init_callchain_streams(struct evlist *evlist, hists__output_resort(hists, NULL); init_hot_callchain(hists, &es[i]); - es[i].evsel_idx = pos->idx; + es[i].evsel_idx = pos->core.idx; i++; } diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index a73345730ba9..31cd59a2b66e 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1074,14 +1074,15 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, return 0; } -int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, - struct symsrc *runtime_ss, int kmodule) +static int +dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, + struct symsrc *runtime_ss, int kmodule, int dynsym) { struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; struct maps *kmaps = kmap ? map__kmaps(map) : NULL; struct map *curr_map = map; struct dso *curr_dso = dso; - Elf_Data *symstrs, *secstrs; + Elf_Data *symstrs, *secstrs, *secstrs_run, *secstrs_sym; uint32_t nr_syms; int err = -1; uint32_t idx; @@ -1098,34 +1099,15 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, if (kmap && !kmaps) return -1; - dso->symtab_type = syms_ss->type; - dso->is_64_bit = syms_ss->is_64_bit; - dso->rel = syms_ss->ehdr.e_type == ET_REL; - - /* - * Modules may already have symbols from kallsyms, but those symbols - * have the wrong values for the dso maps, so remove them. - */ - if (kmodule && syms_ss->symtab) - symbols__delete(&dso->symbols); - - if (!syms_ss->symtab) { - /* - * If the vmlinux is stripped, fail so we will fall back - * to using kallsyms. The vmlinux runtime symbols aren't - * of much use. - */ - if (dso->kernel) - goto out_elf_end; - - syms_ss->symtab = syms_ss->dynsym; - syms_ss->symshdr = syms_ss->dynshdr; - } - elf = syms_ss->elf; ehdr = syms_ss->ehdr; - sec = syms_ss->symtab; - shdr = syms_ss->symshdr; + if (dynsym) { + sec = syms_ss->dynsym; + shdr = syms_ss->dynshdr; + } else { + sec = syms_ss->symtab; + shdr = syms_ss->symshdr; + } if (elf_section_by_name(runtime_ss->elf, &runtime_ss->ehdr, &tshdr, ".text", NULL)) @@ -1150,8 +1132,16 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, if (sec_strndx == NULL) goto out_elf_end; - secstrs = elf_getdata(sec_strndx, NULL); - if (secstrs == NULL) + secstrs_run = elf_getdata(sec_strndx, NULL); + if (secstrs_run == NULL) + goto out_elf_end; + + sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); + if (sec_strndx == NULL) + goto out_elf_end; + + secstrs_sym = elf_getdata(sec_strndx, NULL); + if (secstrs_sym == NULL) goto out_elf_end; nr_syms = shdr.sh_size / shdr.sh_entsize; @@ -1237,6 +1227,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, gelf_getshdr(sec, &shdr); + secstrs = secstrs_sym; + /* * We have to fallback to runtime when syms' section header has * NOBITS set. NOBITS results in file offset (sh_offset) not @@ -1249,6 +1241,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, goto out_elf_end; gelf_getshdr(sec, &shdr); + secstrs = secstrs_run; } if (is_label && !elf_sec__filter(&shdr, secstrs)) @@ -1312,6 +1305,50 @@ out_elf_end: return err; } +int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, + struct symsrc *runtime_ss, int kmodule) +{ + int nr = 0; + int err = -1; + + dso->symtab_type = syms_ss->type; + dso->is_64_bit = syms_ss->is_64_bit; + dso->rel = syms_ss->ehdr.e_type == ET_REL; + + /* + * Modules may already have symbols from kallsyms, but those symbols + * have the wrong values for the dso maps, so remove them. + */ + if (kmodule && syms_ss->symtab) + symbols__delete(&dso->symbols); + + if (!syms_ss->symtab) { + /* + * If the vmlinux is stripped, fail so we will fall back + * to using kallsyms. The vmlinux runtime symbols aren't + * of much use. + */ + if (dso->kernel) + return err; + } else { + err = dso__load_sym_internal(dso, map, syms_ss, runtime_ss, + kmodule, 0); + if (err < 0) + return err; + nr = err; + } + + if (syms_ss->dynsym) { + err = dso__load_sym_internal(dso, map, syms_ss, runtime_ss, + kmodule, 1); + if (err < 0) + return err; + err += nr; + } + + return err; +} + static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data) { GElf_Phdr phdr; diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc index 2950bfbc6fce..adae72665500 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc @@ -39,6 +39,24 @@ grep "parent_comm: $COMM" events/sched/sched_process_fork/hist > /dev/null || \ reset_trigger +echo "Test histogram with sym modifier" + +echo 'hist:keys=call_site.sym' > events/kmem/kmalloc/trigger +for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done +grep '{ call_site: \[[0-9a-f][0-9a-f]*\] [_a-zA-Z][_a-zA-Z]* *}' events/kmem/kmalloc/hist > /dev/null || \ + fail "sym modifier on kmalloc call_site did not work" + +reset_trigger + +echo "Test histogram with sym-offset modifier" + +echo 'hist:keys=call_site.sym-offset' > events/kmem/kmalloc/trigger +for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done +grep '{ call_site: \[[0-9a-f][0-9a-f]*\] [_a-zA-Z][_a-zA-Z]*+0x[0-9a-f][0-9a-f]*' events/kmem/kmalloc/hist > /dev/null || \ + fail "sym-offset modifier on kmalloc call_site did not work" + +reset_trigger + echo "Test histogram with sort key" echo 'hist:keys=parent_pid,child_pid:sort=child_pid.ascending' > events/sched/sched_process_fork/trigger diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c index 8934a3766d20..c53b070755b6 100644 --- a/tools/testing/selftests/sigaltstack/sas.c +++ b/tools/testing/selftests/sigaltstack/sas.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "../kselftest.h" @@ -24,6 +25,11 @@ #define SS_AUTODISARM (1U << 31) #endif +#ifndef AT_MINSIGSTKSZ +#define AT_MINSIGSTKSZ 51 +#endif + +static unsigned int stack_size; static void *sstack, *ustack; static ucontext_t uc, sc; static const char *msg = "[OK]\tStack preserved"; @@ -47,7 +53,7 @@ void my_usr1(int sig, siginfo_t *si, void *u) #endif if (sp < (unsigned long)sstack || - sp >= (unsigned long)sstack + SIGSTKSZ) { + sp >= (unsigned long)sstack + stack_size) { ksft_exit_fail_msg("SP is not on sigaltstack\n"); } /* put some data on stack. other sighandler will try to overwrite it */ @@ -108,6 +114,10 @@ int main(void) stack_t stk; int err; + /* Make sure more than the required minimum. */ + stack_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ; + ksft_print_msg("[NOTE]\tthe stack size is %lu\n", stack_size); + ksft_print_header(); ksft_set_plan(3); @@ -117,7 +127,7 @@ int main(void) sigaction(SIGUSR1, &act, NULL); act.sa_sigaction = my_usr2; sigaction(SIGUSR2, &act, NULL); - sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, + sstack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (sstack == MAP_FAILED) { ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); @@ -139,7 +149,7 @@ int main(void) } stk.ss_sp = sstack; - stk.ss_size = SIGSTKSZ; + stk.ss_size = stack_size; stk.ss_flags = SS_ONSTACK | SS_AUTODISARM; err = sigaltstack(&stk, NULL); if (err) { @@ -161,7 +171,7 @@ int main(void) } } - ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, + ustack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (ustack == MAP_FAILED) { ksft_exit_fail_msg("mmap() - %s\n", strerror(errno)); @@ -170,7 +180,7 @@ int main(void) getcontext(&uc); uc.uc_link = NULL; uc.uc_stack.ss_sp = ustack; - uc.uc_stack.ss_size = SIGSTKSZ; + uc.uc_stack.ss_size = stack_size; makecontext(&uc, switch_fn, 0); raise(SIGUSR1); diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index d683a49d07d5..f0fd80ef17df 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore @@ -24,5 +24,6 @@ va_128TBswitch map_fixed_noreplace write_to_hugetlbfs hmm-tests +memfd_secret local_config.* split_huge_page_test diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 812bc03e3142..521243770f26 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -35,6 +35,7 @@ TEST_GEN_FILES += madv_populate TEST_GEN_FILES += map_fixed_noreplace TEST_GEN_FILES += map_hugetlb TEST_GEN_FILES += map_populate +TEST_GEN_FILES += memfd_secret TEST_GEN_FILES += mlock-random-test TEST_GEN_FILES += mlock2-tests TEST_GEN_FILES += mremap_dontunmap @@ -135,7 +136,7 @@ warn_32bit_failure: endif endif -$(OUTPUT)/mlock-random-test: LDLIBS += -lcap +$(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS += -lcap $(OUTPUT)/gup_test: ../../../../mm/gup_test.h diff --git a/tools/testing/selftests/vm/memfd_secret.c b/tools/testing/selftests/vm/memfd_secret.c new file mode 100644 index 000000000000..93e7e7ffed33 --- /dev/null +++ b/tools/testing/selftests/vm/memfd_secret.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright IBM Corporation, 2021 + * + * Author: Mike Rapoport + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +#define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__) +#define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__) +#define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__) + +#ifdef __NR_memfd_secret + +#define PATTERN 0x55 + +static const int prot = PROT_READ | PROT_WRITE; +static const int mode = MAP_SHARED; + +static unsigned long page_size; +static unsigned long mlock_limit_cur; +static unsigned long mlock_limit_max; + +static int memfd_secret(unsigned int flags) +{ + return syscall(__NR_memfd_secret, flags); +} + +static void test_file_apis(int fd) +{ + char buf[64]; + + if ((read(fd, buf, sizeof(buf)) >= 0) || + (write(fd, buf, sizeof(buf)) >= 0) || + (pread(fd, buf, sizeof(buf), 0) >= 0) || + (pwrite(fd, buf, sizeof(buf), 0) >= 0)) + fail("unexpected file IO\n"); + else + pass("file IO is blocked as expected\n"); +} + +static void test_mlock_limit(int fd) +{ + size_t len; + char *mem; + + len = mlock_limit_cur; + mem = mmap(NULL, len, prot, mode, fd, 0); + if (mem == MAP_FAILED) { + fail("unable to mmap secret memory\n"); + return; + } + munmap(mem, len); + + len = mlock_limit_max * 2; + mem = mmap(NULL, len, prot, mode, fd, 0); + if (mem != MAP_FAILED) { + fail("unexpected mlock limit violation\n"); + munmap(mem, len); + return; + } + + pass("mlock limit is respected\n"); +} + +static void try_process_vm_read(int fd, int pipefd[2]) +{ + struct iovec liov, riov; + char buf[64]; + char *mem; + + if (read(pipefd[0], &mem, sizeof(mem)) < 0) { + fail("pipe write: %s\n", strerror(errno)); + exit(KSFT_FAIL); + } + + liov.iov_len = riov.iov_len = sizeof(buf); + liov.iov_base = buf; + riov.iov_base = mem; + + if (process_vm_readv(getppid(), &liov, 1, &riov, 1, 0) < 0) { + if (errno == ENOSYS) + exit(KSFT_SKIP); + exit(KSFT_PASS); + } + + exit(KSFT_FAIL); +} + +static void try_ptrace(int fd, int pipefd[2]) +{ + pid_t ppid = getppid(); + int status; + char *mem; + long ret; + + if (read(pipefd[0], &mem, sizeof(mem)) < 0) { + perror("pipe write"); + exit(KSFT_FAIL); + } + + ret = ptrace(PTRACE_ATTACH, ppid, 0, 0); + if (ret) { + perror("ptrace_attach"); + exit(KSFT_FAIL); + } + + ret = waitpid(ppid, &status, WUNTRACED); + if ((ret != ppid) || !(WIFSTOPPED(status))) { + fprintf(stderr, "weird waitppid result %ld stat %x\n", + ret, status); + exit(KSFT_FAIL); + } + + if (ptrace(PTRACE_PEEKDATA, ppid, mem, 0)) + exit(KSFT_PASS); + + exit(KSFT_FAIL); +} + +static void check_child_status(pid_t pid, const char *name) +{ + int status; + + waitpid(pid, &status, 0); + + if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) { + skip("%s is not supported\n", name); + return; + } + + if ((WIFEXITED(status) && WEXITSTATUS(status) == KSFT_PASS) || + WIFSIGNALED(status)) { + pass("%s is blocked as expected\n", name); + return; + } + + fail("%s: unexpected memory access\n", name); +} + +static void test_remote_access(int fd, const char *name, + void (*func)(int fd, int pipefd[2])) +{ + int pipefd[2]; + pid_t pid; + char *mem; + + if (pipe(pipefd)) { + fail("pipe failed: %s\n", strerror(errno)); + return; + } + + pid = fork(); + if (pid < 0) { + fail("fork failed: %s\n", strerror(errno)); + return; + } + + if (pid == 0) { + func(fd, pipefd); + return; + } + + mem = mmap(NULL, page_size, prot, mode, fd, 0); + if (mem == MAP_FAILED) { + fail("Unable to mmap secret memory\n"); + return; + } + + ftruncate(fd, page_size); + memset(mem, PATTERN, page_size); + + if (write(pipefd[1], &mem, sizeof(mem)) < 0) { + fail("pipe write: %s\n", strerror(errno)); + return; + } + + check_child_status(pid, name); +} + +static void test_process_vm_read(int fd) +{ + test_remote_access(fd, "process_vm_read", try_process_vm_read); +} + +static void test_ptrace(int fd) +{ + test_remote_access(fd, "ptrace", try_ptrace); +} + +static int set_cap_limits(rlim_t max) +{ + struct rlimit new; + cap_t cap = cap_init(); + + new.rlim_cur = max; + new.rlim_max = max; + if (setrlimit(RLIMIT_MEMLOCK, &new)) { + perror("setrlimit() returns error"); + return -1; + } + + /* drop capabilities including CAP_IPC_LOCK */ + if (cap_set_proc(cap)) { + perror("cap_set_proc() returns error"); + return -2; + } + + return 0; +} + +static void prepare(void) +{ + struct rlimit rlim; + + page_size = sysconf(_SC_PAGE_SIZE); + if (!page_size) + ksft_exit_fail_msg("Failed to get page size %s\n", + strerror(errno)); + + if (getrlimit(RLIMIT_MEMLOCK, &rlim)) + ksft_exit_fail_msg("Unable to detect mlock limit: %s\n", + strerror(errno)); + + mlock_limit_cur = rlim.rlim_cur; + mlock_limit_max = rlim.rlim_max; + + printf("page_size: %ld, mlock.soft: %ld, mlock.hard: %ld\n", + page_size, mlock_limit_cur, mlock_limit_max); + + if (page_size > mlock_limit_cur) + mlock_limit_cur = page_size; + if (page_size > mlock_limit_max) + mlock_limit_max = page_size; + + if (set_cap_limits(mlock_limit_max)) + ksft_exit_fail_msg("Unable to set mlock limit: %s\n", + strerror(errno)); +} + +#define NUM_TESTS 4 + +int main(int argc, char *argv[]) +{ + int fd; + + prepare(); + + ksft_print_header(); + ksft_set_plan(NUM_TESTS); + + fd = memfd_secret(0); + if (fd < 0) { + if (errno == ENOSYS) + ksft_exit_skip("memfd_secret is not supported\n"); + else + ksft_exit_fail_msg("memfd_secret failed: %s\n", + strerror(errno)); + } + + test_mlock_limit(fd); + test_file_apis(fd); + test_process_vm_read(fd); + test_ptrace(fd); + + close(fd); + + ksft_exit(!ksft_get_fail_cnt()); +} + +#else /* __NR_memfd_secret */ + +int main(int argc, char *argv[]) +{ + printf("skip: skipping memfd_secret test (missing __NR_memfd_secret)\n"); + return KSFT_SKIP; +} + +#endif /* __NR_memfd_secret */ diff --git a/tools/testing/selftests/vm/mremap_test.c b/tools/testing/selftests/vm/mremap_test.c index 9c391d016922..0624d1bd71b5 100644 --- a/tools/testing/selftests/vm/mremap_test.c +++ b/tools/testing/selftests/vm/mremap_test.c @@ -45,14 +45,15 @@ enum { _4MB = 4ULL << 20, _1GB = 1ULL << 30, _2GB = 2ULL << 30, - PTE = _4KB, PMD = _2MB, PUD = _1GB, }; +#define PTE page_size + #define MAKE_TEST(source_align, destination_align, size, \ overlaps, should_fail, test_name) \ -{ \ +(struct test){ \ .name = test_name, \ .config = { \ .src_alignment = source_align, \ @@ -74,9 +75,10 @@ static void *get_source_mapping(struct config c) retry: addr += c.src_alignment; src_addr = mmap((void *) addr, c.region_size, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, -1, 0); + MAP_FIXED_NOREPLACE | MAP_ANONYMOUS | MAP_SHARED, + -1, 0); if (src_addr == MAP_FAILED) { - if (errno == EPERM) + if (errno == EPERM || errno == EEXIST) goto retry; goto error; } @@ -252,12 +254,17 @@ static int parse_args(int argc, char **argv, unsigned int *threshold_mb, return 0; } +#define MAX_TEST 13 +#define MAX_PERF_TEST 3 int main(int argc, char **argv) { int failures = 0; int i, run_perf_tests; unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD; unsigned int pattern_seed; + struct test test_cases[MAX_TEST]; + struct test perf_test_cases[MAX_PERF_TEST]; + int page_size; time_t t; pattern_seed = (unsigned int) time(&t); @@ -268,56 +275,59 @@ int main(int argc, char **argv) ksft_print_msg("Test configs:\n\tthreshold_mb=%u\n\tpattern_seed=%u\n\n", threshold_mb, pattern_seed); - struct test test_cases[] = { - /* Expected mremap failures */ - MAKE_TEST(_4KB, _4KB, _4KB, OVERLAPPING, EXPECT_FAILURE, - "mremap - Source and Destination Regions Overlapping"), - MAKE_TEST(_4KB, _1KB, _4KB, NON_OVERLAPPING, EXPECT_FAILURE, - "mremap - Destination Address Misaligned (1KB-aligned)"), - MAKE_TEST(_1KB, _4KB, _4KB, NON_OVERLAPPING, EXPECT_FAILURE, - "mremap - Source Address Misaligned (1KB-aligned)"), + page_size = sysconf(_SC_PAGESIZE); - /* Src addr PTE aligned */ - MAKE_TEST(PTE, PTE, _8KB, NON_OVERLAPPING, EXPECT_SUCCESS, - "8KB mremap - Source PTE-aligned, Destination PTE-aligned"), + /* Expected mremap failures */ + test_cases[0] = MAKE_TEST(page_size, page_size, page_size, + OVERLAPPING, EXPECT_FAILURE, + "mremap - Source and Destination Regions Overlapping"); - /* Src addr 1MB aligned */ - MAKE_TEST(_1MB, PTE, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2MB mremap - Source 1MB-aligned, Destination PTE-aligned"), - MAKE_TEST(_1MB, _1MB, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2MB mremap - Source 1MB-aligned, Destination 1MB-aligned"), + test_cases[1] = MAKE_TEST(page_size, page_size/4, page_size, + NON_OVERLAPPING, EXPECT_FAILURE, + "mremap - Destination Address Misaligned (1KB-aligned)"); + test_cases[2] = MAKE_TEST(page_size/4, page_size, page_size, + NON_OVERLAPPING, EXPECT_FAILURE, + "mremap - Source Address Misaligned (1KB-aligned)"); - /* Src addr PMD aligned */ - MAKE_TEST(PMD, PTE, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, - "4MB mremap - Source PMD-aligned, Destination PTE-aligned"), - MAKE_TEST(PMD, _1MB, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, - "4MB mremap - Source PMD-aligned, Destination 1MB-aligned"), - MAKE_TEST(PMD, PMD, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, - "4MB mremap - Source PMD-aligned, Destination PMD-aligned"), + /* Src addr PTE aligned */ + test_cases[3] = MAKE_TEST(PTE, PTE, PTE * 2, + NON_OVERLAPPING, EXPECT_SUCCESS, + "8KB mremap - Source PTE-aligned, Destination PTE-aligned"); - /* Src addr PUD aligned */ - MAKE_TEST(PUD, PTE, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2GB mremap - Source PUD-aligned, Destination PTE-aligned"), - MAKE_TEST(PUD, _1MB, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2GB mremap - Source PUD-aligned, Destination 1MB-aligned"), - MAKE_TEST(PUD, PMD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2GB mremap - Source PUD-aligned, Destination PMD-aligned"), - MAKE_TEST(PUD, PUD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "2GB mremap - Source PUD-aligned, Destination PUD-aligned"), - }; + /* Src addr 1MB aligned */ + test_cases[4] = MAKE_TEST(_1MB, PTE, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2MB mremap - Source 1MB-aligned, Destination PTE-aligned"); + test_cases[5] = MAKE_TEST(_1MB, _1MB, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2MB mremap - Source 1MB-aligned, Destination 1MB-aligned"); - struct test perf_test_cases[] = { - /* - * mremap 1GB region - Page table level aligned time - * comparison. - */ - MAKE_TEST(PTE, PTE, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "1GB mremap - Source PTE-aligned, Destination PTE-aligned"), - MAKE_TEST(PMD, PMD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "1GB mremap - Source PMD-aligned, Destination PMD-aligned"), - MAKE_TEST(PUD, PUD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, - "1GB mremap - Source PUD-aligned, Destination PUD-aligned"), - }; + /* Src addr PMD aligned */ + test_cases[6] = MAKE_TEST(PMD, PTE, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, + "4MB mremap - Source PMD-aligned, Destination PTE-aligned"); + test_cases[7] = MAKE_TEST(PMD, _1MB, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, + "4MB mremap - Source PMD-aligned, Destination 1MB-aligned"); + test_cases[8] = MAKE_TEST(PMD, PMD, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS, + "4MB mremap - Source PMD-aligned, Destination PMD-aligned"); + + /* Src addr PUD aligned */ + test_cases[9] = MAKE_TEST(PUD, PTE, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2GB mremap - Source PUD-aligned, Destination PTE-aligned"); + test_cases[10] = MAKE_TEST(PUD, _1MB, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2GB mremap - Source PUD-aligned, Destination 1MB-aligned"); + test_cases[11] = MAKE_TEST(PUD, PMD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2GB mremap - Source PUD-aligned, Destination PMD-aligned"); + test_cases[12] = MAKE_TEST(PUD, PUD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "2GB mremap - Source PUD-aligned, Destination PUD-aligned"); + + perf_test_cases[0] = MAKE_TEST(page_size, page_size, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "1GB mremap - Source PTE-aligned, Destination PTE-aligned"); + /* + * mremap 1GB region - Page table level aligned time + * comparison. + */ + perf_test_cases[1] = MAKE_TEST(PMD, PMD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "1GB mremap - Source PMD-aligned, Destination PMD-aligned"); + perf_test_cases[2] = MAKE_TEST(PUD, PUD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS, + "1GB mremap - Source PUD-aligned, Destination PUD-aligned"); run_perf_tests = (threshold_mb == VALIDATION_NO_THRESHOLD) || (threshold_mb * _1MB >= _1GB); diff --git a/tools/testing/selftests/vm/run_vmtests.sh b/tools/testing/selftests/vm/run_vmtests.sh index 955782d138ab..d09a6b71f1e9 100755 --- a/tools/testing/selftests/vm/run_vmtests.sh +++ b/tools/testing/selftests/vm/run_vmtests.sh @@ -362,4 +362,21 @@ else exitcode=1 fi +echo "running memfd_secret test" +echo "------------------------------------" +./memfd_secret +ret_val=$? + +if [ $ret_val -eq 0 ]; then + echo "[PASS]" +elif [ $ret_val -eq $ksft_skip ]; then + echo "[SKIP]" + exitcode=$ksft_skip +else + echo "[FAIL]" + exitcode=1 +fi + +exit $exitcode + exit $exitcode diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 333980375bc7..b4142cd1c5c2 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -13,11 +13,12 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vsyscall mov_ss_trap \ - syscall_arg_fault fsgsbase_restore + syscall_arg_fault fsgsbase_restore sigaltstack TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer -TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip syscall_numbering +TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip syscall_numbering \ + corrupt_xstate_header # Some selftests require 32bit support enabled also on 64bit systems TARGETS_C_32BIT_NEEDED := ldt_gdt ptrace_syscall diff --git a/tools/testing/selftests/x86/corrupt_xstate_header.c b/tools/testing/selftests/x86/corrupt_xstate_header.c new file mode 100644 index 000000000000..ab8599c10ce5 --- /dev/null +++ b/tools/testing/selftests/x86/corrupt_xstate_header.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Corrupt the XSTATE header in a signal frame + * + * Based on analysis and a test case from Thomas Gleixner. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + asm volatile( + "cpuid;" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +static inline int xsave_enabled(void) +{ + unsigned int eax, ebx, ecx, edx; + + eax = 0x1; + ecx = 0x0; + __cpuid(&eax, &ebx, &ecx, &edx); + + /* Is CR4.OSXSAVE enabled ? */ + return ecx & (1U << 27); +} + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static void sigusr1(int sig, siginfo_t *info, void *uc_void) +{ + ucontext_t *uc = uc_void; + uint8_t *fpstate = (uint8_t *)uc->uc_mcontext.fpregs; + uint64_t *xfeatures = (uint64_t *)(fpstate + 512); + + printf("\tWreck XSTATE header\n"); + /* Wreck the first reserved bytes in the header */ + *(xfeatures + 2) = 0xfffffff; +} + +static void sigsegv(int sig, siginfo_t *info, void *uc_void) +{ + printf("\tGot SIGSEGV\n"); +} + +int main(void) +{ + cpu_set_t set; + + sethandler(SIGUSR1, sigusr1, 0); + sethandler(SIGSEGV, sigsegv, 0); + + if (!xsave_enabled()) { + printf("[SKIP] CR4.OSXSAVE disabled.\n"); + return 0; + } + + CPU_ZERO(&set); + CPU_SET(0, &set); + + /* + * Enforce that the child runs on the same CPU + * which in turn forces a schedule. + */ + sched_setaffinity(getpid(), sizeof(set), &set); + + printf("[RUN]\tSend ourselves a signal\n"); + raise(SIGUSR1); + + printf("[OK]\tBack from the signal. Now schedule.\n"); + pid_t child = fork(); + if (child < 0) + err(1, "fork"); + if (child == 0) + return 0; + if (child) + waitpid(child, NULL, 0); + printf("[OK]\tBack in the main thread.\n"); + + /* + * We could try to confirm that extended state is still preserved + * when we schedule. For now, the only indication of failure is + * a warning in the kernel logs. + */ + + return 0; +} diff --git a/tools/testing/selftests/x86/sigaltstack.c b/tools/testing/selftests/x86/sigaltstack.c new file mode 100644 index 000000000000..f689af75e979 --- /dev/null +++ b/tools/testing/selftests/x86/sigaltstack.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* sigaltstack()-enforced minimum stack */ +#define ENFORCED_MINSIGSTKSZ 2048 + +#ifndef AT_MINSIGSTKSZ +# define AT_MINSIGSTKSZ 51 +#endif + +static int nerrs; + +static bool sigalrm_expected; + +static unsigned long at_minstack_size; + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static void clearhandler(int sig) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static int setup_altstack(void *start, unsigned long size) +{ + stack_t ss; + + memset(&ss, 0, sizeof(ss)); + ss.ss_size = size; + ss.ss_sp = start; + + return sigaltstack(&ss, NULL); +} + +static jmp_buf jmpbuf; + +static void sigsegv(int sig, siginfo_t *info, void *ctx_void) +{ + if (sigalrm_expected) { + printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM)."); + nerrs++; + } else { + printf("[OK]\tSIGSEGV signal delivered.\n"); + } + + siglongjmp(jmpbuf, 1); +} + +static void sigalrm(int sig, siginfo_t *info, void *ctx_void) +{ + if (!sigalrm_expected) { + printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV)."); + nerrs++; + } else { + printf("[OK]\tSIGALRM signal delivered.\n"); + } +} + +static void test_sigaltstack(void *altstack, unsigned long size) +{ + if (setup_altstack(altstack, size)) + err(1, "sigaltstack()"); + + sigalrm_expected = (size > at_minstack_size) ? true : false; + + sethandler(SIGSEGV, sigsegv, 0); + sethandler(SIGALRM, sigalrm, SA_ONSTACK); + + if (!sigsetjmp(jmpbuf, 1)) { + printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n", + sigalrm_expected ? "" : "in"); + printf("\tRaise SIGALRM. %s is expected to be delivered.\n", + sigalrm_expected ? "It" : "SIGSEGV"); + raise(SIGALRM); + } + + clearhandler(SIGALRM); + clearhandler(SIGSEGV); +} + +int main(void) +{ + void *altstack; + + at_minstack_size = getauxval(AT_MINSIGSTKSZ); + + altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (altstack == MAP_FAILED) + err(1, "mmap()"); + + if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size) + test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1); + + test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ); + + return nerrs == 0 ? 0 : 1; +}