diff options
52 files changed, 815 insertions, 500 deletions
diff --git a/.clang-format b/.clang-format index d988e9fa9b26..2048b0296d76 100644 --- a/.clang-format +++ b/.clang-format @@ -520,6 +520,7 @@ ForEachMacros: - 'of_property_for_each_string' - 'of_property_for_each_u32' - 'pci_bus_for_each_resource' + - 'pci_dev_for_each_resource' - 'pci_doe_for_each_off' - 'pcl_for_each_chunk' - 'pcl_for_each_segment' diff --git a/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml b/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml new file mode 100644 index 000000000000..a5bd90bc0712 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/amlogic,axg-pcie.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson AXG DWC PCIe SoC controller + +maintainers: + - Neil Armstrong <neil.armstrong@linaro.org> + +description: + Amlogic Meson PCIe host controller is based on the Synopsys DesignWare PCI core. + +allOf: + - $ref: /schemas/pci/pci-bus.yaml# + - $ref: /schemas/pci/snps,dw-pcie-common.yaml# + +# We need a select here so we don't match all nodes with 'snps,dw-pcie' +select: + properties: + compatible: + enum: + - amlogic,axg-pcie + - amlogic,g12a-pcie + required: + - compatible + +properties: + compatible: + items: + - enum: + - amlogic,axg-pcie + - amlogic,g12a-pcie + - const: snps,dw-pcie + + reg: + items: + - description: External local bus interface registers + - description: Meson designed configuration registers + - description: PCIe configuration space + + reg-names: + items: + - const: elbi + - const: cfg + - const: config + + interrupts: + maxItems: 1 + + clocks: + items: + - description: PCIe GEN 100M PLL clock + - description: PCIe RC clock gate + - description: PCIe PHY clock + + clock-names: + items: + - const: pclk + - const: port + - const: general + + phys: + maxItems: 1 + + phy-names: + const: pcie + + resets: + items: + - description: Port Reset + - description: Shared APB reset + + reset-names: + items: + - const: port + - const: apb + + num-lanes: + const: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - interrupts + - clock + - clock-names + - "#address-cells" + - "#size-cells" + - "#interrupt-cells" + - interrupt-map + - interrupt-map-mask + - ranges + - bus-range + - device_type + - num-lanes + - phys + - phy-names + - resets + - reset-names + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + pcie: pcie@f9800000 { + compatible = "amlogic,axg-pcie", "snps,dw-pcie"; + reg = <0xf9800000 0x400000>, <0xff646000 0x2000>, <0xf9f00000 0x100000>; + reg-names = "elbi", "cfg", "config"; + interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>; + clocks = <&pclk>, <&clk_port>, <&clk_phy>; + clock-names = "pclk", "port", "general"; + resets = <&reset_pcie_port>, <&reset_pcie_apb>; + reset-names = "port", "apb"; + phys = <&pcie_phy>; + phy-names = "pcie"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 179 IRQ_TYPE_EDGE_RISING>; + bus-range = <0x0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <1>; + ranges = <0x82000000 0 0 0xf9c00000 0 0x00300000>; + }; +... diff --git a/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt b/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt deleted file mode 100644 index c3a75ac6e59d..000000000000 --- a/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt +++ /dev/null @@ -1,70 +0,0 @@ -Amlogic Meson AXG DWC PCIE SoC controller - -Amlogic Meson PCIe host controller is based on the Synopsys DesignWare PCI core. -It shares common functions with the PCIe DesignWare core driver and -inherits common properties defined in -Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml. - -Additional properties are described here: - -Required properties: -- compatible: - should contain : - - "amlogic,axg-pcie" for AXG SoC Family - - "amlogic,g12a-pcie" for G12A SoC Family - to identify the core. -- reg: - should contain the configuration address space. -- reg-names: Must be - - "elbi" External local bus interface registers - - "cfg" Meson specific registers - - "config" PCIe configuration space -- reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal. -- clocks: Must contain an entry for each entry in clock-names. -- clock-names: Must include the following entries: - - "pclk" PCIe GEN 100M PLL clock - - "port" PCIe_x(A or B) RC clock gate - - "general" PCIe Phy clock -- resets: phandle to the reset lines. -- reset-names: must contain "port" and "apb" - - "port" Port A or B reset - - "apb" Share APB reset -- phys: should contain a phandle to the PCIE phy -- phy-names: must contain "pcie" - -- device_type: - should be "pci". As specified in snps,dw-pcie.yaml - - -Example configuration: - - pcie: pcie@f9800000 { - compatible = "amlogic,axg-pcie", "snps,dw-pcie"; - reg = <0x0 0xf9800000 0x0 0x400000 - 0x0 0xff646000 0x0 0x2000 - 0x0 0xf9f00000 0x0 0x100000>; - reg-names = "elbi", "cfg", "config"; - reset-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; - interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 179 IRQ_TYPE_EDGE_RISING>; - bus-range = <0x0 0xff>; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges = <0x82000000 0 0 0x0 0xf9c00000 0 0x00300000>; - - clocks = <&clkc CLKID_USB - &clkc CLKID_PCIE_A - &clkc CLKID_PCIE_CML_EN0>; - clock-names = "general", - "pclk", - "port"; - resets = <&reset RESET_PCIE_A>, - <&reset RESET_PCIE_APB>; - reset-names = "port", - "apb"; - phys = <&pcie_phy>; - phy-names = "pcie"; - }; diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml new file mode 100644 index 000000000000..9bff8ecb653c --- /dev/null +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml @@ -0,0 +1,279 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/fsl,imx6q-pcie-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX6 PCIe RC/EP controller + +maintainers: + - Lucas Stach <l.stach@pengutronix.de> + - Richard Zhu <hongxing.zhu@nxp.com> + +description: + Generic Freescale i.MX PCIe Root Port and Endpoint controller + properties. + +properties: + clocks: + minItems: 3 + items: + - description: PCIe bridge clock. + - description: PCIe bus clock. + - description: PCIe PHY clock. + - description: Additional required clock entry for imx6sx-pcie, + imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep. + + clock-names: + minItems: 3 + items: + - const: pcie + - const: pcie_bus + - enum: [ pcie_phy, pcie_aux ] + - enum: [ pcie_inbound_axi, pcie_aux ] + + num-lanes: + const: 1 + + fsl,imx7d-pcie-phy: + $ref: /schemas/types.yaml#/definitions/phandle + description: A phandle to an fsl,imx7d-pcie-phy node. Additional + required properties for imx7d-pcie, imx7d-pcie-ep, imx8mq-pcie, + and imx8mq-pcie-ep. + + power-domains: + minItems: 1 + items: + - description: The phandle pointing to the DISPLAY domain for + imx6sx-pcie, imx6sx-pcie-ep, to PCIE_PHY power domain for + imx7d-pcie, imx7d-pcie-ep, imx8mq-pcie and imx8mq-pcie-ep. + - description: The phandle pointing to the PCIE_PHY power domains + for imx6sx-pcie and imx6sx-pcie-ep. + + power-domain-names: + minItems: 1 + items: + - const: pcie + - const: pcie_phy + + resets: + minItems: 2 + maxItems: 3 + description: Phandles to PCIe-related reset lines exposed by SRC + IP block. Additional required by imx7d-pcie, imx7d-pcie-ep, + imx8mq-pcie, and imx8mq-pcie-ep. + + reset-names: + minItems: 2 + maxItems: 3 + + fsl,tx-deemph-gen1: + description: Gen1 De-emphasis value (optional required). + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + fsl,tx-deemph-gen2-3p5db: + description: Gen2 (3.5db) De-emphasis value (optional required). + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + fsl,tx-deemph-gen2-6db: + description: Gen2 (6db) De-emphasis value (optional required). + $ref: /schemas/types.yaml#/definitions/uint32 + default: 20 + + fsl,tx-swing-full: + description: Gen2 TX SWING FULL value (optional required). + $ref: /schemas/types.yaml#/definitions/uint32 + default: 127 + + fsl,tx-swing-low: + description: TX launch amplitude swing_low value (optional required). + $ref: /schemas/types.yaml#/definitions/uint32 + default: 127 + + fsl,max-link-speed: + description: Specify PCI Gen for link capability (optional required). + Note that the IMX6 LVDS clock outputs do not meet gen2 jitter + requirements and thus for gen2 capability a gen2 compliant clock + generator should be used and configured. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 3, 4] + default: 1 + + phys: + maxItems: 1 + + phy-names: + const: pcie-phy + + vpcie-supply: + description: Should specify the regulator in charge of PCIe port power. + 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 (optional required). + + vph-supply: + description: 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 (optional required). + +required: + - clocks + - clock-names + - num-lanes + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6sx-pcie + - fsl,imx6sx-pcie-ep + then: + properties: + clock-names: + items: + - {} + - {} + - const: pcie_phy + - const: pcie_inbound_axi + power-domains: + minItems: 2 + power-domain-names: + minItems: 2 + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mq-pcie + - fsl,imx8mq-pcie-ep + then: + properties: + clock-names: + items: + - {} + - {} + - const: pcie_phy + - const: pcie_aux + - if: + properties: + compatible: + not: + contains: + enum: + - fsl,imx6sx-pcie + - fsl,imx8mq-pcie + - fsl,imx6sx-pcie-ep + - fsl,imx8mq-pcie-ep + then: + properties: + clocks: + maxItems: 3 + clock-names: + maxItems: 3 + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6q-pcie + - fsl,imx6qp-pcie + - fsl,imx7d-pcie + - fsl,imx6q-pcie-ep + - fsl,imx6qp-pcie-ep + - fsl,imx7d-pcie-ep + then: + properties: + clock-names: + maxItems: 3 + contains: + const: pcie_phy + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mm-pcie + - fsl,imx8mp-pcie + - fsl,imx8mm-pcie-ep + - fsl,imx8mp-pcie-ep + then: + properties: + clock-names: + maxItems: 3 + contains: + const: pcie_aux + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6q-pcie + - fsl,imx6qp-pcie + - fsl,imx6q-pcie-ep + - fsl,imx6qp-pcie-ep + then: + properties: + power-domains: false + power-domain-names: false + + - if: + not: + properties: + compatible: + contains: + enum: + - fsl,imx6sx-pcie + - fsl,imx6q-pcie + - fsl,imx6qp-pcie + - fsl,imx6sx-pcie-ep + - fsl,imx6q-pcie-ep + - fsl,imx6qp-pcie-ep + then: + properties: + power-domains: + maxItems: 1 + power-domain-names: false + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6q-pcie + - fsl,imx6sx-pcie + - fsl,imx6qp-pcie + - fsl,imx7d-pcie + - fsl,imx8mq-pcie + - fsl,imx6q-pcie-ep + - fsl,imx6sx-pcie-ep + - fsl,imx6qp-pcie-ep + - fsl,imx7d-pcie-ep + - fsl,imx8mq-pcie-ep + then: + properties: + resets: + minItems: 3 + reset-names: + items: + - const: pciephy + - const: apps + - const: turnoff + else: + properties: + resets: + maxItems: 2 + reset-names: + items: + - const: apps + - const: turnoff + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml new file mode 100644 index 000000000000..f4a328ec1daa --- /dev/null +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/fsl,imx6q-pcie-ep.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX6 PCIe Endpoint controller + +maintainers: + - Lucas Stach <l.stach@pengutronix.de> + - Richard Zhu <hongxing.zhu@nxp.com> + +description: |+ + This PCIe controller is based on the Synopsys DesignWare PCIe IP and + thus inherits all the common properties defined in snps,dw-pcie-ep.yaml. + The controller instances are dual mode where in they can work either in + Root Port mode or Endpoint mode but one at a time. + +properties: + compatible: + enum: + - fsl,imx8mm-pcie-ep + - fsl,imx8mq-pcie-ep + - fsl,imx8mp-pcie-ep + + reg: + minItems: 2 + + reg-names: + items: + - const: dbi + - const: addr_space + + interrupts: + items: + - description: builtin eDMA interrupter. + + interrupt-names: + items: + - const: dma + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + +allOf: + - $ref: /schemas/pci/snps,dw-pcie-ep.yaml# + - $ref: /schemas/pci/fsl,imx6q-pcie-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/power/imx8mp-power.h> + #include <dt-bindings/reset/imx8mp-reset.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + pcie_ep: pcie-ep@33800000 { + compatible = "fsl,imx8mp-pcie-ep"; + reg = <0x33800000 0x000400000>, <0x18000000 0x08000000>; + reg-names = "dbi", "addr_space"; + clocks = <&clk IMX8MP_CLK_HSIO_ROOT>, + <&clk IMX8MP_CLK_HSIO_AXI>, + <&clk IMX8MP_CLK_PCIE_ROOT>; + clock-names = "pcie", "pcie_bus", "pcie_aux"; + assigned-clocks = <&clk IMX8MP_CLK_PCIE_AUX>; + assigned-clock-rates = <10000000>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_50M>; + num-lanes = <1>; + interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>; /* eDMA */ + interrupt-names = "dma"; + fsl,max-link-speed = <3>; + power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_PCIE>; + resets = <&src IMX8MP_RESET_PCIE_CTRL_APPS_EN>, + <&src IMX8MP_RESET_PCIE_CTRL_APPS_TURNOFF>; + reset-names = "apps", "turnoff"; + phys = <&pcie_phy>; + phy-names = "pcie-phy"; + num-ib-windows = <4>; + num-ob-windows = <4>; + }; diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml index f13f87fddb3d..2443641754d3 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml @@ -13,6 +13,11 @@ maintainers: description: |+ This PCIe host controller is based on the Synopsys DesignWare PCIe IP and thus inherits all the common properties defined in snps,dw-pcie.yaml. + The controller instances are dual mode where in they can work either in + Root Port mode or Endpoint mode but one at a time. + + See fsl,imx6q-pcie-ep.yaml for details on the Endpoint mode device tree + bindings. properties: compatible: @@ -24,9 +29,6 @@ properties: - fsl,imx8mq-pcie - fsl,imx8mm-pcie - fsl,imx8mp-pcie - - fsl,imx8mm-pcie-ep - - fsl,imx8mq-pcie-ep - - fsl,imx8mp-pcie-ep reg: items: @@ -46,96 +48,6 @@ properties: items: - const: msi - clocks: - minItems: 3 - items: - - description: PCIe bridge clock. - - description: PCIe bus clock. - - description: PCIe PHY clock. - - description: Additional required clock entry for imx6sx-pcie, - imx8mq-pcie. - - clock-names: - minItems: 3 - items: - - const: pcie - - const: pcie_bus - - enum: [ pcie_phy, pcie_aux ] - - enum: [ pcie_inbound_axi, pcie_aux ] - - num-lanes: - const: 1 - - fsl,imx7d-pcie-phy: - $ref: /schemas/types.yaml#/definitions/phandle - description: A phandle to an fsl,imx7d-pcie-phy node. Additional - required properties for imx7d-pcie and imx8mq-pcie. - - power-domains: - minItems: 1 - items: - - description: The phandle pointing to the DISPLAY domain for - imx6sx-pcie, to PCIE_PHY power domain for imx7d-pcie and - imx8mq-pcie. - - description: The phandle pointing to the PCIE_PHY power domains - for imx6sx-pcie. - - power-domain-names: - minItems: 1 - items: - - const: pcie - - const: pcie_phy - - resets: - minItems: 2 - maxItems: 3 - description: Phandles to PCIe-related reset lines exposed by SRC - IP block. Additional required by imx7d-pcie and imx8mq-pcie. - - reset-names: - minItems: 2 - maxItems: 3 - - fsl,tx-deemph-gen1: - description: Gen1 De-emphasis value (optional required). - $ref: /schemas/types.yaml#/definitions/uint32 - default: 0 - - fsl,tx-deemph-gen2-3p5db: - description: Gen2 (3.5db) De-emphasis value (optional required). - $ref: /schemas/types.yaml#/definitions/uint32 - default: 0 - - fsl,tx-deemph-gen2-6db: - description: Gen2 (6db) De-emphasis value (optional required). - $ref: /schemas/types.yaml#/definitions/uint32 - default: 20 - - fsl,tx-swing-full: - description: Gen2 TX SWING FULL value (optional required). - $ref: /schemas/types.yaml#/definitions/uint32 - default: 127 - - fsl,tx-swing-low: - description: TX launch amplitude swing_low value (optional required). - $ref: /schemas/types.yaml#/definitions/uint32 - default: 127 - - fsl,max-link-speed: - description: Specify PCI Gen for link capability (optional required). - Note that the IMX6 LVDS clock outputs do not meet gen2 jitter - requirements and thus for gen2 capability a gen2 compliant clock - generator should be used and configured. - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2, 3, 4] - default: 1 - - phys: - maxItems: 1 - - phy-names: - const: pcie-phy - reset-gpio: description: Should specify the GPIO for controlling the PCI bus device reset signal. It's not polarity aware and defaults to active-low reset @@ -147,17 +59,6 @@ properties: L=operation state) (optional required). type: boolean - vpcie-supply: - description: Should specify the regulator in charge of PCIe port power. - 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 (optional required). - - vph-supply: - description: 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 (optional required). - required: - compatible - reg @@ -167,144 +68,15 @@ required: - device_type - bus-range - ranges - - num-lanes - interrupts - interrupt-names - "#interrupt-cells" - interrupt-map-mask - interrupt-map - - clocks - - clock-names allOf: - $ref: /schemas/pci/snps,dw-pcie.yaml# - - if: - properties: - compatible: - contains: - const: fsl,imx6sx-pcie - then: - properties: - clock-names: - items: - - {} - - {} - - const: pcie_phy - - const: pcie_inbound_axi - power-domains: - minItems: 2 - power-domain-names: - minItems: 2 - - if: - properties: - compatible: - contains: - const: fsl,imx8mq-pcie - then: - properties: - clock-names: - items: - - {} - - {} - - const: pcie_phy - - const: pcie_aux - - if: - properties: - compatible: - not: - contains: - enum: - - fsl,imx6sx-pcie - - fsl,imx8mq-pcie - then: - properties: - clocks: - maxItems: 3 - clock-names: - maxItems: 3 - - - if: - properties: - compatible: - contains: - enum: - - fsl,imx6q-pcie - - fsl,imx6qp-pcie - - fsl,imx7d-pcie - then: - properties: - clock-names: - maxItems: 3 - contains: - const: pcie_phy - - - if: - properties: - compatible: - contains: - enum: - - fsl,imx8mm-pcie - - fsl,imx8mp-pcie - then: - properties: - clock-names: - maxItems: 3 - contains: - const: pcie_aux - - if: - properties: - compatible: - contains: - enum: - - fsl,imx6q-pcie - - fsl,imx6qp-pcie - then: - properties: - power-domains: false - power-domain-names: false - - - if: - not: - properties: - compatible: - contains: - enum: - - fsl,imx6sx-pcie - - fsl,imx6q-pcie - - fsl,imx6qp-pcie - then: - properties: - power-domains: - maxItems: 1 - power-domain-names: false - - - if: - properties: - compatible: - contains: - enum: - - fsl,imx6q-pcie - - fsl,imx6sx-pcie - - fsl,imx6qp-pcie - - fsl,imx7d-pcie - - fsl,imx8mq-pcie - then: - properties: - resets: - minItems: 3 - reset-names: - items: - - const: pciephy - - const: apps - - const: turnoff - else: - properties: - resets: - maxItems: 2 - reset-names: - items: - - const: apps - - const: turnoff + - $ref: /schemas/pci/fsl,imx6q-pcie-common.yaml# unevaluatedProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 8d5bc223f305..3032b2c74931 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15973,6 +15973,8 @@ M: Lucas Stach <l.stach@pengutronix.de> L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml +F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml F: drivers/pci/controller/dwc/*imx6* diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 64fbfb0763b2..4458eb7f44f0 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -288,11 +288,10 @@ pcibios_claim_one_bus(struct pci_bus *b) struct pci_bus *child_bus; list_for_each_entry(dev, &b->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; if (pci_has_flag(PCI_PROBE_ONLY) || diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index e7ef2b5bea9c..d334c7fb672b 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -142,15 +142,15 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, */ static void pci_fixup_dec21285(struct pci_dev *dev) { - int i; - if (dev->devfn == 0) { + struct resource *r; + dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } @@ -162,13 +162,11 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_d static void pci_fixup_ide_bases(struct pci_dev *dev) { struct resource *r; - int i; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) return; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - r = dev->resource + i; + pci_dev_for_each_resource(dev, r) { if ((r->start & ~0x80) == 0x374) { r->start |= 2; r->end = r->start; diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 754ca381f600..3044b7e03890 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -142,14 +142,14 @@ static struct pci_ops pcie_ops = { static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index 6190f538a124..0ebc909ea273 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -186,14 +186,14 @@ static struct pci_ops pcie_ops = { static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 888fdc9099c5..3313bc5a63ea 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -522,14 +522,14 @@ static int __init pci_setup(struct pci_sys_data *sys) static void rc_pci_fixup(struct pci_dev *dev) { if (dev->bus->parent == NULL && dev->devfn == 0) { - int i; + struct resource *r; dev->class &= 0xff; dev->class |= PCI_CLASS_BRIDGE_HOST << 8; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index dc6dc2741272..b0ea023c47c0 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -413,18 +413,18 @@ struct pci_ops bcm63xx_cb_ops = { static void bcm63xx_fixup(struct pci_dev *dev) { static int io_window = -1; - int i, found, new_io_window; + int found, new_io_window; + struct resource *r; u32 val; /* look for any io resource */ found = 0; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(dev, i) & IORESOURCE_IO) { + pci_dev_for_each_resource(dev, r) { + if (resource_type(r) == IORESOURCE_IO) { found = 1; break; } } - if (!found) return; diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index 468722c8a5c6..ec2567f8efd8 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -249,12 +249,11 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + pci_dev_for_each_resource(dev, r, idx) { /* Only set up the requested stuff */ if (!(mask & (1<<idx))) continue; - r = &dev->resource[idx]; if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) continue; if ((idx == PCI_ROM_RESOURCE) && diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index d67cf79bf5d0..e88d7c9feeec 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -880,6 +880,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) static void pcibios_fixup_resources(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct resource *res; int i; if (!hose) { @@ -891,9 +892,9 @@ static void pcibios_fixup_resources(struct pci_dev *dev) if (dev->is_virtfn) return; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = dev->resource + i; + pci_dev_for_each_resource(dev, res, i) { struct pci_bus_region reg; + if (!res->flags) continue; @@ -1452,11 +1453,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) struct pci_bus *child_bus; list_for_each_entry(dev, &bus->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; @@ -1705,19 +1705,20 @@ EXPORT_SYMBOL_GPL(pcibios_scan_phb); static void fixup_hide_host_resource_fsl(struct pci_dev *dev) { - int i, class = dev->class >> 8; + int class = dev->class >> 8; /* When configured as agent, programming interface = 1 */ int prog_if = dev->class & 0xf; + struct resource *r; if ((class == PCI_CLASS_PROCESSOR_POWERPC || class == PCI_CLASS_BRIDGE_OTHER) && (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) && (prog_if == 0) && (dev->bus->parent == NULL)) { - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/powerpc/platforms/4xx/pci.c b/arch/powerpc/platforms/4xx/pci.c index ca5dd7a5842a..07dcc2b8007f 100644 --- a/arch/powerpc/platforms/4xx/pci.c +++ b/arch/powerpc/platforms/4xx/pci.c @@ -57,7 +57,7 @@ static inline int ppc440spe_revA(void) static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) { struct pci_controller *hose; - int i; + struct resource *r; if (dev->devfn != 0 || dev->bus->self != NULL) return; @@ -79,9 +79,9 @@ static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) /* Hide the PCI host BARs from the kernel as their content doesn't * fit well in the resource management */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = r->end = 0; + r->flags = 0; } printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 859e2818c43d..0ca4401ba781 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -327,14 +327,13 @@ mpc52xx_pci_setup(struct pci_controller *hose, static void mpc52xx_pci_fixup_resources(struct pci_dev *dev) { - int i; + struct resource *res; pr_debug("%s() %.4x:%.4x\n", __func__, dev->vendor, dev->device); /* We don't rely on boot loader for PCI and resets all devices */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = &dev->resource[i]; + pci_dev_for_each_resource(dev, res) { if (res->end > res->start) { /* Only valid resources */ res->end -= res->start; res->start = 0; diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 60e0a58928ef..1772ae3d193d 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -240,7 +240,7 @@ void __init pSeries_final_fixup(void) */ static void fixup_winbond_82c105(struct pci_dev* dev) { - int i; + struct resource *r; unsigned int reg; if (!machine_is(pseries)) @@ -251,14 +251,14 @@ static void fixup_winbond_82c105(struct pci_dev* dev) /* Enable LEGIRQ to use INTC instead of ISA interrupts */ pci_write_config_dword(dev, 0x40, reg | (1<<11)); - for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { + pci_dev_for_each_resource(dev, r) { /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - if (dev->resource[i].start == 0 && dev->resource[i].end) { - dev->resource[i].flags = 0; - dev->resource[i].end = 0; + if (dev->bus->number == 0 && dev->devfn == 0x81 && + r->flags & IORESOURCE_IO) + r->flags &= ~IORESOURCE_IO; + if (r->start == 0 && r->end) { + r->flags = 0; + r->end = 0; } } } diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index b0c2a5238d04..4f5e49f10805 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -140,12 +140,12 @@ static void sh7786_pci_fixup(struct pci_dev *dev) * Prevent enumeration of root complex resources. */ if (pci_is_root_bus(dev->bus) && dev->devfn == 0) { - int i; + struct resource *r; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + pci_dev_for_each_resource(dev, r) { + r->start = 0; + r->end = 0; + r->flags = 0; } } } diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index e5e5ff6b9a5c..b6663a3fbae9 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -62,15 +62,14 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) int pcibios_enable_device(struct pci_dev *dev, int mask) { + struct resource *res; u16 cmd, oldcmd; int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); oldcmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1<<i))) continue; diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index cb1ef25116e9..a948a49817c7 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -663,11 +663,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus) struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (r->parent || !r->start || !r->flags) continue; @@ -724,15 +723,14 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, int pcibios_enable_device(struct pci_dev *dev, int mask) { + struct resource *res; u16 cmd, oldcmd; int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); oldcmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1<<i))) continue; diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index ee4c9a9a171c..25fe0a061732 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -643,15 +643,14 @@ void pcibios_fixup_bus(struct pci_bus *bus) int pcibios_enable_device(struct pci_dev *dev, int mask) { + struct resource *res; u16 cmd, oldcmd; int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); oldcmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - + pci_dev_for_each_resource(dev, res, i) { /* Only set up the requested stuff */ if (!(mask & (1<<i))) continue; diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 615a76d70019..c6c46605812b 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -824,3 +824,62 @@ static void rs690_fix_64bit_dma(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma); #endif + +/* + * When returning from D3cold to D0, firmware on some Google Coral and Reef + * family Chromebooks with Intel Apollo Lake SoC clobbers the headers of + * both the L1 PM Substates capability and the previous capability for the + * "Celeron N3350/Pentium N4200/Atom E3900 Series PCI Express Port B #1". + * + * Save those values at enumeration-time and restore them at resume. + */ + +static u16 prev_cap, l1ss_cap; +static u32 prev_header, l1ss_header; + +static void chromeos_save_apl_pci_l1ss_capability(struct pci_dev *dev) +{ + int pos = PCI_CFG_SPACE_SIZE, prev = 0; + u32 header, pheader = 0; + + while (pos) { + pci_read_config_dword(dev, pos, &header); + if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_L1SS) { + prev_cap = prev; + prev_header = pheader; + l1ss_cap = pos; + l1ss_header = header; + return; + } + + prev = pos; + pheader = header; + pos = PCI_EXT_CAP_NEXT(header); + } +} + +static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev) +{ + u32 header; + + if (!prev_cap || !prev_header || !l1ss_cap || !l1ss_header) + return; + + /* Fixup the header of L1SS Capability if missing */ + pci_read_config_dword(dev, l1ss_cap, &header); + if (header != l1ss_header) { + pci_write_config_dword(dev, l1ss_cap, l1ss_header); + pci_info(dev, "restore L1SS Capability header (was %#010x now %#010x)\n", + header, l1ss_header); + } + + /* Fixup the link to L1SS Capability if missing */ + pci_read_config_dword(dev, prev_cap, &header); + if (header != prev_header) { + pci_write_config_dword(dev, prev_cap, prev_header); + pci_info(dev, "restore previous Capability header (was %#010x now %#010x)\n", + header, prev_header); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability); diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index 930c2332c3c4..8173e60bb808 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -20,8 +20,8 @@ static struct eisa_root_device pci_eisa_root; static int __init pci_eisa_init(struct pci_dev *pdev) { - int rc, i; struct resource *res, *bus_res = NULL; + int rc; if ((rc = pci_enable_device (pdev))) { dev_err(&pdev->dev, "Could not enable device\n"); @@ -38,7 +38,7 @@ static int __init pci_eisa_init(struct pci_dev *pdev) * eisa_root_register() can only deal with a single io port resource, * so we use the first valid io port resource. */ - pci_bus_for_each_resource(pdev->bus, res, i) + pci_bus_for_each_resource(pdev->bus, res) if (res && (res->flags & IORESOURCE_IO)) { bus_res = res; break; diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c index 36d3b8b9da47..fa9c1c3bf168 100644 --- a/drivers/firmware/efi/cper-arm.c +++ b/drivers/firmware/efi/cper-arm.c @@ -12,7 +12,6 @@ #include <linux/dmi.h> #include <linux/acpi.h> #include <linux/pci.h> -#include <linux/aer.h> #include <linux/printk.h> #include <linux/bcd.h> #include <acpi/ghes.h> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 83ae838ceb5f..f37f23574ad8 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -161,13 +161,13 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, void *alignf_data, struct pci_bus_region *region) { - int i, ret; struct resource *r, avail; resource_size_t max; + int ret; type_mask |= IORESOURCE_TYPE_BITS; - pci_bus_for_each_resource(bus, r, i) { + pci_bus_for_each_resource(bus, r) { resource_size_t min_used = min; if (!r) @@ -268,9 +268,8 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx) struct resource *res = &dev->resource[idx]; struct resource orig_res = *res; struct resource *r; - int i; - pci_bus_for_each_resource(bus, r, i) { + pci_bus_for_each_resource(bus, r) { resource_size_t start, end; if (!r) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 434f6a4f4041..d29551261e80 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -307,6 +307,7 @@ config PCIE_KIRIN tristate "HiSilicon Kirin series SoCs PCIe controllers" depends on PCI_MSI select PCIE_DW_HOST + select REGMAP_MMIO help Say Y here if you want PCIe controller support on HiSilicon Kirin series SoCs. diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 55a0405b921d..52906f999f2b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1566,6 +1566,13 @@ DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_SYNOPSYS, 0xabcd, static int __init imx6_pcie_init(void) { #ifdef CONFIG_ARM + struct device_node *np; + + np = of_find_matching_node(NULL, imx6_pcie_of_match); + if (!np) + return -ENODEV; + of_node_put(np); + /* * Since probe() can be deferred we need to make sure that * hook_fault_code is not called after __init memory is freed diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index ad99707b3b99..c640db60edc6 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -110,6 +110,7 @@ static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = { }; static const struct of_device_id ls_pcie_ep_of_match[] = { + { .compatible = "fsl,ls1028a-pcie-ep", .data = &ls1_ep_drvdata }, { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata }, { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata }, { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata }, diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c index 654ac4a82beb..e44252db6085 100644 --- a/drivers/pci/controller/pci-ixp4xx.c +++ b/drivers/pci/controller/pci-ixp4xx.c @@ -26,6 +26,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/bits.h> +#include "../pci.h" /* Register offsets */ #define IXP4XX_PCI_NP_AD 0x00 @@ -188,12 +189,13 @@ 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); + return (PCI_CONF1_ADDRESS(0, 0, PCI_FUNC(devfn), where) & + ~PCI_CONF1_ENABLE) | BIT(32-PCI_SLOT(devfn)); } else { /* type 1 */ - return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | - ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; + return (PCI_CONF1_ADDRESS(bus_num, PCI_SLOT(devfn), + PCI_FUNC(devfn), where) & + ~PCI_CONF1_ENABLE) | 1; } } diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index 74c109f14ff0..79630885b9c8 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -1375,7 +1375,7 @@ static int tegra_pcie_phys_get(struct tegra_pcie *pcie) struct tegra_pcie_port *port; int err; - if (!soc->has_gen2 || of_find_property(np, "phys", NULL) != NULL) + if (!soc->has_gen2 || of_property_present(np, "phys")) return tegra_pcie_phys_get_legacy(pcie); list_for_each_entry(port, &pcie->ports, list) { @@ -1944,7 +1944,7 @@ static bool of_regulator_bulk_available(struct device_node *np, for (i = 0; i < num_supplies; i++) { snprintf(property, 32, "%s-supply", supplies[i].supply); - if (of_find_property(np, property, NULL) == NULL) + if (!of_property_present(np, property)) return false; } diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index ae5ad05ddc1d..31de7a29192c 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -643,7 +643,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, return err; } - if (of_find_property(dev->of_node, "interrupt-names", NULL)) + if (of_property_present(dev->of_node, "interrupt-names")) port->irq = platform_get_irq_byname(pdev, "pcie_irq"); else port->irq = platform_get_irq(pdev, port->slot); diff --git a/drivers/pci/controller/pcie-mt7621.c b/drivers/pci/controller/pcie-mt7621.c index 63a5f4463a9f..a445ec314375 100644 --- a/drivers/pci/controller/pcie-mt7621.c +++ b/drivers/pci/controller/pcie-mt7621.c @@ -378,8 +378,8 @@ static int mt7621_pcie_init_ports(struct mt7621_pcie *pcie) u32 slot = port->slot; if (!mt7621_pcie_port_is_linkup(port)) { - dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", - slot); + dev_info(dev, "pcie%d no card, disable it (RST & CLK)\n", + slot); mt7621_control_assert(port); port->enabled = false; num_disabled++; diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index d17f3bf36f70..ad12515a4a12 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -63,7 +63,14 @@ int pciehp_configure_device(struct controller *ctrl) pci_assign_unassigned_bridge_resources(bridge); pcie_bus_configure_settings(parent); + + /* + * Release reset_lock during driver binding + * to avoid AB-BA deadlock with device_lock. + */ + up_read(&ctrl->reset_lock); pci_bus_add_devices(parent); + down_read_nested(&ctrl->reset_lock, ctrl->depth); out: pci_unlock_rescan_remove(); @@ -104,7 +111,15 @@ void pciehp_unconfigure_device(struct controller *ctrl, bool presence) list_for_each_entry_safe_reverse(dev, temp, &parent->devices, bus_list) { pci_dev_get(dev); + + /* + * Release reset_lock during driver unbinding + * to avoid AB-BA deadlock with device_lock. + */ + up_read(&ctrl->reset_lock); pci_stop_and_remove_bus_device(dev); + down_read_nested(&ctrl->reset_lock, ctrl->depth); + /* * Ensure that no new Requests will be generated from * the device. diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 491986197c47..2316de0fd198 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -278,7 +278,7 @@ int rpaphp_check_drc_props(struct device_node *dn, char *drc_name, return -EINVAL; } - if (of_find_property(dn->parent, "ibm,drc-info", NULL)) + if (of_property_present(dn->parent, "ibm,drc-info")) return rpaphp_check_drc_props_v2(dn, drc_name, drc_type, be32_to_cpu(*my_index)); else @@ -440,7 +440,7 @@ int rpaphp_add_slot(struct device_node *dn) if (!of_node_name_eq(dn, "pci")) return 0; - if (of_find_property(dn, "ibm,drc-info", NULL)) + if (of_property_present(dn, "ibm,drc-info")) return rpaphp_drc_info_add_slot(dn); else return rpaphp_drc_add_slot(dn); diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index 64beed7a26be..01d47a42da04 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -24,16 +24,16 @@ static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; - int index, busnr; struct resource *res; struct pci_bus *bus; size_t len = 0; + int busnr; pdev = to_pci_dev(dev); bus = pdev->subordinate; len += sysfs_emit_at(buf, len, "Free resources: memory\n"); - pci_bus_for_each_resource(bus, res, index) { + pci_bus_for_each_resource(bus, res) { if (res && (res->flags & IORESOURCE_MEM) && !(res->flags & IORESOURCE_PREFETCH)) { len += sysfs_emit_at(buf, len, @@ -43,7 +43,7 @@ static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char } } len += sysfs_emit_at(buf, len, "Free resources: prefetchable memory\n"); - pci_bus_for_each_resource(bus, res, index) { + pci_bus_for_each_resource(bus, res) { if (res && (res->flags & IORESOURCE_MEM) && (res->flags & IORESOURCE_PREFETCH)) { len += sysfs_emit_at(buf, len, @@ -53,7 +53,7 @@ static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char } } len += sysfs_emit_at(buf, len, "Free resources: IO\n"); - pci_bus_for_each_resource(bus, res, index) { + pci_bus_for_each_resource(bus, res) { if (res && (res->flags & IORESOURCE_IO)) { len += sysfs_emit_at(buf, len, "start = %8.8llx, length = %8.8llx\n", diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 196834ed44fe..e085f2eca372 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -447,7 +447,7 @@ static int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args * return -ENODEV; /* Local interrupt-map in the device node? Use it! */ - if (of_get_property(dn, "interrupt-map", NULL)) { + if (of_property_present(dn, "interrupt-map")) { pin = pci_swizzle_interrupt_pin(pdev, pin); ppnode = dn; } diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 9e8205572830..6cd98ffca198 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -746,8 +746,7 @@ EXPORT_SYMBOL_GPL(pci_has_p2pmem); /** * pci_p2pmem_find_many - find a peer-to-peer DMA memory device compatible with - * the specified list of clients and shortest distance (as determined - * by pci_p2pmem_dma()) + * the specified list of clients and shortest distance * @clients: array of devices to check (NULL-terminated) * @num_clients: number of client devices in the list * diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 57ddcc59af30..ae9baf801681 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -572,7 +572,8 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) { - pci_bridge_wait_for_secondary_bus(pci_dev, "resume", PCI_RESET_WAIT); + pci_bridge_wait_for_secondary_bus(pci_dev, "resume"); + /* * When powering on a bridge from D3cold, the whole hierarchy may be * powered on into D0uninitialized state, resume them to give them a diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7a67611dc5f4..199024beaee9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -64,6 +64,14 @@ struct pci_pme_device { #define PME_TIMEOUT 1000 /* How long between PME checks */ +/* + * Devices may extend the 1 sec period through Request Retry Status + * completions (PCIe r6.0 sec 2.3.1). The spec does not provide an upper + * limit, but 60 sec ought to be enough for any device to become + * responsive. + */ +#define PCIE_RESET_READY_POLL_MS 60000 /* msec */ + static void pci_dev_d3_sleep(struct pci_dev *dev) { unsigned int delay_ms = max(dev->d3hot_delay, pci_pm_d3hot_delay); @@ -779,9 +787,8 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev, { const struct pci_bus *bus = dev->bus; struct resource *r; - int i; - pci_bus_for_each_resource(bus, r, i) { + pci_bus_for_each_resource(bus, r) { if (!r) continue; if (resource_contains(r, res)) { @@ -4939,7 +4946,6 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus) * pci_bridge_wait_for_secondary_bus - Wait for secondary bus to be accessible * @dev: PCI bridge * @reset_type: reset type in human-readable form - * @timeout: maximum time to wait for devices on secondary bus (milliseconds) * * Handle necessary delays before access to the devices on the secondary * side of the bridge are permitted after D3cold to D0 transition @@ -4952,8 +4958,7 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus) * Return 0 on success or -ENOTTY if the first device on the secondary bus * failed to become accessible. */ -int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type, - int timeout) +int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) { struct pci_dev *child; int delay; @@ -5031,7 +5036,8 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type, } } - return pci_dev_wait(child, reset_type, timeout - delay); + return pci_dev_wait(child, reset_type, + PCIE_RESET_READY_POLL_MS - delay); } void pci_reset_secondary_bus(struct pci_dev *dev) @@ -5068,8 +5074,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev) { pcibios_reset_secondary_bus(dev); - return pci_bridge_wait_for_secondary_bus(dev, "bus reset", - PCIE_RESET_READY_POLL_MS); + return pci_bridge_wait_for_secondary_bus(dev, "bus reset"); } EXPORT_SYMBOL_GPL(pci_bridge_secondary_bus_reset); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d2c08670a20e..022da58afb33 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -70,12 +70,6 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, * Reset (PCIe r6.0 sec 5.8). */ #define PCI_RESET_WAIT 1000 /* msec */ -/* - * Devices may extend the 1 sec period through Request Retry Status completions - * (PCIe r6.0 sec 2.3.1). The spec does not provide an upper limit, but 60 sec - * ought to be enough for any device to become responsive. - */ -#define PCIE_RESET_READY_POLL_MS 60000 /* msec */ void pci_update_current_state(struct pci_dev *dev, pci_power_t state); void pci_refresh_power_state(struct pci_dev *dev); @@ -100,8 +94,7 @@ void pci_msix_init(struct pci_dev *dev); bool pci_bridge_d3_possible(struct pci_dev *dev); void pci_bridge_d3_update(struct pci_dev *dev); void pci_bridge_reconfigure_ltr(struct pci_dev *dev); -int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type, - int timeout); +int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type); static inline void pci_wakeup_event(struct pci_dev *dev) { diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index a5d7c69b764e..3ceed8e3de41 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -170,8 +170,7 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, PCI_EXP_DPC_STATUS_TRIGGER); - if (pci_bridge_wait_for_secondary_bus(pdev, "DPC", - PCIE_RESET_READY_POLL_MS)) { + if (pci_bridge_wait_for_secondary_bus(pdev, "DPC")) { clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); ret = PCI_ERS_RESULT_DISCONNECT; } else { diff --git a/drivers/pci/pcie/edr.c b/drivers/pci/pcie/edr.c index a6b9b479b97a..5f4914d313a1 100644 --- a/drivers/pci/pcie/edr.c +++ b/drivers/pci/pcie/edr.c @@ -151,9 +151,18 @@ static void edr_handle_event(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_DISCONNECT_RECOVER) return; + /* + * pdev is a Root Port or Downstream Port that is still present and + * has triggered a containment event, e.g., DPC, so its child + * devices have been disconnected (ACPI r6.5, sec 5.6.6). + */ pci_info(pdev, "EDR event received\n"); - /* Locate the port which issued EDR event */ + /* + * Locate the port that experienced the containment event. pdev + * may be that port or a parent of it (PCI Firmware r3.3, sec + * 4.6.13). + */ edev = acpi_dpc_port_get(pdev); if (!edev) { pci_err(pdev, "Firmware failed to locate DPC port\n"); @@ -193,6 +202,7 @@ send_ost: */ if (estate == PCI_ERS_RESULT_RECOVERED) { pci_dbg(edev, "DPC port successfully recovered\n"); + pcie_clear_device_status(edev); acpi_send_edr_status(pdev, edev, EDR_OST_SUCCESS); } else { pci_dbg(edev, "DPC port recovery failed\n"); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3f68b6ba6ac..f8191750f6b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -533,7 +533,7 @@ void pci_read_bridge_bases(struct pci_bus *child) pci_read_bridge_mmio_pref(child); if (dev->transparent) { - pci_bus_for_each_resource(child->parent, res, i) { + pci_bus_for_each_resource(child->parent, res) { if (res && res->flags) { pci_bus_add_resource(child, res, PCI_SUBTRACTIVE_DECODE); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 44cab813bf95..f4e2a88729fd 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1940,6 +1940,19 @@ static void quirk_radeon_pm(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6741, quirk_radeon_pm); /* + * NVIDIA Ampere-based HDA controllers can wedge the whole device if a bus + * reset is performed too soon after transition to D0, extend d3hot_delay + * to previous effective default for all NVIDIA HDA controllers. + */ +static void quirk_nvidia_hda_pm(struct pci_dev *dev) +{ + quirk_d3hot_delay(dev, 20); +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, + quirk_nvidia_hda_pm); + +/* * Ryzen5/7 XHCI controllers fail upon resume from runtime suspend or s2idle. * https://bugzilla.kernel.org/show_bug.cgi?id=205587 * diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 0145aef1b930..c049eddc1e2f 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -5,10 +5,9 @@ static void pci_free_resources(struct pci_dev *dev) { - int i; + struct resource *res; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = dev->resource + i; + pci_dev_for_each_resource(dev, res) { if (res->parent) release_resource(res); } diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index c690572b10ce..fdeb121e9175 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -124,20 +124,17 @@ static resource_size_t get_res_add_align(struct list_head *head, return dev_res ? dev_res->min_align : 0; } - /* Sort resources by alignment */ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r; + pci_dev_for_each_resource(dev, r, i) { struct pci_dev_resource *dev_res, *tmp; resource_size_t r_align; struct list_head *n; - r = &dev->resource[i]; - if (r->flags & IORESOURCE_PCI_FIXED) continue; @@ -773,9 +770,8 @@ static struct resource *find_bus_resource_of_type(struct pci_bus *bus, unsigned long type) { struct resource *r, *r_assigned = NULL; - int i; - pci_bus_for_each_resource(bus, r, i) { + pci_bus_for_each_resource(bus, r) { if (r == &ioport_resource || r == &iomem_resource) continue; if (r && (r->flags & type_mask) == type && !r->parent) @@ -895,10 +891,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, min_align = window_alignment(bus, IORESOURCE_IO); list_for_each_entry(dev, &bus->devices, bus_list) { - int i; + struct resource *r; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; + pci_dev_for_each_resource(dev, r) { unsigned long r_size; if (r->parent || !(r->flags & IORESOURCE_IO)) @@ -1014,10 +1009,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, size = 0; list_for_each_entry(dev, &bus->devices, bus_list) { + struct resource *r; int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; + pci_dev_for_each_resource(dev, r, i) { resource_size_t r_size; if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) || @@ -1208,7 +1203,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) additional_mmio_pref_size = 0; struct resource *pref; struct pci_host_bridge *host; - int hdr_type, i, ret; + int hdr_type, ret; list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; @@ -1232,7 +1227,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) host = to_pci_host_bridge(bus->bridge); if (!host->size_windows) return; - pci_bus_for_each_resource(bus, pref, i) + pci_bus_for_each_resource(bus, pref) if (pref && (pref->flags & IORESOURCE_PREFETCH)) break; hdr_type = -1; /* Intentionally invalid - not a PCI device. */ @@ -1337,12 +1332,11 @@ EXPORT_SYMBOL(pci_bus_size_bridges); static void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r) { - int i; struct resource *parent_r; unsigned long mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; - pci_bus_for_each_resource(b, parent_r, i) { + pci_bus_for_each_resource(b, parent_r) { if (!parent_r) continue; @@ -1358,11 +1352,10 @@ static void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r) */ static void pdev_assign_fixed_resources(struct pci_dev *dev) { - int i; + struct resource *r; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { + pci_dev_for_each_resource(dev, r) { struct pci_bus *b; - struct resource *r = &dev->resource[i]; if (r->parent || !(r->flags & IORESOURCE_PCI_FIXED) || !(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) @@ -1795,11 +1788,9 @@ static void remove_dev_resources(struct pci_dev *dev, struct resource *io, struct resource *mmio, struct resource *mmio_pref) { - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; + struct resource *res; + pci_dev_for_each_resource(dev, res) { if (resource_type(res) == IORESOURCE_IO) { remove_dev_resource(io, dev, res); } else if (resource_type(res) == IORESOURCE_MEM) { diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index b492e67c3d87..967f9a758923 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -484,12 +484,10 @@ int pci_enable_resources(struct pci_dev *dev, int mask) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { + pci_dev_for_each_resource(dev, r, i) { if (!(mask & (1 << i))) continue; - r = &dev->resource[i]; - if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) continue; if ((i == PCI_ROM_RESOURCE) && diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index f80b6ec88dc3..5a696078b382 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -548,10 +548,8 @@ static bool vga_is_firmware_default(struct pci_dev *pdev) #if defined(CONFIG_X86) || defined(CONFIG_IA64) u64 base = screen_info.lfb_base; u64 size = screen_info.lfb_size; + struct resource *r; u64 limit; - resource_size_t start, end; - unsigned long flags; - int i; /* Select the device owning the boot framebuffer if there is one */ @@ -561,19 +559,14 @@ static bool vga_is_firmware_default(struct pci_dev *pdev) limit = base + size; /* Does firmware framebuffer belong to us? */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - flags = pci_resource_flags(pdev, i); - - if ((flags & IORESOURCE_MEM) == 0) + pci_dev_for_each_resource(pdev, r) { + if (resource_type(r) != IORESOURCE_MEM) continue; - start = pci_resource_start(pdev, i); - end = pci_resource_end(pdev, i); - - if (!start || !end) + if (!r->start || !r->end) continue; - if (base < start || limit >= end) + if (base < r->start || limit >= r->end) continue; return true; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index fcd029ca2eb1..83c0ab50676d 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -390,9 +390,7 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data) int i; struct resource *r; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - r = &dev->resource[i]; - + pci_dev_for_each_resource(dev, r, i) { if (!r->parent && r->start && r->flags) { dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n", pci_name(dev), i); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index ac98b9919029..6085a1471de2 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -229,8 +229,7 @@ static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) static void quirk_system_pci_resources(struct pnp_dev *dev) { struct pci_dev *pdev = NULL; - struct resource *res; - resource_size_t pnp_start, pnp_end, pci_start, pci_end; + struct resource *res, *r; int i, j; /* @@ -243,32 +242,26 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) * so they won't be claimed by the PNP system driver. */ for_each_pci_dev(pdev) { - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - unsigned long flags, type; + pci_dev_for_each_resource(pdev, r, i) { + unsigned long type = resource_type(r); - flags = pci_resource_flags(pdev, i); - type = flags & (IORESOURCE_IO | IORESOURCE_MEM); - if (!type || pci_resource_len(pdev, i) == 0) + if (!(type == IORESOURCE_IO || type == IORESOURCE_MEM) || + resource_size(r) == 0) continue; - if (flags & IORESOURCE_UNSET) + if (r->flags & IORESOURCE_UNSET) continue; - pci_start = pci_resource_start(pdev, i); - pci_end = pci_resource_end(pdev, i); for (j = 0; (res = pnp_get_resource(dev, type, j)); j++) { if (res->start == 0 && res->end == 0) continue; - pnp_start = res->start; - pnp_end = res->end; - /* * If the PNP region doesn't overlap the PCI * region at all, there's no problem. */ - if (pnp_end < pci_start || pnp_start > pci_end) + if (!resource_overlaps(res, r)) continue; /* @@ -278,8 +271,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) * PNP device describes a bridge with PCI * behind it. */ - if (pnp_start <= pci_start && - pnp_end >= pci_end) + if (res->start <= r->start && res->end >= r->end) continue; /* @@ -288,9 +280,8 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) * driver from requesting its resources. */ dev_warn(&dev->dev, - "disabling %pR because it overlaps " - "%s BAR %d %pR\n", res, - pci_name(pdev), i, &pdev->resource[i]); + "disabling %pR because it overlaps %s BAR %d %pR\n", + res, pci_name(pdev), i, r); res->flags |= IORESOURCE_DISABLED; } } diff --git a/include/linux/pci.h b/include/linux/pci.h index fafd8020c6d7..c048e70d42b9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1444,10 +1444,44 @@ int devm_request_pci_bus_resources(struct device *dev, /* Temporary until new and working PCI SBR API in place */ int pci_bridge_secondary_bus_reset(struct pci_dev *dev); -#define pci_bus_for_each_resource(bus, res, i) \ - for (i = 0; \ - (res = pci_bus_resource_n(bus, i)) || i < PCI_BRIDGE_RESOURCE_NUM; \ - i++) +#define __pci_bus_for_each_res0(bus, res, ...) \ + for (unsigned int __b = 0; \ + (res = pci_bus_resource_n(bus, __b)) || __b < PCI_BRIDGE_RESOURCE_NUM; \ + __b++) + +#define __pci_bus_for_each_res1(bus, res, __b) \ + for (__b = 0; \ + (res = pci_bus_resource_n(bus, __b)) || __b < PCI_BRIDGE_RESOURCE_NUM; \ + __b++) + +/** + * pci_bus_for_each_resource - iterate over PCI bus resources + * @bus: the PCI bus + * @res: pointer to the current resource + * @...: optional index of the current resource + * + * Iterate over PCI bus resources. The first part is to go over PCI bus + * resource array, which has at most the %PCI_BRIDGE_RESOURCE_NUM entries. + * After that continue with the separate list of the additional resources, + * if not empty. That's why the Logical OR is being used. + * + * Possible usage: + * + * struct pci_bus *bus = ...; + * struct resource *res; + * unsigned int i; + * + * // With optional index + * pci_bus_for_each_resource(bus, res, i) + * pr_info("PCI bus resource[%u]: %pR\n", i, res); + * + * // Without index + * pci_bus_for_each_resource(bus, res) + * _do_something_(res); + */ +#define pci_bus_for_each_resource(bus, res, ...) \ + CONCATENATE(__pci_bus_for_each_res, COUNT_ARGS(__VA_ARGS__)) \ + (bus, res, __VA_ARGS__) int __must_check pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t size, @@ -1994,14 +2028,27 @@ int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma); * These helpers provide future and backwards compatibility * for accessing popular PCI BAR info */ -#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) -#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end) -#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags) -#define pci_resource_len(dev,bar) \ - ((pci_resource_end((dev), (bar)) == 0) ? 0 : \ - \ - (pci_resource_end((dev), (bar)) - \ - pci_resource_start((dev), (bar)) + 1)) +#define pci_resource_n(dev, bar) (&(dev)->resource[(bar)]) +#define pci_resource_start(dev, bar) (pci_resource_n(dev, bar)->start) +#define pci_resource_end(dev, bar) (pci_resource_n(dev, bar)->end) +#define pci_resource_flags(dev, bar) (pci_resource_n(dev, bar)->flags) +#define pci_resource_len(dev,bar) \ + (pci_resource_end((dev), (bar)) ? \ + resource_size(pci_resource_n((dev), (bar))) : 0) + +#define __pci_dev_for_each_res0(dev, res, ...) \ + for (unsigned int __b = 0; \ + res = pci_resource_n(dev, __b), __b < PCI_NUM_RESOURCES; \ + __b++) + +#define __pci_dev_for_each_res1(dev, res, __b) \ + for (__b = 0; \ + res = pci_resource_n(dev, __b), __b < PCI_NUM_RESOURCES; \ + __b++) + +#define pci_dev_for_each_resource(dev, res, ...) \ + CONCATENATE(__pci_dev_for_each_res, COUNT_ARGS(__VA_ARGS__)) \ + (dev, res, __VA_ARGS__) /* * Similar to the helpers above, these manipulate per-pci_dev |