aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Documentation/PCI/pci-error-recovery.rst8
-rw-r--r--Documentation/PCI/pci.rst9
-rw-r--r--Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml8
-rw-r--r--Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt12
-rw-r--r--Documentation/devicetree/bindings/pci/pci.txt4
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.txt15
-rw-r--r--Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml94
-rw-r--r--Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml113
-rw-r--r--Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml99
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/powerpc/kernel/eeh_driver.c2
-rw-r--r--arch/x86/pci/fixup.c4
-rw-r--r--arch/x86/pci/xen.c2
-rw-r--r--drivers/block/rsxx/core.c2
-rw-r--r--drivers/dma/ioat/init.c6
-rw-r--r--drivers/gpu/drm/qxl/qxl_dev.h2
-rw-r--r--drivers/iommu/intel/iommu.c8
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c2
-rw-r--r--drivers/misc/genwqe/card_base.c2
-rw-r--r--drivers/misc/pci_endpoint_test.c9
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c2
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c4
-rw-r--r--drivers/net/ethernet/rocker/rocker_hw.h1
-rw-r--r--drivers/net/ethernet/sfc/efx.c2
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.c2
-rw-r--r--drivers/pci/access.c16
-rw-r--r--drivers/pci/ats.c15
-rw-r--r--drivers/pci/bus.c6
-rw-r--r--drivers/pci/controller/Kconfig8
-rw-r--r--drivers/pci/controller/Makefile1
-rw-r--r--drivers/pci/controller/cadence/Kconfig23
-rw-r--r--drivers/pci/controller/cadence/Makefile1
-rw-r--r--drivers/pci/controller/cadence/pci-j721e.c485
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence-ep.c128
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence-host.c301
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence-plat.c16
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence.c8
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence.h161
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c16
-rw-r--r--drivers/pci/controller/dwc/pci-exynos.c2
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c2
-rw-r--r--drivers/pci/controller/dwc/pci-keystone.c5
-rw-r--r--drivers/pci/controller/dwc/pcie-artpec6.c12
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-plat.c3
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h2
-rw-r--r--drivers/pci/controller/dwc/pcie-hisi.c219
-rw-r--r--drivers/pci/controller/dwc/pcie-histb.c7
-rw-r--r--drivers/pci/controller/dwc/pcie-intel-gw.c7
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c19
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c198
-rw-r--r--drivers/pci/controller/dwc/pcie-uniphier.c3
-rw-r--r--drivers/pci/controller/pci-aardvark.c11
-rw-r--r--drivers/pci/controller/pci-hyperv.c86
-rw-r--r--drivers/pci/controller/pci-loongson.c6
-rw-r--r--drivers/pci/controller/pci-mvebu.c16
-rw-r--r--drivers/pci/controller/pci-tegra.c42
-rw-r--r--drivers/pci/controller/pcie-rcar-host.c4
-rw-r--r--drivers/pci/controller/pcie-xilinx-cpm.c611
-rw-r--r--drivers/pci/controller/vmd.c44
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c6
-rw-r--r--drivers/pci/irq.c50
-rw-r--r--drivers/pci/msi.c22
-rw-r--r--drivers/pci/of.c2
-rw-r--r--drivers/pci/p2pdma.c23
-rw-r--r--drivers/pci/pci-acpi.c9
-rw-r--r--drivers/pci/pci-label.c2
-rw-r--r--drivers/pci/pci.c286
-rw-r--r--drivers/pci/pci.h7
-rw-r--r--drivers/pci/pcie/Kconfig2
-rw-r--r--drivers/pci/pcie/aer.c87
-rw-r--r--drivers/pci/pcie/aer_inject.c2
-rw-r--r--drivers/pci/pcie/aspm.c1
-rw-r--r--drivers/pci/pcie/err.c7
-rw-r--r--drivers/pci/pcie/portdrv_pci.c2
-rw-r--r--drivers/pci/probe.c10
-rw-r--r--drivers/pci/quirks.c33
-rw-r--r--drivers/pci/setup-bus.c2
-rw-r--r--drivers/pci/setup-res.c3
-rw-r--r--drivers/pci/slot.c6
-rw-r--r--drivers/pci/switch/switchtec.c16
-rw-r--r--drivers/scsi/aacraid/linit.c2
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c6
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/staging/qlge/qlge_main.c2
-rw-r--r--include/linux/kernel.h1
-rw-r--r--include/linux/pci-ats.h4
-rw-r--r--include/linux/pci.h18
-rw-r--r--include/linux/pci_ids.h2
-rw-r--r--samples/vfio-mdev/mdpy-defs.h2
92 files changed, 2646 insertions, 877 deletions
diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst
index 13beee23cb04..ccd713423133 100644
--- a/Documentation/PCI/pci-error-recovery.rst
+++ b/Documentation/PCI/pci-error-recovery.rst
@@ -79,7 +79,7 @@ This structure has the form::
struct pci_error_handlers
{
- int (*error_detected)(struct pci_dev *dev, enum pci_channel_state);
+ int (*error_detected)(struct pci_dev *dev, pci_channel_state_t);
int (*mmio_enabled)(struct pci_dev *dev);
int (*slot_reset)(struct pci_dev *dev);
void (*resume)(struct pci_dev *dev);
@@ -87,11 +87,11 @@ This structure has the form::
The possible channel states are::
- enum pci_channel_state {
+ typedef enum {
pci_channel_io_normal, /* I/O channel is in normal state */
pci_channel_io_frozen, /* I/O to channel is blocked */
pci_channel_io_perm_failure, /* PCI card is dead */
- };
+ } pci_channel_state_t;
Possible return values are::
@@ -348,7 +348,7 @@ STEP 6: Permanent Failure
-------------------------
A "permanent failure" has occurred, and the platform cannot recover
the device. The platform will call error_detected() with a
-pci_channel_state value of pci_channel_io_perm_failure.
+pci_channel_state_t value of pci_channel_io_perm_failure.
The device driver should, at this point, assume the worst. It should
cancel all pending I/O, refuse all new I/O, returning -EIO to
diff --git a/Documentation/PCI/pci.rst b/Documentation/PCI/pci.rst
index 8c016d8c9862..281d8a241eae 100644
--- a/Documentation/PCI/pci.rst
+++ b/Documentation/PCI/pci.rst
@@ -17,7 +17,7 @@ PCI device drivers.
A more complete resource is the third edition of "Linux Device Drivers"
by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman.
LDD3 is available for free (under Creative Commons License) from:
-http://lwn.net/Kernel/LDD3/.
+https://lwn.net/Kernel/LDD3/.
However, keep in mind that all documents are subject to "bit rot".
Refer to the source code if things are not working as described here.
@@ -214,7 +214,7 @@ the PCI device by calling pci_enable_device(). This will:
problem and unlikely to get fixed soon.
This has been discussed before but not changed as of 2.6.19:
- http://lkml.org/lkml/2006/3/2/194
+ https://lore.kernel.org/r/20060302180025.GC28895@flint.arm.linux.org.uk/
pci_set_master() will enable DMA by setting the bus master bit
@@ -514,9 +514,8 @@ your driver if they're helpful, or just use plain hex constants.
The device IDs are arbitrary hex numbers (vendor controlled) and normally used
only in a single location, the pci_device_id table.
-Please DO submit new vendor/device IDs to http://pci-ids.ucw.cz/.
-There are mirrors of the pci.ids file at http://pciids.sourceforge.net/
-and https://github.com/pciutils/pciids.
+Please DO submit new vendor/device IDs to https://pci-ids.ucw.cz/.
+There's a mirror of the pci.ids file at https://github.com/pciutils/pciids.
Obsolete functions
diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
index 84a8f095d031..6d67067843bf 100644
--- a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
@@ -18,13 +18,12 @@ properties:
const: cdns,cdns-pcie-host
reg:
- maxItems: 3
+ maxItems: 2
reg-names:
items:
- const: reg
- const: cfg
- - const: mem
msi-parent: true
@@ -49,9 +48,8 @@ examples:
device-id = <0x0200>;
reg = <0x0 0xfb000000 0x0 0x01000000>,
- <0x0 0x41000000 0x0 0x00001000>,
- <0x0 0x40000000 0x0 0x04000000>;
- reg-names = "reg", "cfg", "mem";
+ <0x0 0x41000000 0x0 0x00001000>;
+ reg-names = "reg", "cfg";
ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
<0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
index 7939bca47861..d099f3476ccc 100644
--- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
@@ -112,28 +112,16 @@ Power supplies for Tegra124:
- Required:
- avddio-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
- dvddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
- - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must
- supply 1.05 V.
- hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks.
Must supply 3.3 V.
- - hvdd-pex-pll-e-supply: High-voltage supply for PLLE (shared with USB3).
- Must supply 3.3 V.
- vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
supply 2.8-3.3 V.
- - avdd-pll-erefe-supply: Power supply for PLLE (shared with USB3). Must
- supply 1.05 V.
Power supplies for Tegra210:
- Required:
- - avdd-pll-uerefe-supply: Power supply for PLLE (shared with USB3). Must
- supply 1.05 V.
- hvddio-pex-supply: High-voltage supply for PCIe I/O and PCIe output
clocks. Must supply 1.8 V.
- dvddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
- - dvdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must
- supply 1.05 V.
- - hvdd-pex-pll-e-supply: High-voltage supply for PLLE (shared with USB3).
- Must supply 3.3 V.
- vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
supply 1.8 V.
diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
index 29bcbd88f457..6a8f2874a24d 100644
--- a/Documentation/devicetree/bindings/pci/pci.txt
+++ b/Documentation/devicetree/bindings/pci/pci.txt
@@ -1,12 +1,12 @@
PCI bus bridges have standardized Device Tree bindings:
PCI Bus Binding to: IEEE Std 1275-1994
-http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf
+https://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf
And for the interrupt mapping part:
Open Firmware Recommended Practice: Interrupt Mapping
-http://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf
+https://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf
Additionally to the properties specified in the above standards a host bridge
driver implementation may support the following properties:
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index 981b4de12807..02bc81bb8b2d 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -5,6 +5,7 @@
Value type: <stringlist>
Definition: Value should contain
- "qcom,pcie-ipq8064" for ipq8064
+ - "qcom,pcie-ipq8064-v2" for ipq8064 rev 2 or ipq8065
- "qcom,pcie-apq8064" for apq8064
- "qcom,pcie-apq8084" for apq8084
- "qcom,pcie-msm8996" for msm8996 or apq8096
@@ -90,6 +91,8 @@
Definition: Should contain the following entries
- "core" Clocks the pcie hw block
- "phy" Clocks the pcie PHY block
+ - "aux" Clocks the pcie AUX block
+ - "ref" Clocks the pcie ref block
- clock-names:
Usage: required for apq8084/ipq4019
Value type: <stringlist>
@@ -177,6 +180,7 @@
- "pwr" PWR reset
- "ahb" AHB reset
- "phy_ahb" PHY AHB reset
+ - "ext" EXT reset
- reset-names:
Usage: required for ipq8074
@@ -277,14 +281,17 @@
<0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
clocks = <&gcc PCIE_A_CLK>,
<&gcc PCIE_H_CLK>,
- <&gcc PCIE_PHY_CLK>;
- clock-names = "core", "iface", "phy";
+ <&gcc PCIE_PHY_CLK>,
+ <&gcc PCIE_AUX_CLK>,
+ <&gcc PCIE_ALT_REF_CLK>;
+ clock-names = "core", "iface", "phy", "aux", "ref";
resets = <&gcc PCIE_ACLK_RESET>,
<&gcc PCIE_HCLK_RESET>,
<&gcc PCIE_POR_RESET>,
<&gcc PCIE_PCI_RESET>,
- <&gcc PCIE_PHY_RESET>;
- reset-names = "axi", "ahb", "por", "pci", "phy";
+ <&gcc PCIE_PHY_RESET>,
+ <&gcc PCIE_EXT_RESET>;
+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
pinctrl-0 = <&pcie_pins_default>;
pinctrl-names = "default";
};
diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
new file mode 100644
index 000000000000..cfe25cface21
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI EP (PCIe Wrapper)
+
+maintainers:
+ - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+ - $ref: "cdns-pcie-ep.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - ti,j721e-pcie-ep
+
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: intd_cfg
+ - const: user_cfg
+ - const: reg
+ - const: mem
+
+ ti,syscon-pcie-ctrl:
+ description: Phandle to the SYSCON entry required for configuring PCIe mode
+ and link speed.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: clock-specifier to represent input to the PCIe
+
+ clock-names:
+ items:
+ - const: fck
+
+ dma-coherent:
+ description: Indicates that the PCIe IP block can ensure the coherency
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - ti,syscon-pcie-ctrl
+ - max-link-speed
+ - num-lanes
+ - power-domains
+ - clocks
+ - clock-names
+ - cdns,max-outbound-regions
+ - dma-coherent
+ - max-functions
+ - phys
+ - phy-names
+
+examples:
+ - |
+ #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie0_ep: pcie-ep@d000000 {
+ compatible = "ti,j721e-pcie-ep";
+ reg = <0x00 0x02900000 0x00 0x1000>,
+ <0x00 0x02907000 0x00 0x400>,
+ <0x00 0x0d000000 0x00 0x00800000>,
+ <0x00 0x10000000 0x00 0x08000000>;
+ reg-names = "intd_cfg", "user_cfg", "reg", "mem";
+ ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+ max-link-speed = <3>;
+ num-lanes = <2>;
+ power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 239 1>;
+ clock-names = "fck";
+ cdns,max-outbound-regions = <16>;
+ max-functions = /bits/ 8 <6>;
+ dma-coherent;
+ phys = <&serdes0_pcie_link>;
+ phy-names = "pcie-phy";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
new file mode 100644
index 000000000000..d7b60487c6c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-host.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI Host (PCIe Wrapper)
+
+maintainers:
+ - Kishon Vijay Abraham I <kishon@ti.com>
+
+allOf:
+ - $ref: "cdns-pcie-host.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - ti,j721e-pcie-host
+
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: intd_cfg
+ - const: user_cfg
+ - const: reg
+ - const: cfg
+
+ ti,syscon-pcie-ctrl:
+ description: Phandle to the SYSCON entry required for configuring PCIe mode
+ and link speed.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: clock-specifier to represent input to the PCIe
+
+ clock-names:
+ items:
+ - const: fck
+
+ vendor-id:
+ const: 0x104c
+
+ device-id:
+ const: 0xb00d
+
+ msi-map: true
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - ti,syscon-pcie-ctrl
+ - max-link-speed
+ - num-lanes
+ - power-domains
+ - clocks
+ - clock-names
+ - vendor-id
+ - device-id
+ - msi-map
+ - dma-coherent
+ - dma-ranges
+ - ranges
+ - reset-gpios
+ - phys
+ - phy-names
+
+examples:
+ - |
+ #include <dt-bindings/soc/ti,sci_pm_domain.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie0_rc: pcie@2900000 {
+ compatible = "ti,j721e-pcie-host";
+ reg = <0x00 0x02900000 0x00 0x1000>,
+ <0x00 0x02907000 0x00 0x400>,
+ <0x00 0x0d000000 0x00 0x00800000>,
+ <0x00 0x10000000 0x00 0x00001000>;
+ reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
+ ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+ max-link-speed = <3>;
+ num-lanes = <2>;
+ power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 239 1>;
+ clock-names = "fck";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xf>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x0 0x10000>;
+ dma-coherent;
+ reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>;
+ phys = <&serdes0_pcie_link>;
+ phy-names = "pcie-phy";
+ ranges = <0x01000000 0x0 0x10001000 0x00 0x10001000 0x0 0x0010000>,
+ <0x02000000 0x0 0x10011000 0x00 0x10011000 0x0 0x7fef000>;
+ dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml b/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
new file mode 100644
index 000000000000..a2bbc0eb7220
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/xilinx-versal-cpm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CPM Host Controller device tree for Xilinx Versal SoCs
+
+maintainers:
+ - Bharat Kumar Gogada <bharat.kumar.gogada@xilinx.com>
+
+allOf:
+ - $ref: /schemas/pci/pci-bus.yaml#
+
+properties:
+ compatible:
+ const: xlnx,versal-cpm-host-1.00
+
+ reg:
+ items:
+ - description: Configuration space region and bridge registers.
+ - description: CPM system level control and status registers.
+
+ reg-names:
+ items:
+ - const: cfg
+ - const: cpm_slcr
+
+ interrupts:
+ maxItems: 1
+
+ msi-map:
+ description:
+ Maps a Requester ID to an MSI controller and associated MSI sideband data.
+
+ ranges:
+ maxItems: 2
+
+ "#interrupt-cells":
+ const: 1
+
+ interrupt-controller:
+ description: Interrupt controller node for handling legacy PCI interrupts.
+ type: object
+ properties:
+ "#address-cells":
+ const: 0
+ "#interrupt-cells":
+ const: 1
+ "interrupt-controller": true
+ additionalProperties: false
+
+required:
+ - reg
+ - reg-names
+ - "#interrupt-cells"
+ - interrupts
+ - interrupt-parent
+ - interrupt-map
+ - interrupt-map-mask
+ - bus-range
+ - msi-map
+ - interrupt-controller
+
+unevaluatedProperties: false
+
+examples:
+ - |
+
+ versal {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ cpm_pcie: pcie@fca10000 {
+ compatible = "xlnx,versal-cpm-host-1.00";
+ device_type = "pci";
+ #address-cells = <3>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ interrupts = <0 72 4>;
+ interrupt-parent = <&gic>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc_0 0>,
+ <0 0 0 2 &pcie_intc_0 1>,
+ <0 0 0 3 &pcie_intc_0 2>,
+ <0 0 0 4 &pcie_intc_0 3>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x02000000 0x0 0xe0000000 0x0 0xe0000000 0x0 0x10000000>,
+ <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>;
+ msi-map = <0x0 &its_gic 0x0 0x10000>;
+ reg = <0x6 0x00000000 0x0 0x10000000>,
+ <0x0 0xfca10000 0x0 0x1000>;
+ reg-names = "cfg", "cpm_slcr";
+ pcie_intc_0: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 68f21d46614c..6df9b54d3003 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13149,12 +13149,14 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/designware-pcie.txt
F: drivers/pci/controller/dwc/*designware*
-PCI DRIVER FOR TI DRA7XX
+PCI DRIVER FOR TI DRA7XX/J721E
M: Kishon Vijay Abraham I <kishon@ti.com>
L: linux-omap@vger.kernel.org
L: linux-pci@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org
S: Supported
F: Documentation/devicetree/bindings/pci/ti-pci.txt
+F: drivers/pci/controller/cadence/pci-j721e.c
F: drivers/pci/controller/dwc/pci-dra7xx.c
PCI DRIVER FOR TI KEYSTONE
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 7b048cee767c..ab8806d2e03e 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -214,7 +214,7 @@ static void eeh_dev_save_state(struct eeh_dev *edev, void *userdata)
pci_save_state(pdev);
}
-static void eeh_set_channel_state(struct eeh_pe *root, enum pci_channel_state s)
+static void eeh_set_channel_state(struct eeh_pe *root, pci_channel_state_t s)
{
struct eeh_pe *pe;
struct eeh_dev *edev, *tmp;
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 0c67a5a94de3..b8c9a5b87f37 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -557,12 +557,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_z
* Device [8086:2fc0]
* Erratum HSE43
* CONFIG_TDP_NOMINAL CSR Implemented at Incorrect Offset
- * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v3-spec-update.html
+ * https://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v3-spec-update.html
*
* Devices [8086:6f60,6fa0,6fc0]
* Erratum BDF2
* PCI BARs in the Home Agent Will Return Non-Zero Values During Enumeration
- * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
+ * https://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
*/
static void pci_invalid_bar(struct pci_dev *dev)
{
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index e3f1ca316068..9f9aad42ccff 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -62,7 +62,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
#ifdef CONFIG_ACPI
static int xen_register_pirq(u32 gsi, int triggering, bool set_pirq)
{
- int rc, pirq = -1, irq = -1;
+ int rc, pirq = -1, irq;
struct physdev_map_pirq map_irq;
int shareable = 0;
char *name;
diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
index 10f6368117d8..34e937dd6bca 100644
--- a/drivers/block/rsxx/core.c
+++ b/drivers/block/rsxx/core.c
@@ -625,7 +625,7 @@ static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card)
}
static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev,
- enum pci_channel_state error)
+ pci_channel_state_t error)
{
int st;
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 58d13564f88b..20a4f36a2f6e 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -1195,13 +1195,13 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
/* disable relaxed ordering */
err = pcie_capability_read_word(pdev, IOAT_DEVCTRL_OFFSET, &val16);
if (err)
- return err;
+ return pcibios_err_to_errno(err);
/* clear relaxed ordering enable */
val16 &= ~IOAT_DEVCTRL_ROE;
err = pcie_capability_write_word(pdev, IOAT_DEVCTRL_OFFSET, val16);
if (err)
- return err;
+ return pcibios_err_to_errno(err);
if (ioat_dma->cap & IOAT_CAP_DPS)
writeb(ioat_pending_level + 1,
@@ -1267,7 +1267,7 @@ static void ioat_resume(struct ioatdma_device *ioat_dma)
#define DRV_NAME "ioatdma"
static pci_ers_result_t ioat_pcie_error_detected(struct pci_dev *pdev,
- enum pci_channel_state error)
+ pci_channel_state_t error)
{
dev_dbg(&pdev->dev, "%s: PCIe AER error %d\n", DRV_NAME, error);
diff --git a/drivers/gpu/drm/qxl/qxl_dev.h b/drivers/gpu/drm/qxl/qxl_dev.h
index a0ee41632d7e..a7bc31f6d565 100644
--- a/drivers/gpu/drm/qxl/qxl_dev.h
+++ b/drivers/gpu/drm/qxl/qxl_dev.h
@@ -131,8 +131,6 @@ enum SpiceCursorType {
#pragma pack(push, 1)
-#define REDHAT_PCI_VENDOR_ID 0x1b36
-
/* 0x100-0x11f reserved for spice, 0x1ff used for unstable work */
#define QXL_DEVICE_ID_STABLE 0x0100
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 9129663a7406..13110482553d 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2554,7 +2554,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
}
if (info->ats_supported && ecap_prs(iommu->ecap) &&
- pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI))
+ pci_pri_supported(pdev))
info->pri_supported = 1;
}
}
@@ -4730,12 +4730,12 @@ const struct attribute_group *intel_iommu_groups[] = {
NULL,
};
-static inline bool has_untrusted_dev(void)
+static inline bool has_external_pci(void)
{
struct pci_dev *pdev = NULL;
for_each_pci_dev(pdev)
- if (pdev->untrusted)
+ if (pdev->external_facing)
return true;
return false;
@@ -4743,7 +4743,7 @@ static inline bool has_untrusted_dev(void)
static int __init platform_optin_force_iommu(void)
{
- if (!dmar_platform_optin() || no_platform_optin || !has_untrusted_dev())
+ if (!dmar_platform_optin() || no_platform_optin || !has_external_pci())
return 0;
if (no_iommu || dmar_disabled)
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index 6185806a00e0..8bfb3d8ea610 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -1186,7 +1186,7 @@ MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
/****************************************************************************/
static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
dev_err(&dev->dev, "PCI error\n");
if (state == pci_channel_io_perm_failure)
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index 1dc6c7c5cbce..97b8ecc42383 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -1240,7 +1240,7 @@ static void genwqe_remove(struct pci_dev *pci_dev)
* error is detected.
*/
static pci_ers_result_t genwqe_err_error_detected(struct pci_dev *pci_dev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
struct genwqe_dev *cd;
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 41c40971979e..e060796f9caa 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -68,6 +68,7 @@
#define PCI_ENDPOINT_TEST_FLAGS 0x2c
#define FLAG_USE_DMA BIT(0)
+#define PCI_DEVICE_ID_TI_J721E 0xb00d
#define PCI_DEVICE_ID_TI_AM654 0xb00c
#define is_am654_pci_dev(pdev) \
@@ -932,6 +933,11 @@ static const struct pci_endpoint_test_data am654_data = {
.irq_type = IRQ_TYPE_MSI,
};
+static const struct pci_endpoint_test_data j721e_data = {
+ .alignment = 256,
+ .irq_type = IRQ_TYPE_MSI,
+};
+
static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
.driver_data = (kernel_ulong_t)&default_data,
@@ -946,6 +952,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
},
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
},
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
+ .driver_data = (kernel_ulong_t)&j721e_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 5d807c8004f8..f0de2d1842b4 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -15465,7 +15465,7 @@ unmap:
* remediation.
**/
static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev,
- enum pci_channel_state error)
+ pci_channel_state_t error)
{
struct i40e_pf *pf = pci_get_drvdata(pdev);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 082825e3cb39..4dd9226a12df 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3586,7 +3586,7 @@ static void ice_remove(struct pci_dev *pdev)
* is in progress. Allows the driver to gracefully prepare/handle PCI errors.
*/
static pci_ers_result_t
-ice_pci_err_detected(struct pci_dev *pdev, enum pci_channel_state err)
+ice_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t err)
{
struct ice_pf *pf = pci_get_drvdata(pdev);
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index b64e91ea3465..00db4b5863b1 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -82,7 +82,7 @@ static int ixgb_vlan_rx_kill_vid(struct net_device *netdev,
static void ixgb_restore_vlan(struct ixgb_adapter *adapter);
static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
- enum pci_channel_state state);
+ pci_channel_state_t state);
static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
static void ixgb_io_resume (struct pci_dev *pdev);
@@ -2194,7 +2194,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)
* a PCI bus error is detected.
*/
static pci_ers_result_t ixgb_io_error_detected(struct pci_dev *pdev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgb_adapter *adapter = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/rocker/rocker_hw.h b/drivers/net/ethernet/rocker/rocker_hw.h
index 59f1f8b690d2..62fd84cf3435 100644
--- a/drivers/net/ethernet/rocker/rocker_hw.h
+++ b/drivers/net/ethernet/rocker/rocker_hw.h
@@ -25,7 +25,6 @@ enum {
#define ROCKER_FP_PORTS_MAX 62
-#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_ROCKER 0x0006
#define ROCKER_PCI_BAR0_SIZE 0x2000
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 256807c28ff7..ed627aff7b36 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1519,7 +1519,7 @@ static const struct dev_pm_ops efx_pm_ops = {
* Stop the software path and request a slot reset.
*/
static pci_ers_result_t efx_io_error_detected(struct pci_dev *pdev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
struct efx_nic *efx = pci_get_drvdata(pdev);
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index 42bcd34fc508..f8979991970e 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -3118,7 +3118,7 @@ static const struct dev_pm_ops ef4_pm_ops = {
* Stop the software path and request a slot reset.
*/
static pci_ers_result_t ef4_io_error_detected(struct pci_dev *pdev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
struct ef4_nic *efx = pci_get_drvdata(pdev);
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 79c4a2ef269a..46935695cfb9 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -204,17 +204,13 @@ EXPORT_SYMBOL(pci_bus_set_ops);
static DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait);
static noinline void pci_wait_cfg(struct pci_dev *dev)
+ __must_hold(&pci_lock)
{
- DECLARE_WAITQUEUE(wait, current);
-
- __add_wait_queue(&pci_cfg_wait, &wait);
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
raw_spin_unlock_irq(&pci_lock);
- schedule();
+ wait_event(pci_cfg_wait, !dev->block_cfg_access);
raw_spin_lock_irq(&pci_lock);
} while (dev->block_cfg_access);
- __remove_wait_queue(&pci_cfg_wait, &wait);
}
/* Returns 0 on success, negative values indicate error. */
@@ -409,7 +405,7 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
*val = 0;
if (pos & 1)
- return -EINVAL;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
@@ -444,7 +440,7 @@ int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
*val = 0;
if (pos & 3)
- return -EINVAL;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
@@ -469,7 +465,7 @@ EXPORT_SYMBOL(pcie_capability_read_dword);
int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
{
if (pos & 1)
- return -EINVAL;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
if (!pcie_capability_reg_implemented(dev, pos))
return 0;
@@ -481,7 +477,7 @@ EXPORT_SYMBOL(pcie_capability_write_word);
int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
{
if (pos & 3)
- return -EINVAL;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
if (!pcie_capability_reg_implemented(dev, pos))
return 0;
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index b761c1f72f67..647e097530a8 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -325,6 +325,21 @@ int pci_prg_resp_pasid_required(struct pci_dev *pdev)
return pdev->pasid_required;
}
+
+/**
+ * pci_pri_supported - Check if PRI is supported.
+ * @pdev: PCI device structure
+ *
+ * Returns true if PRI capability is present, false otherwise.
+ */
+bool pci_pri_supported(struct pci_dev *pdev)
+{
+ /* VFs share the PF PRI */
+ if (pci_physfn(pdev)->pri_cap)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(pci_pri_supported);
#endif /* CONFIG_PCI_PRI */
#ifdef CONFIG_PCI_PASID
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 8e40b3e6da77..3cef835b375f 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -322,12 +322,8 @@ void pci_bus_add_device(struct pci_dev *dev)
dev->match_driver = true;
retval = device_attach(&dev->dev);
- if (retval < 0 && retval != -EPROBE_DEFER) {
+ if (retval < 0 && retval != -EPROBE_DEFER)
pci_warn(dev, "device attach failed (%d)\n", retval);
- pci_proc_detach_device(dev);
- pci_remove_sysfs_dev_files(dev);
- return;
- }
pci_dev_assign_added(dev, true);
}
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index adddf21fa381..f18c3725ef80 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -99,6 +99,14 @@ config PCIE_XILINX
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
Host Bridge driver.
+config PCIE_XILINX_CPM
+ bool "Xilinx Versal CPM host bridge support"
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ select PCI_HOST_COMMON
+ help
+ Say 'Y' here if you want kernel support for the
+ Xilinx Versal CPM host bridge.
+
config PCI_XGENE
bool "X-Gene PCIe controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index efd9733ead26..bcdbf49ab1e4 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
+obj-$(CONFIG_PCIE_XILINX_CPM) += pcie-xilinx-cpm.o
obj-$(CONFIG_PCI_V3_SEMI) += pci-v3-semi.o
obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index b76b3cf55ce5..5d30564190e1 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
endpoint mode. This PCIe controller may be embedded into many
different vendors SoCs.
+config PCI_J721E
+ bool
+
+config PCI_J721E_HOST
+ bool "TI J721E PCIe platform host controller"
+ depends on OF
+ select PCIE_CADENCE_HOST
+ select PCI_J721E
+ help
+ Say Y here if you want to support the TI J721E PCIe platform
+ controller in host mode. TI J721E PCIe controller uses Cadence PCIe
+ core.
+
+config PCI_J721E_EP
+ bool "TI J721E PCIe platform endpoint controller"
+ depends on OF
+ depends on PCI_ENDPOINT
+ select PCIE_CADENCE_EP
+ select PCI_J721E
+ help
+ Say Y here if you want to support the TI J721E PCIe platform
+ controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
+ core.
endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 232a3f20876a..9bac5fb2f13d 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
+obj-$(CONFIG_PCI_J721E) += pci-j721e.o
diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
new file mode 100644
index 000000000000..586b9d69fa5e
--- /dev/null
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -0,0 +1,485 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * pci-j721e - PCIe controller driver for TI's J721E SoCs
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "../../pci.h"
+#include "pcie-cadence.h"
+
+#define ENABLE_REG_SYS_2 0x108
+#define STATUS_REG_SYS_2 0x508
+#define STATUS_CLR_REG_SYS_2 0x708
+#define LINK_DOWN BIT(1)
+
+#define J721E_PCIE_USER_CMD_STATUS 0x4
+#define LINK_TRAINING_ENABLE BIT(0)
+
+#define J721E_PCIE_USER_LINKSTATUS 0x14
+#define LINK_STATUS GENMASK(1, 0)
+
+enum link_status {
+ NO_RECEIVERS_DETECTED,
+ LINK_TRAINING_IN_PROGRESS,
+ LINK_UP_DL_IN_PROGRESS,
+ LINK_UP_DL_COMPLETED,
+};
+
+#define J721E_MODE_RC BIT(7)
+#define LANE_COUNT_MASK BIT(8)
+#define LANE_COUNT(n) ((n) << 8)
+
+#define GENERATION_SEL_MASK GENMASK(1, 0)
+
+#define MAX_LANES 2
+
+struct j721e_pcie {
+ struct device *dev;
+ u32 mode;
+ u32 num_lanes;
+ struct cdns_pcie *cdns_pcie;
+ void __iomem *user_cfg_base;
+ void __iomem *intd_cfg_base;
+};
+
+enum j721e_pcie_mode {
+ PCI_MODE_RC,
+ PCI_MODE_EP,
+};
+
+struct j721e_pcie_data {
+ enum j721e_pcie_mode mode;
+};
+
+static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
+{
+ return readl(pcie->user_cfg_base + offset);
+}
+
+static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
+ u32 value)
+{
+ writel(value, pcie->user_cfg_base + offset);
+}
+
+static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
+{
+ return readl(pcie->intd_cfg_base + offset);
+}
+
+static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
+ u32 value)
+{
+ writel(value, pcie->intd_cfg_base + offset);
+}
+
+static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
+{
+ struct j721e_pcie *pcie = priv;
+ struct device *dev = pcie->dev;
+ u32 reg;
+
+ reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
+ if (!(reg & LINK_DOWN))
+ return IRQ_NONE;
+
+ dev_err(dev, "LINK DOWN!\n");
+
+ j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
+ return IRQ_HANDLED;
+}
+
+static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
+{
+ u32 reg;
+
+ reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
+ reg |= LINK_DOWN;
+ j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
+}
+
+static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+ reg |= LINK_TRAINING_ENABLE;
+ j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+
+ return 0;
+}
+
+static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+ reg &= ~LINK_TRAINING_ENABLE;
+ j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+}
+
+static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
+ reg &= LINK_STATUS;
+ if (reg == LINK_UP_DL_COMPLETED)
+ return true;
+
+ return false;
+}
+
+static const struct cdns_pcie_ops j721e_pcie_ops = {
+ .start_link = j721e_pcie_start_link,
+ .stop_link = j721e_pcie_stop_link,
+ .link_up = j721e_pcie_link_up,
+};
+
+static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ u32 mask = J721E_MODE_RC;
+ u32 mode = pcie->mode;
+ u32 val = 0;
+ int ret = 0;
+
+ if (mode == PCI_MODE_RC)
+ val = J721E_MODE_RC;
+
+ ret = regmap_update_bits(syscon, 0, mask, val);
+ if (ret)
+ dev_err(dev, "failed to set pcie mode\n");
+
+ return ret;
+}
+
+static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
+ struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ int link_speed;
+ u32 val = 0;
+ int ret;
+
+ link_speed = of_pci_get_max_link_speed(np);
+ if (link_speed < 2)
+ link_speed = 2;
+
+ val = link_speed - 1;
+ ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
+ if (ret)
+ dev_err(dev, "failed to set link speed\n");
+
+ return ret;
+}
+
+static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
+ struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ u32 lanes = pcie->num_lanes;
+ u32 val = 0;
+ int ret;
+
+ val = LANE_COUNT(lanes - 1);
+ ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
+ if (ret)
+ dev_err(dev, "failed to set link count\n");
+
+ return ret;
+}
+
+static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ struct device_node *node = dev->of_node;
+ struct regmap *syscon;
+ int ret;
+
+ syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
+ if (IS_ERR(syscon)) {
+ dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
+ return PTR_ERR(syscon);
+ }
+
+ ret = j721e_pcie_set_mode(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set pci mode\n");
+ return ret;
+ }
+
+ ret = j721e_pcie_set_link_speed(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set link speed\n");
+ return ret;
+ }
+
+ ret = j721e_pcie_set_lane_count(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set num-lanes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ if (pci_is_root_bus(bus))
+ return pci_generic_config_read32(bus, devfn, where, size,
+ value);
+
+ return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ if (pci_is_root_bus(bus))
+ return pci_generic_config_write32(bus, devfn, where, size,
+ value);
+
+ return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
+static struct pci_ops cdns_ti_pcie_host_ops = {
+ .map_bus = cdns_pci_map_bus,
+ .read = cdns_ti_pcie_config_read,
+ .write = cdns_ti_pcie_config_write,
+};
+
+static const struct j721e_pcie_data j721e_pcie_rc_data = {
+ .mode = PCI_MODE_RC,
+};
+
+static const struct j721e_pcie_data j721e_pcie_ep_data = {
+ .mode = PCI_MODE_EP,
+};
+
+static const struct of_device_id of_j721e_pcie_match[] = {
+ {
+ .compatible = "ti,j721e-pcie-host",
+ .data = &j721e_pcie_rc_data,
+ },
+ {
+ .compatible = "ti,j721e-pcie-ep",
+ .data = &j721e_pcie_ep_data,
+ },
+ {},
+};
+
+static int j721e_pcie_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct j721e_pcie_data *data;
+ struct cdns_pcie *cdns_pcie;
+ struct j721e_pcie *pcie;
+ struct cdns_pcie_rc *rc;
+ struct cdns_pcie_ep *ep;
+ struct gpio_desc *gpiod;
+ void __iomem *base;
+ u32 num_lanes;
+ u32 mode;
+ int ret;
+ int irq;
+
+ data = (struct j721e_pcie_data *)of_device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ mode = (u32)data->mode;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->dev = dev;
+ pcie->mode = mode;
+
+ base = devm_platform_ioremap_resource_byname(pdev, "intd_cfg");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ pcie->intd_cfg_base = base;
+
+ base = devm_platform_ioremap_resource_byname(pdev, "user_cfg");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ pcie->user_cfg_base = base;
+
+ ret = of_property_read_u32(node, "num-lanes", &num_lanes);
+ if (ret || num_lanes > MAX_LANES)
+ num_lanes = 1;
+ pcie->num_lanes = num_lanes;
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)))
+ return -EINVAL;
+
+ irq = platform_get_irq_byname(pdev, "link_state");
+ if (irq < 0)
+ return irq;
+
+ dev_set_drvdata(dev, pcie);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_get_sync;
+ }
+
+ ret = j721e_pcie_ctrl_init(pcie);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_get_sync;
+ }
+
+ ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler, 0,
+ "j721e-pcie-link-down-irq", pcie);
+ if (ret < 0) {
+ dev_err(dev, "failed to request link state IRQ %d\n", irq);
+ goto err_get_sync;
+ }
+
+ j721e_pcie_config_link_irq(pcie);
+
+ switch (mode) {
+ case PCI_MODE_RC:
+ if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
+ ret = -ENODEV;
+ goto err_get_sync;
+ }
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+ if (!bridge) {
+ ret = -ENOMEM;
+ goto err_get_sync;
+ }
+
+ bridge->ops = &cdns_ti_pcie_host_ops;
+ rc = pci_host_bridge_priv(bridge);
+
+ cdns_pcie = &rc->pcie;
+ cdns_pcie->dev = dev;
+ cdns_pcie->ops = &j721e_pcie_ops;
+ pcie->cdns_pcie = cdns_pcie;
+
+ gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod)) {
+ ret = PTR_ERR(gpiod);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get reset GPIO\n");
+ goto err_get_sync;
+ }
+
+ ret = cdns_pcie_init_phy(dev, cdns_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to init phy\n");
+ goto err_get_sync;
+ }
+
+ /*
+ * "Power Sequencing and Reset Signal Timings" table in
+ * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
+ * indicates PERST# should be deasserted after minimum of 100us
+ * once REFCLK is stable. The REFCLK to the connector in RC
+ * mode is selected while enabling the PHY. So deassert PERST#
+ * after 100 us.
+ */
+ if (gpiod) {
+ usleep_range(100, 200);
+ gpiod_set_value_cansleep(gpiod, 1);
+ }
+
+ ret = cdns_pcie_host_setup(rc);
+ if (ret < 0)
+ goto err_pcie_setup;
+
+ break;
+ case PCI_MODE_EP:
+ if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
+ ret = -ENODEV;
+ goto err_get_sync;
+ }
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ ret = -ENOMEM;
+ goto err_get_sync;
+ }
+
+ cdns_pcie = &ep->pcie;
+ cdns_pcie->dev = dev;
+ cdns_pcie->ops = &j721e_pcie_ops;
+ pcie->cdns_pcie = cdns_pcie;
+
+ ret = cdns_pcie_init_phy(dev, cdns_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to init phy\n");
+ goto err_get_sync;
+ }
+
+ ret = cdns_pcie_ep_setup(ep);
+ if (ret < 0)
+ goto err_pcie_setup;
+
+ break;
+ default:
+ dev_err(dev, "INVALID device type %d\n", mode);
+ }
+
+ return 0;
+
+err_pcie_setup:
+ cdns_pcie_disable_phy(cdns_pcie);
+
+err_get_sync:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int j721e_pcie_remove(struct platform_device *pdev)
+{
+ struct j721e_pcie *pcie = platform_get_drvdata(pdev);
+ struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
+ struct device *dev = &pdev->dev;
+
+ cdns_pcie_disable_phy(cdns_pcie);
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+static struct platform_driver j721e_pcie_driver = {
+ .probe = j721e_pcie_probe,
+ .remove = j721e_pcie_remove,
+ .driver = {
+ .name = "j721e-pcie",
+ .of_match_table = of_j721e_pcie_match,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(j721e_pcie_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index e208fa5904bc..254a3e1eff50 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -8,7 +8,6 @@
#include <linux/of.h>
#include <linux/pci-epc.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
#include <linux/sizes.h>
#include "pcie-cadence.h"
@@ -52,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
struct pci_epf_bar *epf_bar)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie_epf *epf = &ep->epf[fn];
struct cdns_pcie *pcie = &ep->pcie;
dma_addr_t bar_phys = epf_bar->phys_addr;
enum pci_barno bar = epf_bar->barno;
@@ -112,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
cdns_pcie_writel(pcie, reg, cfg);
+ epf->epf_bar[bar] = epf_bar;
+
return 0;
}
@@ -119,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
struct pci_epf_bar *epf_bar)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie_epf *epf = &ep->epf[fn];
struct cdns_pcie *pcie = &ep->pcie;
enum pci_barno bar = epf_bar->barno;
u32 reg, cfg, b, ctrl;
@@ -140,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+
+ epf->epf_bar[bar] = NULL;
}
static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
@@ -225,10 +230,55 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
return mme;
}
+static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 val, reg;
+
+ reg = cap + PCI_MSIX_FLAGS;
+ val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
+ if (!(val & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ val &= PCI_MSIX_FLAGS_QSIZE;
+
+ return val;
+}
+
+static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
+ enum pci_barno bir, u32 offset)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 val, reg;
+
+ reg = cap + PCI_MSIX_FLAGS;
+ val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
+ val &= ~PCI_MSIX_FLAGS_QSIZE;
+ val |= interrupts;
+ cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
+
+ /* Set MSIX BAR and offset */
+ reg = cap + PCI_MSIX_TABLE;
+ val = offset | bir;
+ cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+ /* Set PBA BAR and offset. BAR must match MSIX BAR */
+ reg = cap + PCI_MSIX_PBA;
+ val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
+ cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+ return 0;
+}
+
static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
u8 intx, bool is_asserted)
{
struct cdns_pcie *pcie = &ep->pcie;
+ unsigned long flags;
u32 offset;
u16 status;
u8 msg_code;
@@ -253,11 +303,13 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
msg_code = MSG_CODE_DEASSERT_INTA + intx;
}
+ spin_lock_irqsave(&ep->lock, flags);
status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
status ^= PCI_STATUS_INTERRUPT;
cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
}
+ spin_unlock_irqrestore(&ep->lock, flags);
offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
@@ -331,6 +383,51 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
return 0;
}
+static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
+ u16 interrupt_num)
+{
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 tbl_offset, msg_data, reg;
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct pci_epf_msix_tbl *msix_tbl;
+ struct cdns_pcie_epf *epf;
+ u64 pci_addr_mask = 0xff;
+ u64 msg_addr;
+ u16 flags;
+ u8 bir;
+
+ /* Check whether the MSI-X feature has been enabled by the PCI host. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
+ if (!(flags & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ reg = cap + PCI_MSIX_TABLE;
+ tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
+ bir = tbl_offset & PCI_MSIX_TABLE_BIR;
+ tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+
+ epf = &ep->epf[fn];
+ msix_tbl = epf->epf_bar[bir]->addr + tbl_offset;
+ msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
+ msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
+
+ /* Set the outbound region if needed. */
+ if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
+ ep->irq_pci_fn != fn) {
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region(pcie, 0, fn, 0,
+ false,
+ ep->irq_phys_addr,
+ msg_addr & ~pci_addr_mask,
+ pci_addr_mask + 1);
+ ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
+ ep->irq_pci_fn = fn;
+ }
+ writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
+
+ return 0;
+}
+
static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
enum pci_epc_irq_type type,
u16 interrupt_num)
@@ -344,6 +441,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
case PCI_EPC_IRQ_MSI:
return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
+ case PCI_EPC_IRQ_MSIX:
+ return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
+
default:
break;
}
@@ -355,8 +455,10 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
struct cdns_pcie *pcie = &ep->pcie;
+ struct device *dev = pcie->dev;
struct pci_epf *epf;
u32 cfg;
+ int ret;
/*
* BIT(0) is hardwired to 1, hence function 0 is always enabled
@@ -367,13 +469,19 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
cfg |= BIT(epf->func_no);
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
+ ret = cdns_pcie_start_link(pcie);
+ if (ret) {
+ dev_err(dev, "Failed to start link\n");
+ return ret;
+ }
+
return 0;
}
static const struct pci_epc_features cdns_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
- .msix_capable = false,
+ .msix_capable = true,
};
static const struct pci_epc_features*
@@ -390,6 +498,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
.unmap_addr = cdns_pcie_ep_unmap_addr,
.set_msi = cdns_pcie_ep_set_msi,
.get_msi = cdns_pcie_ep_get_msi,
+ .set_msix = cdns_pcie_ep_set_msix,
+ .get_msix = cdns_pcie_ep_get_msix,
.raise_irq = cdns_pcie_ep_raise_irq,
.start = cdns_pcie_ep_start,
.get_features = cdns_pcie_ep_get_features,
@@ -439,8 +549,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "failed to create epc device\n");
- ret = PTR_ERR(epc);
- goto err_init;
+ return PTR_ERR(epc);
}
epc_set_drvdata(epc, ep);
@@ -448,11 +557,16 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
epc->max_functions = 1;
+ ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
+ GFP_KERNEL);
+ if (!ep->epf)
+ return -ENOMEM;
+
ret = pci_epc_mem_init(epc, pcie->mem_res->start,
resource_size(pcie->mem_res), PAGE_SIZE);
if (ret < 0) {
dev_err(dev, "failed to initialize the memory space\n");
- goto err_init;
+ return ret;
}
ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
@@ -465,14 +579,12 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
/* Reserve region 0 for IRQs */
set_bit(0, &ep->ob_region_map);
+ spin_lock_init(&ep->lock);
return 0;
free_epc_mem:
pci_epc_mem_exit(epc);
- err_init:
- pm_runtime_put_sync(dev);
-
return ret;
}
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index e60f72780ab0..4550e0d469ca 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -3,16 +3,28 @@
// Cadence PCIe host controller driver.
// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+#include <linux/delay.h>
#include <linux/kernel.h>
+#include <linux/list_sort.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
#include "pcie-cadence.h"
-static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
- int where)
+static u64 bar_max_size[] = {
+ [RP_BAR0] = _ULL(128 * SZ_2G),
+ [RP_BAR1] = SZ_2G,
+ [RP_NO_BAR] = _BITULL(63),
+};
+
+static u8 bar_aperture_mask[] = {
+ [RP_BAR0] = 0x1F,
+ [RP_BAR1] = 0xF,
+};
+
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
@@ -70,6 +82,7 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
u32 value, ctrl;
+ u32 id;
/*
* Set the root complex BAR configuration register:
@@ -89,8 +102,12 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
/* Set root port configuration space */
- if (rc->vendor_id != 0xffff)
- cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+ if (rc->vendor_id != 0xffff) {
+ id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
+ CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+ }
+
if (rc->device_id != 0xffff)
cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
@@ -101,16 +118,226 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
return 0;
}
+static int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
+ enum cdns_pcie_rp_bar bar,
+ u64 cpu_addr, u64 size,
+ unsigned long flags)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 addr0, addr1, aperture, value;
+
+ if (!rc->avail_ib_bar[bar])
+ return -EBUSY;
+
+ rc->avail_ib_bar[bar] = false;
+
+ aperture = ilog2(size);
+ addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), addr1);
+
+ if (bar == RP_NO_BAR)
+ return 0;
+
+ value = cdns_pcie_readl(pcie, CDNS_PCIE_LM_RC_BAR_CFG);
+ value &= ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
+ LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
+ if (size + cpu_addr >= SZ_4G) {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
+ value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
+ } else {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
+ value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
+ }
+
+ value |= LM_RC_BAR_CFG_APERTURE(bar, aperture);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
+
+ return 0;
+}
+
+static enum cdns_pcie_rp_bar
+cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size <= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] < bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+
+static enum cdns_pcie_rp_bar
+cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size >= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] > bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+
+static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
+ struct resource_entry *entry)
+{
+ u64 cpu_addr, pci_addr, size, winsize;
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ enum cdns_pcie_rp_bar bar;
+ unsigned long flags;
+ int ret;
+
+ cpu_addr = entry->res->start;
+ pci_addr = entry->res->start - entry->offset;
+ flags = entry->res->flags;
+ size = resource_size(entry->res);
+
+ if (entry->offset) {
+ dev_err(dev, "PCI addr: %llx must be equal to CPU addr: %llx\n",
+ pci_addr, cpu_addr);
+ return -EINVAL;
+ }
+
+ while (size > 0) {
+ /*
+ * Try to find a minimum BAR whose size is greater than
+ * or equal to the remaining resource_entry size. This will
+ * fail if the size of each of the available BARs is less than
+ * the remaining resource_entry size.
+ * If a minimum BAR is found, IB ATU will be configured and
+ * exited.
+ */
+ bar = cdns_pcie_host_find_min_bar(rc, size);
+ if (bar != RP_BAR_UNDEFINED) {
+ ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr,
+ size, flags);
+ if (ret)
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ /*
+ * If the control reaches here, it would mean the remaining
+ * resource_entry size cannot be fitted in a single BAR. So we
+ * find a maximum BAR whose size is less than or equal to the
+ * remaining resource_entry size and split the resource entry
+ * so that part of resource entry is fitted inside the maximum
+ * BAR. The remaining size would be fitted during the next
+ * iteration of the loop.
+ * If a maximum BAR is not found, there is no way we can fit
+ * this resource_entry, so we error out.
+ */
+ bar = cdns_pcie_host_find_max_bar(rc, size);
+ if (bar == RP_BAR_UNDEFINED) {
+ dev_err(dev, "No free BAR to map cpu_addr %llx\n",
+ cpu_addr);
+ return -EINVAL;
+ }
+
+ winsize = bar_max_size[bar];
+ ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr, winsize,
+ flags);
+ if (ret) {
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ size -= winsize;
+ cpu_addr += winsize;
+ }
+
+ return 0;
+}
+
+static int cdns_pcie_host_dma_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct resource_entry *entry1, *entry2;
+
+ entry1 = container_of(a, struct resource_entry, node);
+ entry2 = container_of(b, struct resource_entry, node);
+
+ return resource_size(entry2->res) - resource_size(entry1->res);
+}
+
+static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct resource_entry *entry;
+ u32 no_bar_nbits = 32;
+ int err;
+
+ bridge = pci_host_bridge_from_priv(rc);
+ if (!bridge)
+ return -ENOMEM;
+
+ if (list_empty(&bridge->dma_ranges)) {
+ of_property_read_u32(np, "cdns,no-bar-match-nbits",
+ &no_bar_nbits);
+ err = cdns_pcie_host_bar_ib_config(rc, RP_NO_BAR, 0x0,
+ (u64)1 << no_bar_nbits, 0);
+ if (err)
+ dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
+ return err;
+ }
+
+ list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
+
+ resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+ err = cdns_pcie_host_bar_config(rc, entry);
+ if (err)
+ dev_err(dev, "Fail to configure IB using dma-ranges\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
- struct resource *mem_res = pcie->mem_res;
struct resource *cfg_res = rc->cfg_res;
struct resource_entry *entry;
+ u64 cpu_addr = cfg_res->start;
u32 addr0, addr1, desc1;
- u64 cpu_addr;
- int r, busnr = 0;
+ int r, err, busnr = 0;
entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
if (entry)
@@ -126,7 +353,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
- cpu_addr = cfg_res->start - mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
@@ -154,16 +383,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
r++;
}
- /*
- * Set Root Port no BAR match Inbound Translation registers:
- * needed for MSI and DMA.
- * Root Port BAR0 and BAR1 are disabled, hence no need to set their
- * inbound translation registers.
- */
- addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
- addr1 = 0;
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
+ err = cdns_pcie_host_map_dma_ranges(rc);
+ if (err)
+ return err;
return 0;
}
@@ -180,12 +402,30 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
}
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ int retries;
+
+ /* Check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+ if (cdns_pcie_link_up(pcie)) {
+ dev_info(dev, "Link up\n");
+ return 0;
+ }
+ usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+ }
+
+ return -ETIMEDOUT;
+}
+
int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
{
struct device *dev = rc->pcie.dev;
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
struct pci_host_bridge *bridge;
+ enum cdns_pcie_rp_bar bar;
struct cdns_pcie *pcie;
struct resource *res;
int ret;
@@ -197,9 +437,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
pcie = &rc->pcie;
pcie->is_rc = true;
- rc->no_bar_nbits = 32;
- of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
-
rc->vendor_id = 0xffff;
of_property_read_u32(np, "vendor-id", &rc->vendor_id);
@@ -218,19 +455,25 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
return PTR_ERR(rc->cfg_base);
rc->cfg_res = res;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
- if (!res) {
- dev_err(dev, "missing \"mem\"\n");
- return -EINVAL;
+ ret = cdns_pcie_start_link(pcie);
+ if (ret) {
+ dev_err(dev, "Failed to start link\n");
+ return ret;
}
- pcie->mem_res = res;
+ ret = cdns_pcie_host_wait_for_link(pcie);
+ if (ret)
+ dev_dbg(dev, "PCIe link never came up\n");
+
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
+ rc->avail_ib_bar[bar] = true;
ret = cdns_pcie_host_init(dev, rc);
if (ret)
- goto err_init;
+ return ret;
- bridge->ops = &cdns_pcie_host_ops;
+ if (!bridge->ops)
+ bridge->ops = &cdns_pcie_host_ops;
ret = pci_host_probe(bridge);
if (ret < 0)
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index f5c6bf6dfcb8..5fee0f89ab59 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -13,6 +13,8 @@
#include <linux/of_device.h>
#include "pcie-cadence.h"
+#define CDNS_PLAT_CPU_TO_BUS_ADDR 0x0FFFFFFF
+
/**
* struct cdns_plat_pcie - private data for this PCIe platform driver
* @pcie: Cadence PCIe controller
@@ -30,6 +32,15 @@ struct cdns_plat_pcie_of_data {
static const struct of_device_id cdns_plat_pcie_of_match[];
+static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
+{
+ return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
+}
+
+static const struct cdns_pcie_ops cdns_plat_ops = {
+ .cpu_addr_fixup = cdns_plat_cpu_addr_fixup,
+};
+
static int cdns_plat_pcie_probe(struct platform_device *pdev)
{
const struct cdns_plat_pcie_of_data *data;
@@ -66,6 +77,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
rc = pci_host_bridge_priv(bridge);
rc->pcie.dev = dev;
+ rc->pcie.ops = &cdns_plat_ops;
cdns_plat_pcie->pcie = &rc->pcie;
cdns_plat_pcie->is_rc = is_rc;
@@ -93,6 +105,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
return -ENOMEM;
ep->pcie.dev = dev;
+ ep->pcie.ops = &cdns_plat_ops;
cdns_plat_pcie->pcie = &ep->pcie;
cdns_plat_pcie->is_rc = is_rc;
@@ -115,9 +128,8 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
}
err_init:
- pm_runtime_put_sync(dev);
-
err_get_sync:
+ pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
cdns_pcie_disable_phy(cdns_plat_pcie->pcie);
phy_count = cdns_plat_pcie->pcie->phy_count;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index fdd13765ee75..3c3646502d05 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -73,7 +73,9 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
/* Set the CPU address */
- cpu_addr -= pcie->mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
@@ -101,7 +103,9 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
}
/* Set the CPU address */
- cpu_addr -= pcie->mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 02803f262f0c..feed1e3038f4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -10,6 +10,11 @@
#include <linux/pci.h>
#include <linux/phy/phy.h>
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MIN 90000
+#define LINK_WAIT_USLEEP_MAX 100000
+
/*
* Local Management Registers
*/
@@ -87,6 +92,20 @@
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
+#define LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \
+ (((aperture) - 2) << ((bar) * 8))
/*
* Endpoint Function Registers (PCI configuration space for endpoint functions)
@@ -94,6 +113,7 @@
#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
+#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET 0xb0
/*
* Root Port Registers (PCI configuration space for the root port function)
@@ -170,11 +190,19 @@
#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
enum cdns_pcie_rp_bar {
+ RP_BAR_UNDEFINED = -1,
RP_BAR0,
RP_BAR1,
RP_NO_BAR
};
+#define CDNS_PCIE_RP_MAX_IB 0x3
+
+struct cdns_pcie_rp_ib_bar {
+ u64 size;
+ bool free;
+};
+
/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
(CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
@@ -223,12 +251,21 @@ enum cdns_pcie_msg_routing {
MSG_ROUTING_GATHER,
};
+struct cdns_pcie_ops {
+ int (*start_link)(struct cdns_pcie *pcie);
+ void (*stop_link)(struct cdns_pcie *pcie);
+ bool (*link_up)(struct cdns_pcie *pcie);
+ u64 (*cpu_addr_fixup)(struct cdns_pcie *pcie, u64 cpu_addr);
+};
+
/**
* 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
* @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
+ * wrapper
*/
struct cdns_pcie {
void __iomem *reg_base;
@@ -238,7 +275,7 @@ struct cdns_pcie {
int phy_count;
struct phy **phy;
struct device_link **link;
- const struct cdns_pcie_common_ops *ops;
+ const struct cdns_pcie_ops *ops;
};
/**
@@ -249,18 +286,26 @@ struct cdns_pcie {
* configuration space accesses
* @cfg_base: IO mapped window to access the PCI configuration space of a
* single function at a time
- * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
- * translation (nbits sets into the "no BAR match" register)
* @vendor_id: PCI vendor ID
* @device_id: PCI device ID
+ * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 and RP_NO_BAR if it's free or
+ * available
*/
struct cdns_pcie_rc {
struct cdns_pcie pcie;
struct resource *cfg_res;
void __iomem *cfg_base;
- u32 no_bar_nbits;
u32 vendor_id;
u32 device_id;
+ bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
+};
+
+/**
+ * struct cdns_pcie_epf - Structure to hold info about endpoint function
+ * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
+ */
+struct cdns_pcie_epf {
+ struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
};
/**
@@ -279,6 +324,10 @@ struct cdns_pcie_rc {
* @irq_pci_fn: the latest PCI function that has updated the mapping of
* the MSI/legacy IRQ dedicated outbound region.
* @irq_pending: bitmask of asserted legacy IRQs.
+ * @lock: spin lock to disable interrupts while modifying PCIe controller
+ * registers fields (RMW) accessible by both remote RC and EP to
+ * minimize time between read and write
+ * @epf: Structure to hold info about endpoint function
*/
struct cdns_pcie_ep {
struct cdns_pcie pcie;
@@ -290,54 +339,95 @@ struct cdns_pcie_ep {
u64 irq_pci_addr;
u8 irq_pci_fn;
u8 irq_pending;
+ /* protect writing to PCI_STATUS while raising legacy interrupts */
+ spinlock_t lock;
+ struct cdns_pcie_epf *epf;
};
/* Register access */
-static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
+static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
{
- writeb(value, pcie->reg_base + reg);
+ writel(value, pcie->reg_base + reg);
}
-static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
+static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
{
- writew(value, pcie->reg_base + reg);
+ return readl(pcie->reg_base + reg);
}
-static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
+static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
{
- writel(value, pcie->reg_base + reg);
+ void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+ unsigned int offset = (unsigned long)addr & 0x3;
+ u32 val = readl(aligned_addr);
+
+ if (!IS_ALIGNED((uintptr_t)addr, size)) {
+ pr_warn("Address %p and size %d are not aligned\n", addr, size);
+ return 0;
+ }
+
+ if (size > 2)
+ return val;
+
+ return (val >> (8 * offset)) & ((1 << (size * 8)) - 1);
}
-static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
+static inline void cdns_pcie_write_sz(void __iomem *addr, int size, u32 value)
{
- return readl(pcie->reg_base + reg);
+ void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
+ unsigned int offset = (unsigned long)addr & 0x3;
+ u32 mask;
+ u32 val;
+
+ if (!IS_ALIGNED((uintptr_t)addr, size)) {
+ pr_warn("Address %p and size %d are not aligned\n", addr, size);
+ return;
+ }
+
+ if (size > 2) {
+ writel(value, addr);
+ return;
+ }
+
+ mask = ~(((1 << (size * 8)) - 1) << (offset * 8));
+ val = readl(aligned_addr) & mask;
+ val |= value << (offset * 8);
+ writel(val, aligned_addr);
}
/* Root Port register access */
static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
u32 reg, u8 value)
{
- writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+ cdns_pcie_write_sz(addr, 0x1, value);
}
static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
u32 reg, u16 value)
{
- writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+ cdns_pcie_write_sz(addr, 0x2, value);
}
/* Endpoint Function register access */
static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
u32 reg, u8 value)
{
- writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+ cdns_pcie_write_sz(addr, 0x1, value);
}
static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
u32 reg, u16 value)
{
- writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+ cdns_pcie_write_sz(addr, 0x2, value);
}
static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
@@ -346,14 +436,11 @@ static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
-static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
-{
- return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
-}
-
static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
{
- return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+ void __iomem *addr = pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg;
+
+ return cdns_pcie_read_sz(addr, 0x2);
}
static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
@@ -361,13 +448,43 @@ static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
+static inline int cdns_pcie_start_link(struct cdns_pcie *pcie)
+{
+ if (pcie->ops->start_link)
+ return pcie->ops->start_link(pcie);
+
+ return 0;
+}
+
+static inline void cdns_pcie_stop_link(struct cdns_pcie *pcie)
+{
+ if (pcie->ops->stop_link)
+ pcie->ops->stop_link(pcie);
+}
+
+static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)
+{
+ if (pcie->ops->link_up)
+ return pcie->ops->link_up(pcie);
+
+ return true;
+}
+
#ifdef CONFIG_PCIE_CADENCE_HOST
int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where);
#else
static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
{
return 0;
}
+
+static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ return NULL;
+}
#endif
#ifdef CONFIG_PCIE_CADENCE_EP
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index 6184ebc9392d..5fda5f4d68b1 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -2,7 +2,7 @@
/*
* pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs
*
- * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Kishon Vijay Abraham I <kishon@ti.com>
*/
@@ -593,13 +593,12 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics");
- pci->dbi_base = devm_ioremap_resource(dev, res);
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "ep_dbics");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ep_dbics2");
- pci->dbi_base2 = devm_ioremap_resource(dev, res);
+ pci->dbi_base2 =
+ devm_platform_ioremap_resource_byname(pdev, "ep_dbics2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
@@ -626,7 +625,6 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
struct dw_pcie *pci = dra7xx->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
- struct resource *res;
pp->irq = platform_get_irq(pdev, 1);
if (pp->irq < 0) {
@@ -638,8 +636,7 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
if (ret < 0)
return ret;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics");
- pci->dbi_base = devm_ioremap_resource(dev, res);
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "rc_dbics");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
@@ -998,9 +995,8 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
return 0;
err_gpio:
- pm_runtime_put(dev);
-
err_get_sync:
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
dra7xx_pcie_disable_phy(dra7xx);
diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
index 5791039d6a54..5b136a59938d 100644
--- a/drivers/pci/controller/dwc/pci-exynos.c
+++ b/drivers/pci/controller/dwc/pci-exynos.c
@@ -3,7 +3,7 @@
* PCIe host controller driver for Samsung Exynos SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
*/
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 9f1e4d9c008b..12ac47178c91 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -3,7 +3,7 @@
* PCIe host controller driver for Freescale i.MX6 SoCs
*
* Copyright (C) 2013 Kosagi
- * http://www.kosagi.com
+ * https://www.kosagi.com
*
* Author: Sean Cross <xobs@kosagi.com>
*/
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index fcc3586c345b..d274c64d6799 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -3,7 +3,7 @@
* PCIe host controller driver for Texas Instruments Keystone SoCs
*
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
- * http://www.ti.com
+ * https://www.ti.com
*
* Author: Murali Karicheri <m-karicheri2@ti.com>
* Implementation based on pci-exynos.c and pcie-designware.c
@@ -1323,8 +1323,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
}
if (pci->version >= 0x480A) {
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
- atu_base = devm_ioremap_resource(dev, res);
+ atu_base = devm_platform_ioremap_resource_byname(pdev, "atu");
if (IS_ERR(atu_base)) {
ret = PTR_ERR(atu_base);
goto err_get_sync;
diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
index 28d5a1095200..7d2cfa288b01 100644
--- a/drivers/pci/controller/dwc/pcie-artpec6.c
+++ b/drivers/pci/controller/dwc/pcie-artpec6.c
@@ -455,8 +455,7 @@ static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
- pci->dbi_base2 = devm_ioremap_resource(dev, res);
+ pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
@@ -481,8 +480,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dw_pcie *pci;
struct artpec6_pcie *artpec6_pcie;
- struct resource *dbi_base;
- struct resource *phy_base;
int ret;
const struct of_device_id *match;
const struct artpec_pcie_of_data *data;
@@ -512,13 +509,12 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
artpec6_pcie->variant = variant;
artpec6_pcie->mode = mode;
- dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
- pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
- phy_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
- artpec6_pcie->phy_base = devm_ioremap_resource(dev, phy_base);
+ artpec6_pcie->phy_base =
+ devm_platform_ioremap_resource_byname(pdev, "phy");
if (IS_ERR(artpec6_pcie->phy_base))
return PTR_ERR(artpec6_pcie->phy_base);
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 7461357d98f6..9dafecba347f 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -3,7 +3,7 @@
* Synopsys DesignWare PCIe host controller driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
*/
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index 73646b677aff..712456f6ce36 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -153,8 +153,7 @@ static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
- pci->dbi_base2 = devm_ioremap_resource(dev, res);
+ pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c92496e36fd5..b723e0cc41fb 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -3,7 +3,7 @@
* Synopsys DesignWare PCIe host controller driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
*/
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index fd2146298b58..f911760dcc69 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -3,7 +3,7 @@
* Synopsys DesignWare PCIe host controller driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
+ * https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
*/
diff --git a/drivers/pci/controller/dwc/pcie-hisi.c b/drivers/pci/controller/dwc/pcie-hisi.c
index 0ad4e07dd4c2..5ca86796d43a 100644
--- a/drivers/pci/controller/dwc/pcie-hisi.c
+++ b/drivers/pci/controller/dwc/pcie-hisi.c
@@ -10,15 +10,10 @@
*/
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_address.h>
-#include <linux/of_pci.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
-#include <linux/regmap.h>
#include "../../pci.h"
#if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
@@ -118,220 +113,6 @@ const struct pci_ecam_ops hisi_pcie_ops = {
#ifdef CONFIG_PCI_HISI
-#include "pcie-designware.h"
-
-#define PCIE_SUBCTRL_SYS_STATE4_REG 0x6818
-#define PCIE_HIP06_CTRL_OFF 0x1000
-#define PCIE_SYS_STATE4 (PCIE_HIP06_CTRL_OFF + 0x31c)
-#define PCIE_LTSSM_LINKUP_STATE 0x11
-#define PCIE_LTSSM_STATE_MASK 0x3F
-
-#define to_hisi_pcie(x) dev_get_drvdata((x)->dev)
-
-struct hisi_pcie;
-
-struct pcie_soc_ops {
- int (*hisi_pcie_link_up)(struct hisi_pcie *hisi_pcie);
-};
-
-struct hisi_pcie {
- struct dw_pcie *pci;
- struct regmap *subctrl;
- u32 port_id;
- const struct pcie_soc_ops *soc_ops;
-};
-
-/* HipXX PCIe host only supports 32-bit config access */
-static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
- u32 *val)
-{
- u32 reg;
- u32 reg_val;
- void *walker = &reg_val;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
- walker += (where & 0x3);
- reg = where & ~0x3;
- reg_val = dw_pcie_readl_dbi(pci, reg);
-
- if (size == 1)
- *val = *(u8 __force *) walker;
- else if (size == 2)
- *val = *(u16 __force *) walker;
- else if (size == 4)
- *val = reg_val;
- else
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/* HipXX PCIe host only supports 32-bit config access */
-static int hisi_pcie_cfg_write(struct pcie_port *pp, int where, int size,
- u32 val)
-{
- u32 reg_val;
- u32 reg;
- void *walker = &reg_val;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
- walker += (where & 0x3);
- reg = where & ~0x3;
- if (size == 4)
- dw_pcie_writel_dbi(pci, reg, val);
- else if (size == 2) {
- reg_val = dw_pcie_readl_dbi(pci, reg);
- *(u16 __force *) walker = val;
- dw_pcie_writel_dbi(pci, reg, reg_val);
- } else if (size == 1) {
- reg_val = dw_pcie_readl_dbi(pci, reg);
- *(u8 __force *) walker = val;
- dw_pcie_writel_dbi(pci, reg, reg_val);
- } else
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hisi_pcie_link_up_hip05(struct hisi_pcie *hisi_pcie)
-{
- u32 val;
-
- regmap_read(hisi_pcie->subctrl, PCIE_SUBCTRL_SYS_STATE4_REG +
- 0x100 * hisi_pcie->port_id, &val);
-
- return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE);
-}
-
-static int hisi_pcie_link_up_hip06(struct hisi_pcie *hisi_pcie)
-{
- struct dw_pcie *pci = hisi_pcie->pci;
- u32 val;
-
- val = dw_pcie_readl_dbi(pci, PCIE_SYS_STATE4);
-
- return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE);
-}
-
-static int hisi_pcie_link_up(struct dw_pcie *pci)
-{
- struct hisi_pcie *hisi_pcie = to_hisi_pcie(pci);
-
- return hisi_pcie->soc_ops->hisi_pcie_link_up(hisi_pcie);
-}
-
-static const struct dw_pcie_host_ops hisi_pcie_host_ops = {
- .rd_own_conf = hisi_pcie_cfg_read,
- .wr_own_conf = hisi_pcie_cfg_write,
-};
-
-static int hisi_add_pcie_port(struct hisi_pcie *hisi_pcie,
- struct platform_device *pdev)
-{
- struct dw_pcie *pci = hisi_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- struct device *dev = &pdev->dev;
- int ret;
- u32 port_id;
-
- if (of_property_read_u32(dev->of_node, "port-id", &port_id)) {
- dev_err(dev, "failed to read port-id\n");
- return -EINVAL;
- }
- if (port_id > 3) {
- dev_err(dev, "Invalid port-id: %d\n", port_id);
- return -EINVAL;
- }
- hisi_pcie->port_id = port_id;
-
- pp->ops = &hisi_pcie_host_ops;
-
- ret = dw_pcie_host_init(pp);
- if (ret) {
- dev_err(dev, "failed to initialize host\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct dw_pcie_ops dw_pcie_ops = {
- .link_up = hisi_pcie_link_up,
-};
-
-static int hisi_pcie_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct dw_pcie *pci;
- struct hisi_pcie *hisi_pcie;
- struct resource *reg;
- int ret;
-
- hisi_pcie = devm_kzalloc(dev, sizeof(*hisi_pcie), GFP_KERNEL);
- if (!hisi_pcie)
- return -ENOMEM;
-
- pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
- if (!pci)
- return -ENOMEM;
-
- pci->dev = dev;
- pci->ops = &dw_pcie_ops;
-
- hisi_pcie->pci = pci;
-
- hisi_pcie->soc_ops = of_device_get_match_data(dev);
-
- hisi_pcie->subctrl =
- syscon_regmap_lookup_by_compatible("hisilicon,pcie-sas-subctrl");
- if (IS_ERR(hisi_pcie->subctrl)) {
- dev_err(dev, "cannot get subctrl base\n");
- return PTR_ERR(hisi_pcie->subctrl);
- }
-
- reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbi");
- pci->dbi_base = devm_pci_remap_cfg_resource(dev, reg);
- if (IS_ERR(pci->dbi_base))
- return PTR_ERR(pci->dbi_base);
- platform_set_drvdata(pdev, hisi_pcie);
-
- ret = hisi_add_pcie_port(hisi_pcie, pdev);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static struct pcie_soc_ops hip05_ops = {
- &hisi_pcie_link_up_hip05
-};
-
-static struct pcie_soc_ops hip06_ops = {
- &hisi_pcie_link_up_hip06
-};
-
-static const struct of_device_id hisi_pcie_of_match[] = {
- {
- .compatible = "hisilicon,hip05-pcie",
- .data = (void *) &hip05_ops,
- },
- {
- .compatible = "hisilicon,hip06-pcie",
- .data = (void *) &hip06_ops,
- },
- {},
-};
-
-static struct platform_driver hisi_pcie_driver = {
- .probe = hisi_pcie_probe,
- .driver = {
- .name = "hisi-pcie",
- .of_match_table = hisi_pcie_of_match,
- .suppress_bind_attrs = true,
- },
-};
-builtin_platform_driver(hisi_pcie_driver);
-
static int hisi_pcie_platform_init(struct pci_config_window *cfg)
{
struct device *dev = cfg->parent;
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
index 811b5c6d62ea..6d3524c39a9b 100644
--- a/drivers/pci/controller/dwc/pcie-histb.c
+++ b/drivers/pci/controller/dwc/pcie-histb.c
@@ -304,7 +304,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
struct histb_pcie *hipcie;
struct dw_pcie *pci;
struct pcie_port *pp;
- struct resource *res;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
enum of_gpio_flags of_flags;
@@ -324,15 +323,13 @@ static int histb_pcie_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = &dw_pcie_ops;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
- hipcie->ctrl = devm_ioremap_resource(dev, res);
+ hipcie->ctrl = devm_platform_ioremap_resource_byname(pdev, "control");
if (IS_ERR(hipcie->ctrl)) {
dev_err(dev, "cannot get control reg base\n");
return PTR_ERR(hipcie->ctrl);
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc-dbi");
- pci->dbi_base = devm_ioremap_resource(dev, res);
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "rc-dbi");
if (IS_ERR(pci->dbi_base)) {
dev_err(dev, "cannot get rc-dbi base\n");
return PTR_ERR(pci->dbi_base);
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index 2d8dbb318087..c3b3a1d162b5 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -253,11 +253,9 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
struct intel_pcie_port *lpp = platform_get_drvdata(pdev);
struct dw_pcie *pci = &lpp->pci;
struct device *dev = pci->dev;
- struct resource *res;
int ret;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
- pci->dbi_base = devm_ioremap_resource(dev, res);
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
@@ -291,8 +289,7 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
ret = of_pci_get_max_link_speed(dev->of_node);
lpp->link_gen = ret < 0 ? 0 : ret;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app");
- lpp->app_base = devm_ioremap_resource(dev, res);
+ lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
if (IS_ERR(lpp->app_base))
return PTR_ERR(lpp->app_base);
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index c19617a912bd..9adaa65c581f 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -3,7 +3,7 @@
* PCIe host controller driver for Kirin Phone SoCs
*
* Copyright (C) 2017 HiSilicon Electronics Co., Ltd.
- * http://www.huawei.com
+ * https://www.huawei.com
*
* Author: Xiaowei Song <songxiaowei@huawei.com>
*/
@@ -147,23 +147,18 @@ static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct resource *apb;
- struct resource *phy;
- struct resource *dbi;
-
- apb = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb");
- kirin_pcie->apb_base = devm_ioremap_resource(dev, apb);
+ kirin_pcie->apb_base =
+ devm_platform_ioremap_resource_byname(pdev, "apb");
if (IS_ERR(kirin_pcie->apb_base))
return PTR_ERR(kirin_pcie->apb_base);
- phy = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
- kirin_pcie->phy_base = devm_ioremap_resource(dev, phy);
+ kirin_pcie->phy_base =
+ devm_platform_ioremap_resource_byname(pdev, "phy");
if (IS_ERR(kirin_pcie->phy_base))
return PTR_ERR(kirin_pcie->phy_base);
- dbi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
- kirin_pcie->pci->dbi_base = devm_ioremap_resource(dev, dbi);
+ kirin_pcie->pci->dbi_base =
+ devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(kirin_pcie->pci->dbi_base))
return PTR_ERR(kirin_pcie->pci->dbi_base);
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 138e1a2d21cc..3aac77a295ba 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/types.h>
+#include "../../pci.h"
#include "pcie-designware.h"
#define PCIE20_PARF_SYS_CTRL 0x00
@@ -39,13 +40,14 @@
#define L23_CLK_RMV_DIS BIT(2)
#define L1_CLK_RMV_DIS BIT(1)
-#define PCIE20_COMMAND_STATUS 0x04
-#define CMD_BME_VAL 0x4
-#define PCIE20_DEVICE_CONTROL2_STATUS2 0x98
-#define PCIE_CAP_CPL_TIMEOUT_DISABLE 0x10
-
#define PCIE20_PARF_PHY_CTRL 0x40
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK GENMASK(20, 16)
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) ((x) << 16)
+
#define PCIE20_PARF_PHY_REFCLK 0x4C
+#define PHY_REFCLK_SSP_EN BIT(16)
+#define PHY_REFCLK_USE_PAD BIT(12)
+
#define PCIE20_PARF_DBI_BASE_ADDR 0x168
#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16C
#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
@@ -66,8 +68,8 @@
#define CFG_BRIDGE_SB_INIT BIT(0)
#define PCIE20_CAP 0x70
-#define PCIE20_CAP_LINK_CAPABILITIES (PCIE20_CAP + 0xC)
-#define PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT (BIT(10) | BIT(11))
+#define PCIE20_DEVICE_CONTROL2_STATUS2 (PCIE20_CAP + PCI_EXP_DEVCTL2)
+#define PCIE20_CAP_LINK_CAPABILITIES (PCIE20_CAP + PCI_EXP_LNKCAP)
#define PCIE20_CAP_LINK_1 (PCIE20_CAP + 0x14)
#define PCIE_CAP_LINK1_VAL 0x2FD7F
@@ -77,22 +79,36 @@
#define DBI_RO_WR_EN 1
#define PERST_DELAY_US 1000
+/* PARF registers */
+#define PCIE20_PARF_PCS_DEEMPH 0x34
+#define PCS_DEEMPH_TX_DEEMPH_GEN1(x) ((x) << 16)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) ((x) << 8)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) ((x) << 0)
+
+#define PCIE20_PARF_PCS_SWING 0x38
+#define PCS_SWING_TX_SWING_FULL(x) ((x) << 8)
+#define PCS_SWING_TX_SWING_LOW(x) ((x) << 0)
+
+#define PCIE20_PARF_CONFIG_BITS 0x50
+#define PHY_RX0_EQ(x) ((x) << 24)
#define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358
#define SLV_ADDR_SPACE_SZ 0x10000000
+#define PCIE20_LNK_CONTROL2_LINK_STATUS2 0xa0
+
#define DEVICE_TYPE_RC 0x4
#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
+#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5
struct qcom_pcie_resources_2_1_0 {
- struct clk *iface_clk;
- struct clk *core_clk;
- struct clk *phy_clk;
+ struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
struct reset_control *pci_reset;
struct reset_control *axi_reset;
struct reset_control *ahb_reset;
struct reset_control *por_reset;
struct reset_control *phy_reset;
+ struct reset_control *ext_reset;
struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
};
@@ -177,6 +193,7 @@ struct qcom_pcie {
struct phy *phy;
struct gpio_desc *reset;
const struct qcom_pcie_ops *ops;
+ int gen;
};
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
@@ -234,17 +251,21 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
if (ret)
return ret;
- res->iface_clk = devm_clk_get(dev, "iface");
- if (IS_ERR(res->iface_clk))
- return PTR_ERR(res->iface_clk);
+ res->clks[0].id = "iface";
+ res->clks[1].id = "core";
+ res->clks[2].id = "phy";
+ res->clks[3].id = "aux";
+ res->clks[4].id = "ref";
- res->core_clk = devm_clk_get(dev, "core");
- if (IS_ERR(res->core_clk))
- return PTR_ERR(res->core_clk);
+ /* iface, core, phy are required */
+ ret = devm_clk_bulk_get(dev, 3, res->clks);
+ if (ret < 0)
+ return ret;
- res->phy_clk = devm_clk_get(dev, "phy");
- if (IS_ERR(res->phy_clk))
- return PTR_ERR(res->phy_clk);
+ /* aux, ref are optional */
+ ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3);
+ if (ret < 0)
+ return ret;
res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
if (IS_ERR(res->pci_reset))
@@ -262,6 +283,10 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
if (IS_ERR(res->por_reset))
return PTR_ERR(res->por_reset);
+ res->ext_reset = devm_reset_control_get_optional_exclusive(dev, "ext");
+ if (IS_ERR(res->ext_reset))
+ return PTR_ERR(res->ext_reset);
+
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
return PTR_ERR_OR_ZERO(res->phy_reset);
}
@@ -270,14 +295,13 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
+ clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
reset_control_assert(res->pci_reset);
reset_control_assert(res->axi_reset);
reset_control_assert(res->ahb_reset);
reset_control_assert(res->por_reset);
- reset_control_assert(res->pci_reset);
- clk_disable_unprepare(res->iface_clk);
- clk_disable_unprepare(res->core_clk);
- clk_disable_unprepare(res->phy_clk);
+ reset_control_assert(res->ext_reset);
+ reset_control_assert(res->phy_reset);
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
@@ -286,6 +310,7 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ struct device_node *node = dev->of_node;
u32 val;
int ret;
@@ -295,73 +320,85 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
return ret;
}
- ret = reset_control_assert(res->ahb_reset);
- if (ret) {
- dev_err(dev, "cannot assert ahb reset\n");
- goto err_assert_ahb;
- }
-
- ret = clk_prepare_enable(res->iface_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable iface clock\n");
- goto err_assert_ahb;
- }
-
- ret = clk_prepare_enable(res->phy_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable phy clock\n");
- goto err_clk_phy;
- }
-
- ret = clk_prepare_enable(res->core_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable core clock\n");
- goto err_clk_core;
- }
-
ret = reset_control_deassert(res->ahb_reset);
if (ret) {
dev_err(dev, "cannot deassert ahb reset\n");
goto err_deassert_ahb;
}
- /* enable PCIe clocks and resets */
- val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
- val &= ~BIT(0);
- writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
-
- /* enable external reference clock */
- val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
- val |= BIT(16);
- writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
+ ret = reset_control_deassert(res->ext_reset);
+ if (ret) {
+ dev_err(dev, "cannot deassert ext reset\n");
+ goto err_deassert_ext;
+ }
ret = reset_control_deassert(res->phy_reset);
if (ret) {
dev_err(dev, "cannot deassert phy reset\n");
- return ret;
+ goto err_deassert_phy;
}
ret = reset_control_deassert(res->pci_reset);
if (ret) {
dev_err(dev, "cannot deassert pci reset\n");
- return ret;
+ goto err_deassert_pci;
}
ret = reset_control_deassert(res->por_reset);
if (ret) {
dev_err(dev, "cannot deassert por reset\n");
- return ret;
+ goto err_deassert_por;
}
ret = reset_control_deassert(res->axi_reset);
if (ret) {
dev_err(dev, "cannot deassert axi reset\n");
- return ret;
+ goto err_deassert_axi;
}
+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
+ if (ret)
+ goto err_clks;
+
+ /* enable PCIe clocks and resets */
+ val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
+ val &= ~BIT(0);
+ writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
+
+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
+ of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
+ writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
+ PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
+ PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
+ pcie->parf + PCIE20_PARF_PCS_DEEMPH);
+ writel(PCS_SWING_TX_SWING_FULL(120) |
+ PCS_SWING_TX_SWING_LOW(120),
+ pcie->parf + PCIE20_PARF_PCS_SWING);
+ writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
+ }
+
+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
+ /* set TX termination offset */
+ val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
+ val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
+ val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
+ writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
+ }
+
+ /* enable external reference clock */
+ val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
+ val &= ~PHY_REFCLK_USE_PAD;
+ val |= PHY_REFCLK_SSP_EN;
+ writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
+
/* wait for clock acquisition */
usleep_range(1000, 1500);
+ if (pcie->gen == 1) {
+ val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
+ val |= PCI_EXP_LNKSTA_CLS_2_5GB;
+ writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
+ }
/* Set the Max TLP size to 2K, instead of using default of 4K */
writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
@@ -371,13 +408,19 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
return 0;
+err_clks:
+ reset_control_assert(res->axi_reset);
+err_deassert_axi:
+ reset_control_assert(res->por_reset);
+err_deassert_por:
+ reset_control_assert(res->pci_reset);
+err_deassert_pci:
+ reset_control_assert(res->phy_reset);
+err_deassert_phy:
+ reset_control_assert(res->ext_reset);
+err_deassert_ext:
+ reset_control_assert(res->ahb_reset);
err_deassert_ahb:
- clk_disable_unprepare(res->core_clk);
-err_clk_core:
- clk_disable_unprepare(res->phy_clk);
-err_clk_phy:
- clk_disable_unprepare(res->iface_clk);
-err_assert_ahb:
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
return ret;
@@ -1047,15 +1090,15 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
pcie->parf + PCIE20_PARF_SYS_CTRL);
writel(0, pcie->parf + PCIE20_PARF_Q2A_FLUSH);
- writel(CMD_BME_VAL, pci->dbi_base + PCIE20_COMMAND_STATUS);
+ writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1);
val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
- val &= ~PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT;
+ val &= ~PCI_EXP_LNKCAP_ASPMS;
writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
- writel(PCIE_CAP_CPL_TIMEOUT_DISABLE, pci->dbi_base +
+ writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base +
PCIE20_DEVICE_CONTROL2_STATUS2);
return 0;
@@ -1339,10 +1382,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_disable(dev);
- return ret;
- }
+ if (ret < 0)
+ goto err_pm_runtime_put;
pci->dev = dev;
pci->ops = &dw_pcie_ops;
@@ -1358,8 +1399,11 @@ static int qcom_pcie_probe(struct platform_device *pdev)
goto err_pm_runtime_put;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
- pcie->parf = devm_ioremap_resource(dev, res);
+ pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node);
+ if (pcie->gen < 0)
+ pcie->gen = 2;
+
+ pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
if (IS_ERR(pcie->parf)) {
ret = PTR_ERR(pcie->parf);
goto err_pm_runtime_put;
@@ -1372,8 +1416,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
goto err_pm_runtime_put;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
- pcie->elbi = devm_ioremap_resource(dev, res);
+ pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
if (IS_ERR(pcie->elbi)) {
ret = PTR_ERR(pcie->elbi);
goto err_pm_runtime_put;
@@ -1426,6 +1469,7 @@ err_pm_runtime_put:
static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
{ .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
+ { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 },
{ .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
index a5401a0b1e58..3a7f403b57b8 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier.c
@@ -416,8 +416,7 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "link");
- priv->base = devm_ioremap_resource(dev, res);
+ priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index 795e7632b068..1559f79e63b6 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -643,6 +643,13 @@ static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
if (pci_is_root_bus(bus) && PCI_SLOT(devfn) != 0)
return false;
+ /*
+ * If the link goes down after we check for link-up, nothing bad
+ * happens but the config access times out.
+ */
+ if (!pci_is_root_bus(bus) && !advk_pcie_link_up(pcie))
+ return false;
+
return true;
}
@@ -687,8 +694,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
advk_writel(pcie, 1, PIO_START);
ret = advk_pcie_wait_pio(pcie);
- if (ret < 0)
+ if (ret < 0) {
+ *val = 0xffffffff;
return PCIBIOS_SET_FAILED;
+ }
advk_pcie_check_pio_status(pcie);
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index bf40ff09c99d..fc4c3a15e570 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -938,8 +938,9 @@ out:
*
* Return: 0 on success, -errno on failure
*/
-int hv_read_config_block(struct pci_dev *pdev, void *buf, unsigned int len,
- unsigned int block_id, unsigned int *bytes_returned)
+static int hv_read_config_block(struct pci_dev *pdev, void *buf,
+ unsigned int len, unsigned int block_id,
+ unsigned int *bytes_returned)
{
struct hv_pcibus_device *hbus =
container_of(pdev->bus->sysdata, struct hv_pcibus_device,
@@ -1018,8 +1019,8 @@ static void hv_pci_write_config_compl(void *context, struct pci_response *resp,
*
* Return: 0 on success, -errno on failure
*/
-int hv_write_config_block(struct pci_dev *pdev, void *buf, unsigned int len,
- unsigned int block_id)
+static int hv_write_config_block(struct pci_dev *pdev, void *buf,
+ unsigned int len, unsigned int block_id)
{
struct hv_pcibus_device *hbus =
container_of(pdev->bus->sysdata, struct hv_pcibus_device,
@@ -1087,9 +1088,9 @@ int hv_write_config_block(struct pci_dev *pdev, void *buf, unsigned int len,
*
* Return: 0 on success, -errno on failure
*/
-int hv_register_block_invalidate(struct pci_dev *pdev, void *context,
- void (*block_invalidate)(void *context,
- u64 block_mask))
+static int hv_register_block_invalidate(struct pci_dev *pdev, void *context,
+ void (*block_invalidate)(void *context,
+ u64 block_mask))
{
struct hv_pcibus_device *hbus =
container_of(pdev->bus->sysdata, struct hv_pcibus_device,
@@ -2759,10 +2760,8 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
struct pci_bus_d0_entry *d0_entry;
struct hv_pci_compl comp_pkt;
struct pci_packet *pkt;
- bool retry = true;
int ret;
-enter_d0_retry:
/*
* Tell the host that the bus is ready to use, and moved into the
* powered-on state. This includes telling the host which region
@@ -2789,38 +2788,6 @@ enter_d0_retry:
if (ret)
goto exit;
- /*
- * In certain case (Kdump) the pci device of interest was
- * not cleanly shut down and resource is still held on host
- * side, the host could return invalid device status.
- * We need to explicitly request host to release the resource
- * and try to enter D0 again.
- */
- if (comp_pkt.completion_status < 0 && retry) {
- retry = false;
-
- dev_err(&hdev->device, "Retrying D0 Entry\n");
-
- /*
- * Hv_pci_bus_exit() calls hv_send_resource_released()
- * to free up resources of its child devices.
- * In the kdump kernel we need to set the
- * wslot_res_allocated to 255 so it scans all child
- * devices to release resources allocated in the
- * normal kernel before panic happened.
- */
- hbus->wslot_res_allocated = 255;
-
- ret = hv_pci_bus_exit(hdev, true);
-
- if (ret == 0) {
- kfree(pkt);
- goto enter_d0_retry;
- }
- dev_err(&hdev->device,
- "Retrying D0 failed with ret %d\n", ret);
- }
-
if (comp_pkt.completion_status < 0) {
dev_err(&hdev->device,
"PCI Pass-through VSP failed D0 Entry with status %x\n",
@@ -3058,6 +3025,7 @@ static int hv_pci_probe(struct hv_device *hdev,
struct hv_pcibus_device *hbus;
u16 dom_req, dom;
char *name;
+ bool enter_d0_retry = true;
int ret;
/*
@@ -3178,11 +3146,47 @@ static int hv_pci_probe(struct hv_device *hdev,
if (ret)
goto free_fwnode;
+retry:
ret = hv_pci_query_relations(hdev);
if (ret)
goto free_irq_domain;
ret = hv_pci_enter_d0(hdev);
+ /*
+ * In certain case (Kdump) the pci device of interest was
+ * not cleanly shut down and resource is still held on host
+ * side, the host could return invalid device status.
+ * We need to explicitly request host to release the resource
+ * and try to enter D0 again.
+ * Since the hv_pci_bus_exit() call releases structures
+ * of all its child devices, we need to start the retry from
+ * hv_pci_query_relations() call, requesting host to send
+ * the synchronous child device relations message before this
+ * information is needed in hv_send_resources_allocated()
+ * call later.
+ */
+ if (ret == -EPROTO && enter_d0_retry) {
+ enter_d0_retry = false;
+
+ dev_err(&hdev->device, "Retrying D0 Entry\n");
+
+ /*
+ * Hv_pci_bus_exit() calls hv_send_resources_released()
+ * to free up resources of its child devices.
+ * In the kdump kernel we need to set the
+ * wslot_res_allocated to 255 so it scans all child
+ * devices to release resources allocated in the
+ * normal kernel before panic happened.
+ */
+ hbus->wslot_res_allocated = 255;
+ ret = hv_pci_bus_exit(hdev, true);
+
+ if (ret == 0)
+ goto retry;
+
+ dev_err(&hdev->device,
+ "Retrying D0 failed with ret %d\n", ret);
+ }
if (ret)
goto free_irq_domain;
diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
index a7a7fbe2b7a5..719c19fe2bfb 100644
--- a/drivers/pci/controller/pci-loongson.c
+++ b/drivers/pci/controller/pci-loongson.c
@@ -37,11 +37,11 @@ static void bridge_class_quirk(struct pci_dev *dev)
{
dev->class = PCI_CLASS_BRIDGE_PCI << 8;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON,
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_0, bridge_class_quirk);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON,
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_1, bridge_class_quirk);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON,
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_2, bridge_class_quirk);
static void system_bus_quirk(struct pci_dev *pdev)
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index 12d30fb6ae6e..c39978b750ec 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -104,6 +104,7 @@ struct mvebu_pcie_port {
struct mvebu_pcie_window memwin;
struct mvebu_pcie_window iowin;
u32 saved_pcie_stat;
+ struct resource regs;
};
static inline void mvebu_writel(struct mvebu_pcie_port *port, u32 val, u32 reg)
@@ -148,7 +149,9 @@ static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr)
/*
* Setup PCIE BARs and Address Decode Wins:
- * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
+ * BAR[0] -> internal registers (needed for MSI)
+ * BAR[1] -> covers all DRAM banks
+ * BAR[2] -> Disabled
* WIN[0-3] -> DRAM bank[0-3]
*/
static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
@@ -202,6 +205,12 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
mvebu_writel(port, 0, PCIE_BAR_HI_OFF(1));
mvebu_writel(port, ((size - 1) & 0xffff0000) | 1,
PCIE_BAR_CTRL_OFF(1));
+
+ /*
+ * Point BAR[0] to the device's internal registers.
+ */
+ mvebu_writel(port, round_down(port->regs.start, SZ_1M), PCIE_BAR_LO_OFF(0));
+ mvebu_writel(port, 0, PCIE_BAR_HI_OFF(0));
}
static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
@@ -707,14 +716,13 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
struct device_node *np,
struct mvebu_pcie_port *port)
{
- struct resource regs;
int ret = 0;
- ret = of_address_to_resource(np, 0, &regs);
+ ret = of_address_to_resource(np, 0, &port->regs);
if (ret)
return (void __iomem *)ERR_PTR(ret);
- return devm_ioremap_resource(&pdev->dev, &regs);
+ return devm_ioremap_resource(&pdev->dev, &port->regs);
}
#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03)
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 2789d5500f2c..fdbcf0d6b9c3 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -181,13 +181,6 @@
#define AFI_PEXBIAS_CTRL_0 0x168
-#define RP_PRIV_XP_DL 0x00000494
-#define RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1ff << 1)
-
-#define RP_RX_HDR_LIMIT 0x00000e00
-#define RP_RX_HDR_LIMIT_PW_MASK (0xff << 8)
-#define RP_RX_HDR_LIMIT_PW (0x0e << 8)
-
#define RP_ECTL_2_R1 0x00000e84
#define RP_ECTL_2_R1_RX_CTLE_1C_MASK 0xffff
@@ -323,7 +316,6 @@ struct tegra_pcie_soc {
bool program_uphy;
bool update_clamp_threshold;
bool program_deskew_time;
- bool raw_violation_fixup;
bool update_fc_timer;
bool has_cache_bars;
struct {
@@ -659,23 +651,6 @@ static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
writel(value, port->base + RP_VEND_CTL0);
}
- /* Fixup for read after write violation. */
- if (soc->raw_violation_fixup) {
- value = readl(port->base + RP_RX_HDR_LIMIT);
- value &= ~RP_RX_HDR_LIMIT_PW_MASK;
- value |= RP_RX_HDR_LIMIT_PW;
- writel(value, port->base + RP_RX_HDR_LIMIT);
-
- value = readl(port->base + RP_PRIV_XP_DL);
- value |= RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD;
- writel(value, port->base + RP_PRIV_XP_DL);
-
- value = readl(port->base + RP_VEND_XP);
- value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
- value |= soc->update_fc_threshold;
- writel(value, port->base + RP_VEND_XP);
- }
-
if (soc->update_fc_timer) {
value = readl(port->base + RP_VEND_XP);
value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
@@ -2023,7 +1998,7 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
pcie->supplies[i++].supply = "hvdd-pex";
pcie->supplies[i++].supply = "vddio-pexctl-aud";
} else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
- pcie->num_supplies = 6;
+ pcie->num_supplies = 3;
pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
sizeof(*pcie->supplies),
@@ -2031,14 +2006,11 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
if (!pcie->supplies)
return -ENOMEM;
- pcie->supplies[i++].supply = "avdd-pll-uerefe";
pcie->supplies[i++].supply = "hvddio-pex";
pcie->supplies[i++].supply = "dvddio-pex";
- pcie->supplies[i++].supply = "dvdd-pex-pll";
- pcie->supplies[i++].supply = "hvdd-pex-pll-e";
pcie->supplies[i++].supply = "vddio-pex-ctl";
} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
- pcie->num_supplies = 7;
+ pcie->num_supplies = 4;
pcie->supplies = devm_kcalloc(dev, pcie->num_supplies,
sizeof(*pcie->supplies),
@@ -2048,11 +2020,8 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
pcie->supplies[i++].supply = "avddio-pex";
pcie->supplies[i++].supply = "dvddio-pex";
- pcie->supplies[i++].supply = "avdd-pex-pll";
pcie->supplies[i++].supply = "hvdd-pex";
- pcie->supplies[i++].supply = "hvdd-pex-pll-e";
pcie->supplies[i++].supply = "vddio-pex-ctl";
- pcie->supplies[i++].supply = "avdd-pll-erefe";
} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
bool need_pexa = false, need_pexb = false;
@@ -2414,7 +2383,6 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.program_uphy = true,
.update_clamp_threshold = false,
.program_deskew_time = false,
- .raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = true,
.ectl.enable = false,
@@ -2444,7 +2412,6 @@ static const struct tegra_pcie_soc tegra30_pcie = {
.program_uphy = true,
.update_clamp_threshold = false,
.program_deskew_time = false,
- .raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
@@ -2457,8 +2424,6 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x44ac44ac,
- /* FC threshold is bit[25:18] */
- .update_fc_threshold = 0x03fc0000,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
@@ -2468,7 +2433,6 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.program_uphy = true,
.update_clamp_threshold = true,
.program_deskew_time = false,
- .raw_violation_fixup = true,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
@@ -2492,7 +2456,6 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.program_uphy = true,
.update_clamp_threshold = true,
.program_deskew_time = true,
- .raw_violation_fixup = false,
.update_fc_timer = true,
.has_cache_bars = false,
.ectl = {
@@ -2534,7 +2497,6 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.program_uphy = false,
.update_clamp_threshold = false,
.program_deskew_time = false,
- .raw_violation_fixup = false,
.update_fc_timer = false,
.has_cache_bars = false,
.ectl.enable = false,
diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c
index f6f41db31d47..cdc0963f154e 100644
--- a/drivers/pci/controller/pcie-rcar-host.c
+++ b/drivers/pci/controller/pcie-rcar-host.c
@@ -915,7 +915,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
err = pm_runtime_get_sync(pcie->dev);
if (err < 0) {
dev_err(pcie->dev, "pm_runtime_get_sync failed\n");
- goto err_pm_disable;
+ goto err_pm_put;
}
err = rcar_pcie_get_resources(host);
@@ -986,8 +986,6 @@ err_unmap_msi_irqs:
err_pm_put:
pm_runtime_put(dev);
-
-err_pm_disable:
pm_runtime_disable(dev);
return err;
diff --git a/drivers/pci/controller/pcie-xilinx-cpm.c b/drivers/pci/controller/pcie-xilinx-cpm.c
new file mode 100644
index 000000000000..f3082de44e8a
--- /dev/null
+++ b/drivers/pci/controller/pcie-xilinx-cpm.c
@@ -0,0 +1,611 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCIe host controller driver for Xilinx Versal CPM DMA Bridge
+ *
+ * (C) Copyright 2019 - 2020, Xilinx, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pci-ecam.h>
+
+#include "../pci.h"
+
+/* Register definitions */
+#define XILINX_CPM_PCIE_REG_IDR 0x00000E10
+#define XILINX_CPM_PCIE_REG_IMR 0x00000E14
+#define XILINX_CPM_PCIE_REG_PSCR 0x00000E1C
+#define XILINX_CPM_PCIE_REG_RPSC 0x00000E20
+#define XILINX_CPM_PCIE_REG_RPEFR 0x00000E2C
+#define XILINX_CPM_PCIE_REG_IDRN 0x00000E38
+#define XILINX_CPM_PCIE_REG_IDRN_MASK 0x00000E3C
+#define XILINX_CPM_PCIE_MISC_IR_STATUS 0x00000340
+#define XILINX_CPM_PCIE_MISC_IR_ENABLE 0x00000348
+#define XILINX_CPM_PCIE_MISC_IR_LOCAL BIT(1)
+
+/* Interrupt registers definitions */
+#define XILINX_CPM_PCIE_INTR_LINK_DOWN 0
+#define XILINX_CPM_PCIE_INTR_HOT_RESET 3
+#define XILINX_CPM_PCIE_INTR_CFG_PCIE_TIMEOUT 4
+#define XILINX_CPM_PCIE_INTR_CFG_TIMEOUT 8
+#define XILINX_CPM_PCIE_INTR_CORRECTABLE 9
+#define XILINX_CPM_PCIE_INTR_NONFATAL 10
+#define XILINX_CPM_PCIE_INTR_FATAL 11
+#define XILINX_CPM_PCIE_INTR_CFG_ERR_POISON 12
+#define XILINX_CPM_PCIE_INTR_PME_TO_ACK_RCVD 15
+#define XILINX_CPM_PCIE_INTR_INTX 16
+#define XILINX_CPM_PCIE_INTR_PM_PME_RCVD 17
+#define XILINX_CPM_PCIE_INTR_SLV_UNSUPP 20
+#define XILINX_CPM_PCIE_INTR_SLV_UNEXP 21
+#define XILINX_CPM_PCIE_INTR_SLV_COMPL 22
+#define XILINX_CPM_PCIE_INTR_SLV_ERRP 23
+#define XILINX_CPM_PCIE_INTR_SLV_CMPABT 24
+#define XILINX_CPM_PCIE_INTR_SLV_ILLBUR 25
+#define XILINX_CPM_PCIE_INTR_MST_DECERR 26
+#define XILINX_CPM_PCIE_INTR_MST_SLVERR 27
+#define XILINX_CPM_PCIE_INTR_SLV_PCIE_TIMEOUT 28
+
+#define IMR(x) BIT(XILINX_CPM_PCIE_INTR_ ##x)
+
+#define XILINX_CPM_PCIE_IMR_ALL_MASK \
+ ( \
+ IMR(LINK_DOWN) | \
+ IMR(HOT_RESET) | \
+ IMR(CFG_PCIE_TIMEOUT) | \
+ IMR(CFG_TIMEOUT) | \
+ IMR(CORRECTABLE) | \
+ IMR(NONFATAL) | \
+ IMR(FATAL) | \
+ IMR(CFG_ERR_POISON) | \
+ IMR(PME_TO_ACK_RCVD) | \
+ IMR(INTX) | \
+ IMR(PM_PME_RCVD) | \
+ IMR(SLV_UNSUPP) | \
+ IMR(SLV_UNEXP) | \
+ IMR(SLV_COMPL) | \
+ IMR(SLV_ERRP) | \
+ IMR(SLV_CMPABT) | \
+ IMR(SLV_ILLBUR) | \
+ IMR(MST_DECERR) | \
+ IMR(MST_SLVERR) | \
+ IMR(SLV_PCIE_TIMEOUT) \
+ )
+
+#define XILINX_CPM_PCIE_IDR_ALL_MASK 0xFFFFFFFF
+#define XILINX_CPM_PCIE_IDRN_MASK GENMASK(19, 16)
+#define XILINX_CPM_PCIE_IDRN_SHIFT 16
+
+/* Root Port Error FIFO Read Register definitions */
+#define XILINX_CPM_PCIE_RPEFR_ERR_VALID BIT(18)
+#define XILINX_CPM_PCIE_RPEFR_REQ_ID GENMASK(15, 0)
+#define XILINX_CPM_PCIE_RPEFR_ALL_MASK 0xFFFFFFFF
+
+/* Root Port Status/control Register definitions */
+#define XILINX_CPM_PCIE_REG_RPSC_BEN BIT(0)
+
+/* Phy Status/Control Register definitions */
+#define XILINX_CPM_PCIE_REG_PSCR_LNKUP BIT(11)
+
+/**
+ * struct xilinx_cpm_pcie_port - PCIe port information
+ * @reg_base: Bridge Register Base
+ * @cpm_base: CPM System Level Control and Status Register(SLCR) Base
+ * @dev: Device pointer
+ * @intx_domain: Legacy IRQ domain pointer
+ * @cpm_domain: CPM IRQ domain pointer
+ * @cfg: Holds mappings of config space window
+ * @intx_irq: legacy interrupt number
+ * @irq: Error interrupt number
+ * @lock: lock protecting shared register access
+ */
+struct xilinx_cpm_pcie_port {
+ void __iomem *reg_base;
+ void __iomem *cpm_base;
+ struct device *dev;
+ struct irq_domain *intx_domain;
+ struct irq_domain *cpm_domain;
+ struct pci_config_window *cfg;
+ int intx_irq;
+ int irq;
+ raw_spinlock_t lock;
+};
+
+static u32 pcie_read(struct xilinx_cpm_pcie_port *port, u32 reg)
+{
+ return readl_relaxed(port->reg_base + reg);
+}
+
+static void pcie_write(struct xilinx_cpm_pcie_port *port,
+ u32 val, u32 reg)
+{
+ writel_relaxed(val, port->reg_base + reg);
+}
+
+static bool cpm_pcie_link_up(struct xilinx_cpm_pcie_port *port)
+{
+ return (pcie_read(port, XILINX_CPM_PCIE_REG_PSCR) &
+ XILINX_CPM_PCIE_REG_PSCR_LNKUP);
+}
+
+static void cpm_pcie_clear_err_interrupts(struct xilinx_cpm_pcie_port *port)
+{
+ unsigned long val = pcie_read(port, XILINX_CPM_PCIE_REG_RPEFR);
+
+ if (val & XILINX_CPM_PCIE_RPEFR_ERR_VALID) {
+ dev_dbg(port->dev, "Requester ID %lu\n",
+ val & XILINX_CPM_PCIE_RPEFR_REQ_ID);
+ pcie_write(port, XILINX_CPM_PCIE_RPEFR_ALL_MASK,
+ XILINX_CPM_PCIE_REG_RPEFR);
+ }
+}
+
+static void xilinx_cpm_mask_leg_irq(struct irq_data *data)
+{
+ struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(data);
+ unsigned long flags;
+ u32 mask;
+ u32 val;
+
+ mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT);
+ raw_spin_lock_irqsave(&port->lock, flags);
+ val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK);
+ pcie_write(port, (val & (~mask)), XILINX_CPM_PCIE_REG_IDRN_MASK);
+ raw_spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void xilinx_cpm_unmask_leg_irq(struct irq_data *data)
+{
+ struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(data);
+ unsigned long flags;
+ u32 mask;
+ u32 val;
+
+ mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT);
+ raw_spin_lock_irqsave(&port->lock, flags);
+ val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK);
+ pcie_write(port, (val | mask), XILINX_CPM_PCIE_REG_IDRN_MASK);
+ raw_spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static struct irq_chip xilinx_cpm_leg_irq_chip = {
+ .name = "INTx",
+ .irq_mask = xilinx_cpm_mask_leg_irq,
+ .irq_unmask = xilinx_cpm_unmask_leg_irq,
+};
+
+/**
+ * xilinx_cpm_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
+ * @domain: IRQ domain
+ * @irq: Virtual IRQ number
+ * @hwirq: HW interrupt number
+ *
+ * Return: Always returns 0.
+ */
+static int xilinx_cpm_pcie_intx_map(struct irq_domain *domain,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &xilinx_cpm_leg_irq_chip,
+ handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+ irq_set_status_flags(irq, IRQ_LEVEL);
+
+ return 0;
+}
+
+/* INTx IRQ Domain operations */
+static const struct irq_domain_ops intx_domain_ops = {
+ .map = xilinx_cpm_pcie_intx_map,
+};
+
+static void xilinx_cpm_pcie_intx_flow(struct irq_desc *desc)
+{
+ struct xilinx_cpm_pcie_port *port = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long val;
+ int i;
+
+ chained_irq_enter(chip, desc);
+
+ val = FIELD_GET(XILINX_CPM_PCIE_IDRN_MASK,
+ pcie_read(port, XILINX_CPM_PCIE_REG_IDRN));
+
+ for_each_set_bit(i, &val, PCI_NUM_INTX)
+ generic_handle_irq(irq_find_mapping(port->intx_domain, i));
+
+ chained_irq_exit(chip, desc);
+}
+
+static void xilinx_cpm_mask_event_irq(struct irq_data *d)
+{
+ struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(d);
+ u32 val;
+
+ raw_spin_lock(&port->lock);
+ val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
+ val &= ~BIT(d->hwirq);
+ pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR);
+ raw_spin_unlock(&port->lock);
+}
+
+static void xilinx_cpm_unmask_event_irq(struct irq_data *d)
+{
+ struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(d);
+ u32 val;
+
+ raw_spin_lock(&port->lock);
+ val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
+ val |= BIT(d->hwirq);
+ pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR);
+ raw_spin_unlock(&port->lock);
+}
+
+static struct irq_chip xilinx_cpm_event_irq_chip = {
+ .name = "RC-Event",
+ .irq_mask = xilinx_cpm_mask_event_irq,
+ .irq_unmask = xilinx_cpm_unmask_event_irq,
+};
+
+static int xilinx_cpm_pcie_event_map(struct irq_domain *domain,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &xilinx_cpm_event_irq_chip,
+ handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+ irq_set_status_flags(irq, IRQ_LEVEL);
+ return 0;
+}
+
+static const struct irq_domain_ops event_domain_ops = {
+ .map = xilinx_cpm_pcie_event_map,
+};
+
+static void xilinx_cpm_pcie_event_flow(struct irq_desc *desc)
+{
+ struct xilinx_cpm_pcie_port *port = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long val;
+ int i;
+
+ chained_irq_enter(chip, desc);
+ val = pcie_read(port, XILINX_CPM_PCIE_REG_IDR);
+ val &= pcie_read(port, XILINX_CPM_PCIE_REG_IMR);
+ for_each_set_bit(i, &val, 32)
+ generic_handle_irq(irq_find_mapping(port->cpm_domain, i));
+ pcie_write(port, val, XILINX_CPM_PCIE_REG_IDR);
+
+ /*
+ * XILINX_CPM_PCIE_MISC_IR_STATUS register is mapped to
+ * CPM SLCR block.
+ */
+ val = readl_relaxed(port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS);
+ if (val)
+ writel_relaxed(val,
+ port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS);
+
+ chained_irq_exit(chip, desc);
+}
+
+#define _IC(x, s) \
+ [XILINX_CPM_PCIE_INTR_ ## x] = { __stringify(x), s }
+
+static const struct {
+ const char *sym;
+ const char *str;
+} intr_cause[32] = {
+ _IC(LINK_DOWN, "Link Down"),
+ _IC(HOT_RESET, "Hot reset"),
+ _IC(CFG_TIMEOUT, "ECAM access timeout"),
+ _IC(CORRECTABLE, "Correctable error message"),
+ _IC(NONFATAL, "Non fatal error message"),
+ _IC(FATAL, "Fatal error message"),
+ _IC(SLV_UNSUPP, "Slave unsupported request"),
+ _IC(SLV_UNEXP, "Slave unexpected completion"),
+ _IC(SLV_COMPL, "Slave completion timeout"),
+ _IC(SLV_ERRP, "Slave Error Poison"),
+ _IC(SLV_CMPABT, "Slave Completer Abort"),
+ _IC(SLV_ILLBUR, "Slave Illegal Burst"),
+ _IC(MST_DECERR, "Master decode error"),
+ _IC(MST_SLVERR, "Master slave error"),
+ _IC(CFG_PCIE_TIMEOUT, "PCIe ECAM access timeout"),
+ _IC(CFG_ERR_POISON, "ECAM poisoned completion received"),
+ _IC(PME_TO_ACK_RCVD, "PME_TO_ACK message received"),
+ _IC(PM_PME_RCVD, "PM_PME message received"),
+ _IC(SLV_PCIE_TIMEOUT, "PCIe completion timeout received"),
+};
+
+static irqreturn_t xilinx_cpm_pcie_intr_handler(int irq, void *dev_id)
+{
+ struct xilinx_cpm_pcie_port *port = dev_id;
+ struct device *dev = port->dev;
+ struct irq_data *d;
+
+ d = irq_domain_get_irq_data(port->cpm_domain, irq);
+
+ switch (d->hwirq) {
+ case XILINX_CPM_PCIE_INTR_CORRECTABLE:
+ case XILINX_CPM_PCIE_INTR_NONFATAL:
+ case XILINX_CPM_PCIE_INTR_FATAL:
+ cpm_pcie_clear_err_interrupts(port);
+ fallthrough;
+
+ default:
+ if (intr_cause[d->hwirq].str)
+ dev_warn(dev, "%s\n", intr_cause[d->hwirq].str);
+ else
+ dev_warn(dev, "Unknown IRQ %ld\n", d->hwirq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void xilinx_cpm_free_irq_domains(struct xilinx_cpm_pcie_port *port)
+{
+ if (port->intx_domain) {
+ irq_domain_remove(port->intx_domain);
+ port->intx_domain = NULL;
+ }
+
+ if (port->cpm_domain) {
+ irq_domain_remove(port->cpm_domain);
+ port->cpm_domain = NULL;
+ }
+}
+
+/**
+ * xilinx_cpm_pcie_init_irq_domain - Initialize IRQ domain
+ * @port: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie_port *port)
+{
+ struct device *dev = port->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *pcie_intc_node;
+
+ /* Setup INTx */
+ pcie_intc_node = of_get_next_child(node, NULL);
+ if (!pcie_intc_node) {
+ dev_err(dev, "No PCIe Intc node found\n");
+ return -EINVAL;
+ }
+
+ port->cpm_domain = irq_domain_add_linear(pcie_intc_node, 32,
+ &event_domain_ops,
+ port);
+ if (!port->cpm_domain)
+ goto out;
+
+ irq_domain_update_bus_token(port->cpm_domain, DOMAIN_BUS_NEXUS);
+
+ port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
+ &intx_domain_ops,
+ port);
+ if (!port->intx_domain)
+ goto out;
+
+ irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
+
+ of_node_put(pcie_intc_node);
+ raw_spin_lock_init(&port->lock);
+
+ return 0;
+out:
+ xilinx_cpm_free_irq_domains(port);
+ dev_err(dev, "Failed to allocate IRQ domains\n");
+
+ return -ENOMEM;
+}
+
+static int xilinx_cpm_setup_irq(struct xilinx_cpm_pcie_port *port)
+{
+ struct device *dev = port->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int i, irq;
+
+ port->irq = platform_get_irq(pdev, 0);
+ if (port->irq < 0)
+ return port->irq;
+
+ for (i = 0; i < ARRAY_SIZE(intr_cause); i++) {
+ int err;
+
+ if (!intr_cause[i].str)
+ continue;
+
+ irq = irq_create_mapping(port->cpm_domain, i);
+ if (!irq) {
+ dev_err(dev, "Failed to map interrupt\n");
+ return -ENXIO;
+ }
+
+ err = devm_request_irq(dev, irq, xilinx_cpm_pcie_intr_handler,
+ 0, intr_cause[i].sym, port);
+ if (err) {
+ dev_err(dev, "Failed to request IRQ %d\n", irq);
+ return err;
+ }
+ }
+
+ port->intx_irq = irq_create_mapping(port->cpm_domain,
+ XILINX_CPM_PCIE_INTR_INTX);
+ if (!port->intx_irq) {
+ dev_err(dev, "Failed to map INTx interrupt\n");
+ return -ENXIO;
+ }
+
+ /* Plug the INTx chained handler */
+ irq_set_chained_handler_and_data(port->intx_irq,
+ xilinx_cpm_pcie_intx_flow, port);
+
+ /* Plug the main event chained handler */
+ irq_set_chained_handler_and_data(port->irq,
+ xilinx_cpm_pcie_event_flow, port);
+
+ return 0;
+}
+
+/**
+ * xilinx_cpm_pcie_init_port - Initialize hardware
+ * @port: PCIe port information
+ */
+static void xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie_port *port)
+{
+ if (cpm_pcie_link_up(port))
+ dev_info(port->dev, "PCIe Link is UP\n");
+ else
+ dev_info(port->dev, "PCIe Link is DOWN\n");
+
+ /* Disable all interrupts */
+ pcie_write(port, ~XILINX_CPM_PCIE_IDR_ALL_MASK,
+ XILINX_CPM_PCIE_REG_IMR);
+
+ /* Clear pending interrupts */
+ pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_IDR) &
+ XILINX_CPM_PCIE_IMR_ALL_MASK,
+ XILINX_CPM_PCIE_REG_IDR);
+
+ /*
+ * XILINX_CPM_PCIE_MISC_IR_ENABLE register is mapped to
+ * CPM SLCR block.
+ */
+ writel(XILINX_CPM_PCIE_MISC_IR_LOCAL,
+ port->cpm_base + XILINX_CPM_PCIE_MISC_IR_ENABLE);
+ /* Enable the Bridge enable bit */
+ pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_RPSC) |
+ XILINX_CPM_PCIE_REG_RPSC_BEN,
+ XILINX_CPM_PCIE_REG_RPSC);
+}
+
+/**
+ * xilinx_cpm_pcie_parse_dt - Parse Device tree
+ * @port: PCIe port information
+ * @bus_range: Bus resource
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie_port *port,
+ struct resource *bus_range)
+{
+ struct device *dev = port->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+
+ port->cpm_base = devm_platform_ioremap_resource_byname(pdev,
+ "cpm_slcr");
+ if (IS_ERR(port->cpm_base))
+ return PTR_ERR(port->cpm_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ if (!res)
+ return -ENXIO;
+
+ port->cfg = pci_ecam_create(dev, res, bus_range,
+ &pci_generic_ecam_ops);
+ if (IS_ERR(port->cfg))
+ return PTR_ERR(port->cfg);
+
+ port->reg_base = port->cfg->win;
+
+ return 0;
+}
+
+static void xilinx_cpm_free_interrupts(struct xilinx_cpm_pcie_port *port)
+{
+ irq_set_chained_handler_and_data(port->intx_irq, NULL, NULL);
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+}
+
+/**
+ * xilinx_cpm_pcie_probe - Probe function
+ * @pdev: Platform device pointer
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_cpm_pcie_probe(struct platform_device *pdev)
+{
+ struct xilinx_cpm_pcie_port *port;
+ struct device *dev = &pdev->dev;
+ struct pci_host_bridge *bridge;
+ struct resource_entry *bus;
+ int err;
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
+ if (!bridge)
+ return -ENODEV;
+
+ port = pci_host_bridge_priv(bridge);
+
+ port->dev = dev;
+
+ err = xilinx_cpm_pcie_init_irq_domain(port);
+ if (err)
+ return err;
+
+ bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+ if (!bus)
+ return -ENODEV;
+
+ err = xilinx_cpm_pcie_parse_dt(port, bus->res);
+ if (err) {
+ dev_err(dev, "Parsing DT failed\n");
+ goto err_parse_dt;
+ }
+
+ xilinx_cpm_pcie_init_port(port);
+
+ err = xilinx_cpm_setup_irq(port);
+ if (err) {
+ dev_err(dev, "Failed to set up interrupts\n");
+ goto err_setup_irq;
+ }
+
+ bridge->dev.parent = dev;
+ bridge->sysdata = port->cfg;
+ bridge->busnr = port->cfg->busr.start;
+ bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ bridge->swizzle_irq = pci_common_swizzle;
+
+ err = pci_host_probe(bridge);
+ if (err < 0)
+ goto err_host_bridge;
+
+ return 0;
+
+err_host_bridge:
+ xilinx_cpm_free_interrupts(port);
+err_setup_irq:
+ pci_ecam_free(port->cfg);
+err_parse_dt:
+ xilinx_cpm_free_irq_domains(port);
+ return err;
+}
+
+static const struct of_device_id xilinx_cpm_pcie_of_match[] = {
+ { .compatible = "xlnx,versal-cpm-host-1.00", },
+ {}
+};
+
+static struct platform_driver xilinx_cpm_pcie_driver = {
+ .driver = {
+ .name = "xilinx-cpm-pcie",
+ .of_match_table = xilinx_cpm_pcie_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = xilinx_cpm_pcie_probe,
+};
+
+builtin_platform_driver(xilinx_cpm_pcie_driver);
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index e386d4eac407..76d8acbee7d5 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -40,13 +40,19 @@ enum vmd_features {
* membars, in order to allow proper address translation during
* resource assignment to enable guest virtualization
*/
- VMD_FEAT_HAS_MEMBAR_SHADOW = (1 << 0),
+ VMD_FEAT_HAS_MEMBAR_SHADOW = (1 << 0),
/*
* Device may provide root port configuration information which limits
* bus numbering
*/
- VMD_FEAT_HAS_BUS_RESTRICTIONS = (1 << 1),
+ VMD_FEAT_HAS_BUS_RESTRICTIONS = (1 << 1),
+
+ /*
+ * Device contains physical location shadow registers in
+ * vendor-specific capability space
+ */
+ VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2),
};
/*
@@ -454,6 +460,28 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
}
}
+ if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
+ int pos = pci_find_capability(vmd->dev, PCI_CAP_ID_VNDR);
+ u32 reg, regu;
+
+ pci_read_config_dword(vmd->dev, pos + 4, &reg);
+
+ /* "SHDW" */
+ if (pos && reg == 0x53484457) {
+ pci_read_config_dword(vmd->dev, pos + 8, &reg);
+ pci_read_config_dword(vmd->dev, pos + 12, &regu);
+ offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
+ (((u64) regu << 32 | reg) &
+ PCI_BASE_ADDRESS_MEM_MASK);
+
+ pci_read_config_dword(vmd->dev, pos + 16, &reg);
+ pci_read_config_dword(vmd->dev, pos + 20, &regu);
+ offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
+ (((u64) regu << 32 | reg) &
+ PCI_BASE_ADDRESS_MEM_MASK);
+ }
+ }
+
/*
* Certain VMD devices may have a root port configuration option which
* limits the bus range to between 0-127, 128-255, or 224-255
@@ -716,16 +744,20 @@ static int vmd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);
static const struct pci_device_id vmd_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
- .driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+ VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
- .driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+ VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
- .driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
+ VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{0,}
};
MODULE_DEVICE_TABLE(pci, vmd_ids);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index c5eb509c72f0..f979b7098acf 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -352,7 +352,7 @@ static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
* -ENODEV Not a valid drc_name
* -EIO Internal PCI Error
*/
-int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
+static int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
{
struct pci_bus *bus;
struct slot *slot;
@@ -458,7 +458,7 @@ static inline int is_dlpar_capable(void)
return (int) (rc != RTAS_UNKNOWN_SERVICE);
}
-int __init rpadlpar_io_init(void)
+static int __init rpadlpar_io_init(void)
{
if (!is_dlpar_capable()) {
@@ -470,7 +470,7 @@ int __init rpadlpar_io_init(void)
return dlpar_sysfs_init();
}
-void rpadlpar_io_exit(void)
+static void __exit rpadlpar_io_exit(void)
{
dlpar_sysfs_exit();
}
diff --git a/drivers/pci/irq.c b/drivers/pci/irq.c
index a1de501a2729..12ecd0aaa28d 100644
--- a/drivers/pci/irq.c
+++ b/drivers/pci/irq.c
@@ -6,61 +6,11 @@
* Copyright (C) 2017 Christoph Hellwig.
*/
-#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/pci.h>
-static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason)
-{
- struct pci_dev *parent = to_pci_dev(pdev->dev.parent);
-
- pci_err(pdev, "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n",
- dev_name(&parent->dev), parent->vendor, parent->device);
- pci_err(pdev, "%s\n", reason);
- pci_err(pdev, "Please report to linux-kernel@vger.kernel.org\n");
- WARN_ON(1);
-}
-
-/**
- * pci_lost_interrupt - reports a lost PCI interrupt
- * @pdev: device whose interrupt is lost
- *
- * The primary function of this routine is to report a lost interrupt
- * in a standard way which users can recognise (instead of blaming the
- * driver).
- *
- * Returns:
- * a suggestion for fixing it (although the driver is not required to
- * act on this).
- */
-enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *pdev)
-{
- if (pdev->msi_enabled || pdev->msix_enabled) {
- enum pci_lost_interrupt_reason ret;
-
- if (pdev->msix_enabled) {
- pci_note_irq_problem(pdev, "MSIX routing failure");
- ret = PCI_LOST_IRQ_DISABLE_MSIX;
- } else {
- pci_note_irq_problem(pdev, "MSI routing failure");
- ret = PCI_LOST_IRQ_DISABLE_MSI;
- }
- return ret;
- }
-#ifdef CONFIG_ACPI
- if (!(acpi_disabled || acpi_noirq)) {
- pci_note_irq_problem(pdev, "Potential ACPI misrouting please reboot with acpi=noirq");
- /* currently no way to fix acpi on the fly */
- return PCI_LOST_IRQ_DISABLE_ACPI;
- }
-#endif
- pci_note_irq_problem(pdev, "unknown cause (not MSI or ACPI)");
- return PCI_LOST_IRQ_NO_INFORMATION;
-}
-EXPORT_SYMBOL(pci_lost_interrupt);
-
/**
* pci_request_irq - allocate an interrupt line for a PCI device
* @dev: PCI device to operate on
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 6b43a5455c7a..cade9be68b09 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1191,8 +1191,7 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
struct irq_affinity *affd)
{
struct irq_affinity msi_default_affd = {0};
- int msix_vecs = -ENOSPC;
- int msi_vecs = -ENOSPC;
+ int nvecs = -ENOSPC;
if (flags & PCI_IRQ_AFFINITY) {
if (!affd)
@@ -1203,17 +1202,16 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
}
if (flags & PCI_IRQ_MSIX) {
- msix_vecs = __pci_enable_msix_range(dev, NULL, min_vecs,
- max_vecs, affd, flags);
- if (msix_vecs > 0)
- return msix_vecs;
+ nvecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
+ affd, flags);
+ if (nvecs > 0)
+ return nvecs;
}
if (flags & PCI_IRQ_MSI) {
- msi_vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs,
- affd);
- if (msi_vecs > 0)
- return msi_vecs;
+ nvecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd);
+ if (nvecs > 0)
+ return nvecs;
}
/* use legacy IRQ if allowed */
@@ -1231,9 +1229,7 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
}
}
- if (msix_vecs == -ENOSPC)
- return -ENOSPC;
- return msi_vecs;
+ return nvecs;
}
EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 8f478d923196..2ebc5e32e8a0 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -42,7 +42,7 @@ void pci_set_bus_of_node(struct pci_bus *bus)
} else {
node = of_node_get(bus->self->dev.of_node);
if (node && of_property_read_bool(node, "external-facing"))
- bus->self->untrusted = true;
+ bus->self->external_facing = true;
}
bus->dev.of_node = node;
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index e8e444eeb1cd..64ebed129dbf 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -253,7 +253,7 @@ static int pci_bridge_has_acs_redir(struct pci_dev *pdev)
int pos;
u16 ctrl;
- pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+ pos = pdev->acs_cap;
if (!pos)
return 0;
@@ -273,6 +273,19 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
seq_buf_printf(buf, "%s;", pci_name(pdev));
}
+static bool cpu_supports_p2pdma(void)
+{
+#ifdef CONFIG_X86
+ struct cpuinfo_x86 *c = &cpu_data(0);
+
+ /* Any AMD CPU whose family ID is Zen or newer supports p2pdma */
+ if (c->x86_vendor == X86_VENDOR_AMD && c->x86 >= 0x17)
+ return true;
+#endif
+
+ return false;
+}
+
static const struct pci_p2pdma_whitelist_entry {
unsigned short vendor;
unsigned short device;
@@ -280,11 +293,6 @@ static const struct pci_p2pdma_whitelist_entry {
REQ_SAME_HOST_BRIDGE = 1 << 0,
} flags;
} pci_p2pdma_whitelist[] = {
- /* AMD ZEN */
- {PCI_VENDOR_ID_AMD, 0x1450, 0},
- {PCI_VENDOR_ID_AMD, 0x15d0, 0},
- {PCI_VENDOR_ID_AMD, 0x1630, 0},
-
/* Intel Xeon E5/Core i7 */
{PCI_VENDOR_ID_INTEL, 0x3c00, REQ_SAME_HOST_BRIDGE},
{PCI_VENDOR_ID_INTEL, 0x3c01, REQ_SAME_HOST_BRIDGE},
@@ -473,7 +481,8 @@ upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
acs_redirects, acs_list);
if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
- if (!host_bridge_whitelist(provider, client))
+ if (!cpu_supports_p2pdma() &&
+ !host_bridge_whitelist(provider, client))
map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 7224b1e5f2a8..54520d34e27e 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1213,7 +1213,7 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
ACPI_FREE(obj);
}
-static void pci_acpi_set_untrusted(struct pci_dev *dev)
+static void pci_acpi_set_external_facing(struct pci_dev *dev)
{
u8 val;
@@ -1224,11 +1224,10 @@ static void pci_acpi_set_untrusted(struct pci_dev *dev)
/*
* These root ports expose PCIe (including DMA) outside of the
- * system so make sure we treat them and everything behind as
- * untrusted.
+ * system. Everything downstream from them is external.
*/
if (val)
- dev->untrusted = 1;
+ dev->external_facing = 1;
}
static void pci_acpi_setup(struct device *dev)
@@ -1240,7 +1239,7 @@ static void pci_acpi_setup(struct device *dev)
return;
pci_acpi_optimize_delay(pci_dev, adev->handle);
- pci_acpi_set_untrusted(pci_dev);
+ pci_acpi_set_external_facing(pci_dev);
pci_acpi_add_edr_notifier(pci_dev);
pci_acpi_add_pm_notifier(adev, pci_dev);
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 707dd9808676..781e45cf60d1 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -18,7 +18,7 @@
* the instance number and string from the type 41 record and exports
* it to sysfs.
*
- * Please see http://linux.dell.com/files/biosdevname/ for more
+ * Please see https://linux.dell.com/files/biosdevname/ for more
* information.
*/
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ce096272f52b..501035cc0409 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -777,6 +777,133 @@ int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
return 0;
}
+static int pci_acs_enable;
+
+/**
+ * pci_request_acs - ask for ACS to be enabled if supported
+ */
+void pci_request_acs(void)
+{
+ pci_acs_enable = 1;
+}
+
+static const char *disable_acs_redir_param;
+
+/**
+ * pci_disable_acs_redir - disable ACS redirect capabilities
+ * @dev: the PCI device
+ *
+ * For only devices specified in the disable_acs_redir parameter.
+ */
+static void pci_disable_acs_redir(struct pci_dev *dev)
+{
+ int ret = 0;
+ const char *p;
+ int pos;
+ u16 ctrl;
+
+ if (!disable_acs_redir_param)
+ return;
+
+ p = disable_acs_redir_param;
+ while (*p) {
+ ret = pci_dev_str_match(dev, p, &p);
+ if (ret < 0) {
+ pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
+ disable_acs_redir_param);
+
+ break;
+ } else if (ret == 1) {
+ /* Found a match */
+ break;
+ }
+
+ if (*p != ';' && *p != ',') {
+ /* End of param or invalid format */
+ break;
+ }
+ p++;
+ }
+
+ if (ret != 1)
+ return;
+
+ if (!pci_dev_specific_disable_acs_redir(dev))
+ return;
+
+ pos = dev->acs_cap;
+ if (!pos) {
+ pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
+ return;
+ }
+
+ pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+ /* P2P Request & Completion Redirect */
+ ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
+
+ pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+ pci_info(dev, "disabled ACS redirect\n");
+}
+
+/**
+ * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
+ * @dev: the PCI device
+ */
+static void pci_std_enable_acs(struct pci_dev *dev)
+{
+ int pos;
+ u16 cap;
+ u16 ctrl;
+
+ pos = dev->acs_cap;
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+ pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+ /* Source Validation */
+ ctrl |= (cap & PCI_ACS_SV);
+
+ /* P2P Request Redirect */
+ ctrl |= (cap & PCI_ACS_RR);
+
+ /* P2P Completion Redirect */
+ ctrl |= (cap & PCI_ACS_CR);
+
+ /* Upstream Forwarding */
+ ctrl |= (cap & PCI_ACS_UF);
+
+ pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+}
+
+/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+static void pci_enable_acs(struct pci_dev *dev)
+{
+ if (!pci_acs_enable)
+ goto disable_acs_redir;
+
+ if (!pci_dev_specific_enable_acs(dev))
+ goto disable_acs_redir;
+
+ pci_std_enable_acs(dev);
+
+disable_acs_redir:
+ /*
+ * Note: pci_disable_acs_redir() must be called even if ACS was not
+ * enabled by the kernel because it may have been enabled by
+ * platform firmware. So if we are told to disable it, we should
+ * always disable it after setting the kernel's default
+ * preferences.
+ */
+ pci_disable_acs_redir(dev);
+}
+
/**
* pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored
@@ -2046,6 +2173,14 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
}
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
+void pcie_clear_device_status(struct pci_dev *dev)
+{
+ u16 sta;
+
+ pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
+ pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
+}
+
/**
* pcie_clear_root_pme_status - Clear root port PME interrupt status.
* @dev: PCIe root port or event collector.
@@ -3230,139 +3365,12 @@ void pci_configure_ari(struct pci_dev *dev)
}
}
-static int pci_acs_enable;
-
-/**
- * pci_request_acs - ask for ACS to be enabled if supported
- */
-void pci_request_acs(void)
-{
- pci_acs_enable = 1;
-}
-
-static const char *disable_acs_redir_param;
-
-/**
- * pci_disable_acs_redir - disable ACS redirect capabilities
- * @dev: the PCI device
- *
- * For only devices specified in the disable_acs_redir parameter.
- */
-static void pci_disable_acs_redir(struct pci_dev *dev)
-{
- int ret = 0;
- const char *p;
- int pos;
- u16 ctrl;
-
- if (!disable_acs_redir_param)
- return;
-
- p = disable_acs_redir_param;
- while (*p) {
- ret = pci_dev_str_match(dev, p, &p);
- if (ret < 0) {
- pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
- disable_acs_redir_param);
-
- break;
- } else if (ret == 1) {
- /* Found a match */
- break;
- }
-
- if (*p != ';' && *p != ',') {
- /* End of param or invalid format */
- break;
- }
- p++;
- }
-
- if (ret != 1)
- return;
-
- if (!pci_dev_specific_disable_acs_redir(dev))
- return;
-
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
- if (!pos) {
- pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
- return;
- }
-
- pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
-
- /* P2P Request & Completion Redirect */
- ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
-
- pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
-
- pci_info(dev, "disabled ACS redirect\n");
-}
-
-/**
- * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
- * @dev: the PCI device
- */
-static void pci_std_enable_acs(struct pci_dev *dev)
-{
- int pos;
- u16 cap;
- u16 ctrl;
-
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
- if (!pos)
- return;
-
- pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
- pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
-
- /* Source Validation */
- ctrl |= (cap & PCI_ACS_SV);
-
- /* P2P Request Redirect */
- ctrl |= (cap & PCI_ACS_RR);
-
- /* P2P Completion Redirect */
- ctrl |= (cap & PCI_ACS_CR);
-
- /* Upstream Forwarding */
- ctrl |= (cap & PCI_ACS_UF);
-
- pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
-}
-
-/**
- * pci_enable_acs - enable ACS if hardware support it
- * @dev: the PCI device
- */
-void pci_enable_acs(struct pci_dev *dev)
-{
- if (!pci_acs_enable)
- goto disable_acs_redir;
-
- if (!pci_dev_specific_enable_acs(dev))
- goto disable_acs_redir;
-
- pci_std_enable_acs(dev);
-
-disable_acs_redir:
- /*
- * Note: pci_disable_acs_redir() must be called even if ACS was not
- * enabled by the kernel because it may have been enabled by
- * platform firmware. So if we are told to disable it, we should
- * always disable it after setting the kernel's default
- * preferences.
- */
- pci_disable_acs_redir(dev);
-}
-
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
{
int pos;
u16 cap, ctrl;
- pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+ pos = pdev->acs_cap;
if (!pos)
return false;
@@ -3488,6 +3496,18 @@ bool pci_acs_path_enabled(struct pci_dev *start,
}
/**
+ * pci_acs_init - Initialize ACS if hardware supports it
+ * @dev: the PCI device
+ */
+void pci_acs_init(struct pci_dev *dev)
+{
+ dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+
+ if (dev->acs_cap)
+ pci_enable_acs(dev);
+}
+
+/**
* pci_rebar_find_pos - find position of resize ctrl reg for BAR
* @pdev: PCI device
* @bar: BAR to find
@@ -5688,6 +5708,7 @@ EXPORT_SYMBOL(pcie_get_readrq);
int pcie_set_readrq(struct pci_dev *dev, int rq)
{
u16 v;
+ int ret;
if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
return -EINVAL;
@@ -5706,8 +5727,10 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
v = (ffs(rq) - 8) << 12;
- return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+ ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v);
+
+ return pcibios_err_to_errno(ret);
}
EXPORT_SYMBOL(pcie_set_readrq);
@@ -5738,6 +5761,7 @@ EXPORT_SYMBOL(pcie_get_mps);
int pcie_set_mps(struct pci_dev *dev, int mps)
{
u16 v;
+ int ret;
if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
return -EINVAL;
@@ -5747,8 +5771,10 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
return -EINVAL;
v <<= 5;
- return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+ ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_PAYLOAD, v);
+
+ return pcibios_err_to_errno(ret);
}
EXPORT_SYMBOL(pcie_set_mps);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 56d67071e116..fa12f7cbc1a0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -92,6 +92,7 @@ void pci_refresh_power_state(struct pci_dev *dev);
int pci_power_up(struct pci_dev *dev);
void pci_disable_enabled_device(struct pci_dev *dev);
int pci_finish_runtime_suspend(struct pci_dev *dev);
+void pcie_clear_device_status(struct pci_dev *dev);
void pcie_clear_root_pme_status(struct pci_dev *dev);
bool pci_check_pme_status(struct pci_dev *dev);
void pci_pme_wakeup_bus(struct pci_bus *bus);
@@ -532,7 +533,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
return resource_alignment(res);
}
-void pci_enable_acs(struct pci_dev *dev);
+void pci_acs_init(struct pci_dev *dev);
#ifdef CONFIG_PCI_QUIRKS
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
int pci_dev_specific_enable_acs(struct pci_dev *dev);
@@ -555,7 +556,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
/* PCI error reporting and recovery */
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
- enum pci_channel_state state,
+ pci_channel_state_t state,
pci_ers_result_t (*reset_link)(struct pci_dev *pdev));
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
@@ -666,7 +667,6 @@ void pci_aer_init(struct pci_dev *dev);
void pci_aer_exit(struct pci_dev *dev);
extern const struct attribute_group aer_stats_attr_group;
void pci_aer_clear_fatal_status(struct pci_dev *dev);
-void pci_aer_clear_device_status(struct pci_dev *dev);
int pci_aer_clear_status(struct pci_dev *dev);
int pci_aer_raw_clear_status(struct pci_dev *dev);
#else
@@ -674,7 +674,6 @@ static inline void pci_no_aer(void) { }
static inline void pci_aer_init(struct pci_dev *d) { }
static inline void pci_aer_exit(struct pci_dev *d) { }
static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
-static inline void pci_aer_clear_device_status(struct pci_dev *dev) { }
static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
#endif
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 9cd31331aee9..3946555a6042 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -43,7 +43,7 @@ config PCIEAER_INJECT
error injection can fake almost all kinds of errors with the
help of a user space helper tool aer-inject, which can be
gotten from:
- http://www.kernel.org/pub/linux/utils/pci/aer-inject/
+ https://www.kernel.org/pub/linux/utils/pci/aer-inject/
#
# PCI Express ECRC
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 3acf56683915..87283cda3990 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -224,31 +224,28 @@ int pcie_aer_is_native(struct pci_dev *dev)
int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
+ int rc;
+
if (!pcie_aer_is_native(dev))
return -EIO;
- return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
+ rc = pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
+ return pcibios_err_to_errno(rc);
}
EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
int pci_disable_pcie_error_reporting(struct pci_dev *dev)
{
+ int rc;
+
if (!pcie_aer_is_native(dev))
return -EIO;
- return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
- PCI_EXP_AER_FLAGS);
+ rc = pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
+ return pcibios_err_to_errno(rc);
}
EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
-void pci_aer_clear_device_status(struct pci_dev *dev)
-{
- u16 sta;
-
- pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
- pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
-}
-
int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
{
int aer = dev->aer_cap;
@@ -447,7 +444,7 @@ static const char *aer_error_layer[] = {
"Transaction Layer"
};
-static const char *aer_correctable_error_string[AER_MAX_TYPEOF_COR_ERRS] = {
+static const char *aer_correctable_error_string[] = {
"RxErr", /* Bit Position 0 */
NULL,
NULL,
@@ -464,9 +461,25 @@ static const char *aer_correctable_error_string[AER_MAX_TYPEOF_COR_ERRS] = {
"NonFatalErr", /* Bit Position 13 */
"CorrIntErr", /* Bit Position 14 */
"HeaderOF", /* Bit Position 15 */
+ NULL, /* Bit Position 16 */
+ NULL, /* Bit Position 17 */
+ NULL, /* Bit Position 18 */
+ NULL, /* Bit Position 19 */
+ NULL, /* Bit Position 20 */
+ NULL, /* Bit Position 21 */
+ NULL, /* Bit Position 22 */
+ NULL, /* Bit Position 23 */
+ NULL, /* Bit Position 24 */
+ NULL, /* Bit Position 25 */
+ NULL, /* Bit Position 26 */
+ NULL, /* Bit Position 27 */
+ NULL, /* Bit Position 28 */
+ NULL, /* Bit Position 29 */
+ NULL, /* Bit Position 30 */
+ NULL, /* Bit Position 31 */
};
-static const char *aer_uncorrectable_error_string[AER_MAX_TYPEOF_UNCOR_ERRS] = {
+static const char *aer_uncorrectable_error_string[] = {
"Undefined", /* Bit Position 0 */
NULL,
NULL,
@@ -494,6 +507,11 @@ static const char *aer_uncorrectable_error_string[AER_MAX_TYPEOF_UNCOR_ERRS] = {
"AtomicOpBlocked", /* Bit Position 24 */
"TLPBlockedErr", /* Bit Position 25 */
"PoisonTLPBlocked", /* Bit Position 26 */
+ NULL, /* Bit Position 27 */
+ NULL, /* Bit Position 28 */
+ NULL, /* Bit Position 29 */
+ NULL, /* Bit Position 30 */
+ NULL, /* Bit Position 31 */
};
static const char *aer_agent_string[] = {
@@ -650,24 +668,26 @@ static void __print_tlp_header(struct pci_dev *dev,
static void __aer_print_error(struct pci_dev *dev,
struct aer_err_info *info)
{
+ const char **strings;
unsigned long status = info->status & ~info->mask;
- const char *errmsg = NULL;
+ const char *level, *errmsg;
int i;
+ if (info->severity == AER_CORRECTABLE) {
+ strings = aer_correctable_error_string;
+ level = KERN_WARNING;
+ } else {
+ strings = aer_uncorrectable_error_string;
+ level = KERN_ERR;
+ }
+
for_each_set_bit(i, &status, 32) {
- if (info->severity == AER_CORRECTABLE)
- errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ?
- aer_correctable_error_string[i] : NULL;
- else
- errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ?
- aer_uncorrectable_error_string[i] : NULL;
+ errmsg = strings[i];
+ if (!errmsg)
+ errmsg = "Unknown Error Bit";
- if (errmsg)
- pci_err(dev, " [%2d] %-22s%s\n", i, errmsg,
+ pci_printk(level, dev, " [%2d] %-22s%s\n", i, errmsg,
info->first_error == i ? " (First)" : "");
- else
- pci_err(dev, " [%2d] Unknown Error Bit%s\n",
- i, info->first_error == i ? " (First)" : "");
}
pci_dev_aer_stats_incr(dev, info);
}
@@ -676,6 +696,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
{
int layer, agent;
int id = ((dev->bus->number << 8) | dev->devfn);
+ const char *level;
if (!info->status) {
pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
@@ -686,13 +707,14 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
layer = AER_GET_LAYER_ERROR(info->severity, info->status);
agent = AER_GET_AGENT(info->severity, info->status);
- pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
- aer_error_severity_string[info->severity],
- aer_error_layer[layer], aer_agent_string[agent]);
+ level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
+
+ pci_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
+ aer_error_severity_string[info->severity],
+ aer_error_layer[layer], aer_agent_string[agent]);
- pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
- dev->vendor, dev->device,
- info->status, info->mask);
+ pci_printk(level, dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
+ dev->vendor, dev->device, info->status, info->mask);
__aer_print_error(dev, info);
@@ -922,7 +944,8 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
if (aer)
pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS,
info->status);
- pci_aer_clear_device_status(dev);
+ if (pcie_aer_is_native(dev))
+ pcie_clear_device_status(dev);
} else if (info->severity == AER_NONFATAL)
pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);
else if (info->severity == AER_FATAL)
diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c
index 21cc3d3387f7..c2cbf425afc5 100644
--- a/drivers/pci/pcie/aer_inject.c
+++ b/drivers/pci/pcie/aer_inject.c
@@ -6,7 +6,7 @@
* trigger various real hardware errors. Software based error
* injection can fake almost all kinds of errors with the help of a
* user space helper tool aer-inject, which can be gotten from:
- * http://www.kernel.org/pub/linux/utils/pci/aer-inject/
+ * https://www.kernel.org/pub/linux/utils/pci/aer-inject/
*
* Copyright 2009 Intel Corporation.
* Huang Ying <ying.huang@intel.com>
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index b17e5ffd31b1..253c30cc1967 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1182,6 +1182,7 @@ static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp)
cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
else
cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
+ cnt += sprintf(buffer + cnt, "\n");
return cnt;
}
diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c
index 14bb8f54723e..c543f419d8f9 100644
--- a/drivers/pci/pcie/err.c
+++ b/drivers/pci/pcie/err.c
@@ -46,7 +46,7 @@ static pci_ers_result_t merge_result(enum pci_ers_result orig,
}
static int report_error_detected(struct pci_dev *dev,
- enum pci_channel_state state,
+ pci_channel_state_t state,
enum pci_ers_result *result)
{
pci_ers_result_t vote;
@@ -147,7 +147,7 @@ out:
}
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
- enum pci_channel_state state,
+ pci_channel_state_t state,
pci_ers_result_t (*reset_link)(struct pci_dev *pdev))
{
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
@@ -197,7 +197,8 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pci_dbg(dev, "broadcast resume message\n");
pci_walk_bus(bus, report_resume, &status);
- pci_aer_clear_device_status(dev);
+ if (pcie_aer_is_native(dev))
+ pcie_clear_device_status(dev);
pci_aer_clear_nonfatal_status(dev);
pci_info(dev, "device recovery successful\n");
return status;
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 3acf151ae015..3a3ce40ae1ab 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -146,7 +146,7 @@ static void pcie_portdrv_remove(struct pci_dev *dev)
}
static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
- enum pci_channel_state error)
+ pci_channel_state_t error)
{
/* Root Port has no impact. Always recovers. */
return PCI_ERS_RESULT_CAN_RECOVER;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 998f615cdb6d..03d37128a24f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1558,7 +1558,7 @@ static void set_pcie_untrusted(struct pci_dev *dev)
* untrusted as well.
*/
parent = pci_upstream_bridge(dev);
- if (parent && parent->untrusted)
+ if (parent && (parent->untrusted || parent->external_facing))
dev->untrusted = true;
}
@@ -1808,9 +1808,6 @@ int pci_setup_device(struct pci_dev *dev)
dev->revision = class & 0xff;
dev->class = class >> 8; /* upper 3 bytes */
- pci_info(dev, "[%04x:%04x] type %02x class %#08x\n",
- dev->vendor, dev->device, dev->hdr_type, dev->class);
-
if (pci_early_dump)
early_dump_pci_device(dev);
@@ -1828,6 +1825,9 @@ int pci_setup_device(struct pci_dev *dev)
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
+ pci_info(dev, "[%04x:%04x] type %02x class %#08x\n",
+ dev->vendor, dev->device, dev->hdr_type, dev->class);
+
/* Device class may be changed after fixup */
class = dev->class >> 8;
@@ -2396,7 +2396,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_ats_init(dev); /* Address Translation Services */
pci_pri_init(dev); /* Page Request Interface */
pci_pasid_init(dev); /* Process Address Space ID */
- pci_enable_acs(dev); /* Enable ACS P2P upstream forwarding */
+ pci_acs_init(dev); /* Access Control Services */
pci_ptm_init(dev); /* Precision Time Measurement */
pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 812bfc32ecb8..a81315eeb092 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3549,7 +3549,7 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
* The device will throw a Link Down error on AER-capable systems and
* regardless of AER, config space of the device is never accessible again
* and typically causes the system to hang or reset when access is attempted.
- * http://www.spinics.net/lists/linux-pci/msg34797.html
+ * https://lore.kernel.org/r/20140923210318.498dacbd@dualc.maya.org/
*/
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
@@ -4378,9 +4378,9 @@ static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena)
* redirect (CR) since all transactions are redirected to the upstream
* root complex.
*
- * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94086
- * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94102
- * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/99402
+ * https://lore.kernel.org/r/201207111426.q6BEQTbh002928@mail.maya.org/
+ * https://lore.kernel.org/r/20120711165854.GM25282@amd.com/
+ * https://lore.kernel.org/r/20121005130857.GX4009@amd.com/
*
* 1002:4385 SBx00 SMBus Controller
* 1002:439c SB7x0/SB8x0/SB9x0 IDE Controller
@@ -4409,6 +4409,8 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
if (ACPI_FAILURE(status))
return -ENODEV;
+ acpi_put_table(header);
+
/* Filter out flags not applicable to multifunction */
acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
@@ -4620,11 +4622,11 @@ static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags)
*
* 0x9d10-0x9d1b PCI Express Root port #{1-12}
*
- * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html
- * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html
- * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html
- * [4] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-spec-update.html
- * [5] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-datasheet-vol-1.html
+ * [1] https://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html
+ * [2] https://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html
+ * [3] https://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html
+ * [4] https://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-spec-update.html
+ * [5] https://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-datasheet-vol-1.html
* [6] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-spec-update.html
* [7] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-datasheet-vol-1.html
*/
@@ -4653,7 +4655,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)
if (!pci_quirk_intel_spt_pch_acs_match(dev))
return -ENOTTY;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ pos = dev->acs_cap;
if (!pos)
return -ENOTTY;
@@ -4961,7 +4963,7 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
if (!pci_quirk_intel_spt_pch_acs_match(dev))
return -ENOTTY;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ pos = dev->acs_cap;
if (!pos)
return -ENOTTY;
@@ -4988,7 +4990,7 @@ static int pci_quirk_disable_intel_spt_pch_acs_redir(struct pci_dev *dev)
if (!pci_quirk_intel_spt_pch_acs_match(dev))
return -ENOTTY;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ pos = dev->acs_cap;
if (!pos)
return -ENOTTY;
@@ -5192,7 +5194,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags);
*/
static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
{
- if (pdev->device == 0x7340 && pdev->revision != 0xc5)
+ if ((pdev->device == 0x7312 && pdev->revision != 0x00) ||
+ (pdev->device == 0x7340 && pdev->revision != 0xc5))
return;
pci_info(pdev, "disabling ATS\n");
@@ -5203,6 +5206,8 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_amd_harvest_no_ats);
/* AMD Iceland dGPU */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
+/* AMD Navi10 dGPU */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
/* AMD Navi14 dGPU */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
#endif /* CONFIG_PCI_ATS */
@@ -5355,7 +5360,7 @@ int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
bool found;
struct pci_dev *bridge = bus->self;
- pos = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ACS);
+ pos = bridge->acs_cap;
/* Disable ACS SV before initial config reads */
if (pos) {
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 9b94b1f16d80..4d870ed89385 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -152,7 +152,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
- panic("pdev_sort_resources(): kmalloc() failed!\n");
+ panic("%s: kzalloc() failed!\n", __func__);
tmp->res = r;
tmp->dev = dev;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index d21fa04fa44d..43eda101fcf4 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -73,7 +73,8 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno)
/*
* Apparently some Matrox devices have ROM BARs that read
* as zero when disabled, so don't update ROM BARs unless
- * they're enabled. See https://lkml.org/lkml/2005/8/30/138.
+ * they're enabled. See
+ * https://lore.kernel.org/r/43147B3D.1030309@vc.cvut.cz/
*/
if (!(res->flags & IORESOURCE_ROM_ENABLE))
return;
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index cc386ef2fa12..3861505741e6 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -268,13 +268,16 @@ placeholder:
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
+ kfree(slot);
goto err;
}
err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
"%s", slot_name);
- if (err)
+ if (err) {
+ kobject_put(&slot->kobj);
goto err;
+ }
INIT_LIST_HEAD(&slot->list);
list_add(&slot->list, &parent->slots);
@@ -293,7 +296,6 @@ out:
mutex_unlock(&pci_slot_mutex);
return slot;
err:
- kfree(slot);
slot = ERR_PTR(err);
goto out;
}
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 850cfeb74608..ba52459928f7 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -940,7 +940,7 @@ static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev,
size_t off;
if (event_id < 0 || event_id >= SWITCHTEC_IOCTL_MAX_EVENTS)
- return ERR_PTR(-EINVAL);
+ return (u32 __iomem *)ERR_PTR(-EINVAL);
off = event_regs[event_id].offset;
@@ -948,10 +948,10 @@ static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev,
if (index == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)
index = stdev->partition;
else if (index < 0 || index >= stdev->partition_count)
- return ERR_PTR(-EINVAL);
+ return (u32 __iomem *)ERR_PTR(-EINVAL);
} else if (event_regs[event_id].map_reg == pff_ev_reg) {
if (index < 0 || index >= stdev->pff_csr_count)
- return ERR_PTR(-EINVAL);
+ return (u32 __iomem *)ERR_PTR(-EINVAL);
}
return event_regs[event_id].map_reg(stdev, off, index);
@@ -1057,11 +1057,11 @@ static int ioctl_event_ctl(struct switchtec_dev *stdev,
}
static int ioctl_pff_to_port(struct switchtec_dev *stdev,
- struct switchtec_ioctl_pff_port *up)
+ struct switchtec_ioctl_pff_port __user *up)
{
int i, part;
u32 reg;
- struct part_cfg_regs *pcfg;
+ struct part_cfg_regs __iomem *pcfg;
struct switchtec_ioctl_pff_port p;
if (copy_from_user(&p, up, sizeof(p)))
@@ -1104,10 +1104,10 @@ static int ioctl_pff_to_port(struct switchtec_dev *stdev,
}
static int ioctl_port_to_pff(struct switchtec_dev *stdev,
- struct switchtec_ioctl_pff_port *up)
+ struct switchtec_ioctl_pff_port __user *up)
{
struct switchtec_ioctl_pff_port p;
- struct part_cfg_regs *pcfg;
+ struct part_cfg_regs __iomem *pcfg;
if (copy_from_user(&p, up, sizeof(p)))
return -EFAULT;
@@ -1484,7 +1484,7 @@ static void init_pff(struct switchtec_dev *stdev)
{
int i;
u32 reg;
- struct part_cfg_regs *pcfg = stdev->mmio_part_cfg;
+ struct part_cfg_regs __iomem *pcfg = stdev->mmio_part_cfg;
for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index a308e86a97f1..37f65602b0ec 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -2002,7 +2002,7 @@ static void aac_remove_one(struct pci_dev *pdev)
}
static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev,
- enum pci_channel_state error)
+ pci_channel_state_t error)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct aac_dev *aac = shost_priv(shost);
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index cd157f11eb22..bd38c8cea56e 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -7423,8 +7423,12 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info)
static inline int pqi_set_pcie_completion_timeout(struct pci_dev *pci_dev,
u16 timeout)
{
- return pcie_capability_clear_and_set_word(pci_dev, PCI_EXP_DEVCTL2,
+ int rc;
+
+ rc = pcie_capability_clear_and_set_word(pci_dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_COMP_TIMEOUT, timeout);
+
+ return pcibios_err_to_errno(rc);
}
static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 2ca018ce796f..f455243bdb9b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1743,7 +1743,7 @@ static void sym2_remove(struct pci_dev *pdev)
* @state: current state of the PCI slot
*/
static pci_ers_result_t sym2_io_error_detected(struct pci_dev *pdev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
/* If slot is permanently frozen, turn everything off */
if (state == pci_channel_io_perm_failure) {
diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c
index 402edaeffe12..ac30aefe49a1 100644
--- a/drivers/staging/qlge/qlge_main.c
+++ b/drivers/staging/qlge/qlge_main.c
@@ -4678,7 +4678,7 @@ static void ql_eeh_close(struct net_device *ndev)
* a PCI bus error is detected.
*/
static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
- enum pci_channel_state state)
+ pci_channel_state_t state)
{
struct net_device *ndev = pci_get_drvdata(pdev);
struct ql_adapter *qdev = netdev_priv(ndev);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 82d91547d122..7339a00c895e 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -34,6 +34,7 @@
#define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a))
#define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask))
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+#define PTR_ALIGN_DOWN(p, a) ((typeof(p))ALIGN_DOWN((unsigned long)(p), (a)))
#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
/* generic data direction definitions */
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index f75c307f346d..df54cd5b15db 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -28,6 +28,10 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
void pci_disable_pri(struct pci_dev *pdev);
int pci_reset_pri(struct pci_dev *pdev);
int pci_prg_resp_pasid_required(struct pci_dev *pdev);
+bool pci_pri_supported(struct pci_dev *pdev);
+#else
+static inline bool pci_pri_supported(struct pci_dev *pdev)
+{ return false; }
#endif /* CONFIG_PCI_PRI */
#ifdef CONFIG_PCI_PASID
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2830799208fd..ee49469bd2b5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -179,7 +179,7 @@ static inline const char *pci_power_name(pci_power_t state)
*/
typedef unsigned int __bitwise pci_channel_state_t;
-enum pci_channel_state {
+enum {
/* I/O channel is in normal state */
pci_channel_io_normal = (__force pci_channel_state_t) 1,
@@ -432,6 +432,12 @@ struct pci_dev {
* mappings to make sure they cannot access arbitrary memory.
*/
unsigned int untrusted:1;
+ /*
+ * Info from the platform, e.g., ACPI or device tree, may mark a
+ * device as "external-facing". An external-facing device is
+ * itself internal but devices downstream from it are external.
+ */
+ unsigned int external_facing:1;
unsigned int broken_intx_masking:1; /* INTx masking can't be used */
unsigned int io_window_1k:1; /* Intel bridge 1K I/O windows */
unsigned int irq_managed:1;
@@ -486,6 +492,7 @@ struct pci_dev {
#ifdef CONFIG_PCI_P2PDMA
struct pci_p2pdma *p2pdma;
#endif
+ u16 acs_cap; /* ACS Capability offset */
phys_addr_t rom; /* Physical address if not from BAR */
size_t romlen; /* Length if not from BAR */
char *driver_override; /* Driver name to force a match */
@@ -785,7 +792,7 @@ enum pci_ers_result {
struct pci_error_handlers {
/* PCI bus error detected on this device */
pci_ers_result_t (*error_detected)(struct pci_dev *dev,
- enum pci_channel_state error);
+ pci_channel_state_t error);
/* MMIO has been re-enabled, but not DMA */
pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
@@ -1053,13 +1060,6 @@ void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
-enum pci_lost_interrupt_reason {
- PCI_LOST_IRQ_NO_INFORMATION = 0,
- PCI_LOST_IRQ_DISABLE_MSI,
- PCI_LOST_IRQ_DISABLE_MSIX,
- PCI_LOST_IRQ_DISABLE_ACPI,
-};
-enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *dev);
int pci_find_capability(struct pci_dev *dev, int cap);
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability(struct pci_dev *dev, int cap);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 0ad57693f392..5c709a1450b1 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2585,6 +2585,8 @@
#define PCI_VENDOR_ID_ASMEDIA 0x1b21
+#define PCI_VENDOR_ID_REDHAT 0x1b36
+
#define PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS 0x1c36
#define PCI_VENDOR_ID_CIRCUITCO 0x1cc8
diff --git a/samples/vfio-mdev/mdpy-defs.h b/samples/vfio-mdev/mdpy-defs.h
index eb26421b6429..961c55ec3ffd 100644
--- a/samples/vfio-mdev/mdpy-defs.h
+++ b/samples/vfio-mdev/mdpy-defs.h
@@ -9,7 +9,7 @@
*/
/* pci ids */
-#define MDPY_PCI_VENDOR_ID 0x1b36 /* redhat */
+#define MDPY_PCI_VENDOR_ID PCI_VENDOR_ID_REDHAT
#define MDPY_PCI_DEVICE_ID 0x000f
#define MDPY_PCI_SUBVENDOR_ID PCI_SUBVENDOR_ID_REDHAT_QUMRANET
#define MDPY_PCI_SUBDEVICE_ID PCI_SUBDEVICE_ID_QEMU