pci-v5.9-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAl8sdUkUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vwH2Q/7Brcm1uyLORSzseGsaXSGMncBs2YB aKbfhyy4BPsDIZRLnzcfRZzgKo3f4jlLH9dJ6nBukbNXCvS/g7oYCXtNKVuB70MD IgBH3OJxLmqsYgDkoQmj1fZBCBhdqMgGbRmeIPLqiIBrWOJkBpGHXKpb0XtyXAas CpD0Tvr0JBeHMluZq6Uay09jBDKexeCFrT5HCoVaRMXT/C/iB5K1oMrUczzITsdi jB9xesDjh32rYtaePKfuL8itbRT7jtqOwQlk7sCtnMNamaOOaYO/s6hL5v/4GxMh rtWa1knOxxA1nOsnEkUEHi0Fj/+9zXDIdb7v6thRDo0ZgWQxl7l3nshvmPcxX421 tpCm3HqmvHzGqSI85Rtr3p4XKm9e+IjgE2EA/J6Y8Q6Grrb0EGJituhO4meL2Ciq 6mxdhu7InxDJ2p3TLGas3fB/1hrCO0Fc0pQoBJx7YgqA1ANyld9DYCkDN6IDoZBI uUjKgkE1dfbW/pGjotjhBsmz3dycZHkurIFdt1iX/Xtt5KKdPAzu9yM2U03iIS2R im1wZ/THiS/YCOlgL/J8+DHTY0ZvXjAdbiSPjTFfwb9XTh8aHVWtFaaZON1jRIjg xMpIY0SxfshpLx631ThZdDTDiOwE8D3B+1n/kMwps6HOLpxOoJZeSGTRCt9wGP40 j58DTtLm5FKpdYc= =moI9 -----END PGP SIGNATURE----- Merge tag 'pci-v5.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: "Enumeration: - Fix pci_cfg_wait queue locking problem (Bjorn Helgaas) - Convert PCIe capability PCIBIOS errors to errno (Bolarinwa Olayemi Saheed) - Align PCIe capability and PCI accessor return values (Bolarinwa Olayemi Saheed) - Fix pci_create_slot() reference count leak (Qiushi Wu) - Announce device after early fixups (Tiezhu Yang) PCI device hotplug: - Make rpadlpar functions static (Wei Yongjun) Driver binding: - Add device even if driver attach failed (Rajat Jain) Virtualization: - xen: Remove redundant initialization of irq (Colin Ian King) IOMMU: - Add pci_pri_supported() to check device or associated PF (Ashok Raj) - Release IVRS table in AMD ACS quirk (Hanjun Guo) - Mark AMD Navi10 GPU rev 0x00 ATS as broken (Kai-Heng Feng) - Treat "external-facing" devices themselves as internal (Rajat Jain) MSI: - Forward MSI-X error code in pci_alloc_irq_vectors_affinity() (Piotr Stankiewicz) Error handling: - Clear PCIe Device Status errors only if OS owns AER (Jonathan Cameron) - Log correctable errors as warning, not error (Matt Jolly) - Use 'pci_channel_state_t' instead of 'enum pci_channel_state' (Luc Van Oostenryck) Peer-to-peer DMA: - Allow P2PDMA on AMD Zen and newer CPUs (Logan Gunthorpe) ASPM: - Add missing newline in sysfs 'policy' (Xiongfeng Wang) Native PCIe controllers: - Convert to devm_platform_ioremap_resource_byname() (Dejin Zheng) - Convert to devm_platform_ioremap_resource() (Dejin Zheng) - Remove duplicate error message from devm_pci_remap_cfg_resource() callers (Dejin Zheng) - Fix runtime PM imbalance on error (Dinghao Liu) - Remove dev_err() when handing an error from platform_get_irq() (Krzysztof Wilczyński) - Use pci_host_bridge.windows list directly instead of splicing in a temporary list for cadence, mvebu, host-common (Rob Herring) - Use pci_host_probe() instead of open-coding all the pieces for altera, brcmstb, iproc, mobiveil, rcar, rockchip, tegra, v3, versatile, xgene, xilinx, xilinx-nwl (Rob Herring) - Default host bridge parent device to the platform device (Rob Herring) - Use pci_is_root_bus() instead of tracking root bus number separately in aardvark, designware (imx6, keystone, designware-host), mobiveil, xilinx-nwl, xilinx, rockchip, rcar (Rob Herring) - Set host bridge bus number in pci_scan_root_bus_bridge() instead of each driver for aardvark, designware-host, host-common, mediatek, rcar, tegra, v3-semi (Rob Herring) - Move DT resource setup into devm_pci_alloc_host_bridge() (Rob Herring) - Set bridge map_irq and swizzle_irq to default functions; drivers that don't support legacy IRQs (iproc) need to undo this (Rob Herring) ARM Versatile PCIe controller driver: - Drop flag PCI_ENABLE_PROC_DOMAINS (Rob Herring) Cadence PCIe controller driver: - Use "dma-ranges" instead of "cdns,no-bar-match-nbits" property (Kishon Vijay Abraham I) - Remove "mem" from reg binding (Kishon Vijay Abraham I) - Fix cdns_pcie_{host|ep}_setup() error path (Kishon Vijay Abraham I) - Convert all r/w accessors to perform only 32-bit accesses (Kishon Vijay Abraham I) - Add support to start link and verify link status (Kishon Vijay Abraham I) - Allow pci_host_bridge to have custom pci_ops (Kishon Vijay Abraham I) - Add new *ops* for CPU addr fixup (Kishon Vijay Abraham I) - Fix updating Vendor ID and Subsystem Vendor ID register (Kishon Vijay Abraham I) - Use bridge resources for outbound window setup (Rob Herring) - Remove private bus number and range storage (Rob Herring) Cadence PCIe endpoint driver: - Add MSI-X support (Alan Douglas) HiSilicon PCIe controller driver: - Remove non-ECAM HiSilicon hip05/hip06 driver (Rob Herring) Intel VMD host bridge driver: - Use Shadow MEMBAR registers for QEMU/KVM guests (Jon Derrick) Loongson PCIe controller driver: - Use DECLARE_PCI_FIXUP_EARLY for bridge_class_quirk() (Tiezhu Yang) Marvell Aardvark PCIe controller driver: - Indicate error in 'val' when config read fails (Pali Rohár) - Don't touch PCIe registers if no card connected (Pali Rohár) Marvell MVEBU PCIe controller driver: - Setup BAR0 in order to fix MSI (Shmuel Hazan) Microsoft Hyper-V host bridge driver: - Fix a timing issue which causes kdump to fail occasionally (Wei Hu) - Make some functions static (Wei Yongjun) NVIDIA Tegra PCIe controller driver: - Revert tegra124 raw_violation_fixup (Nicolas Chauvet) - Remove PLL power supplies (Thierry Reding) Qualcomm PCIe controller driver: - Change duplicate PCI reset to phy reset (Abhishek Sahu) - Add missing ipq806x clocks in PCIe driver (Ansuel Smith) - Add missing reset for ipq806x (Ansuel Smith) - Add ext reset (Ansuel Smith) - Use bulk clk API and assert on error (Ansuel Smith) - Add support for tx term offset for rev 2.1.0 (Ansuel Smith) - Define some PARF params needed for ipq8064 SoC (Ansuel Smith) - Add ipq8064 rev2 variant (Ansuel Smith) - Support PCI speed set for ipq806x (Sham Muthayyan) Renesas R-Car PCIe controller driver: - Use devm_pci_alloc_host_bridge() (Rob Herring) - Use struct pci_host_bridge.windows list directly (Rob Herring) - Convert rcar-gen2 to use modern host bridge probe functions (Rob Herring) TI J721E PCIe driver: - Add TI J721E PCIe host and endpoint driver (Kishon Vijay Abraham I) Xilinx Versal CPM PCIe controller driver: - Add Versal CPM Root Port driver and YAML schema (Bharat Kumar Gogada) MicroSemi Switchtec management driver: - Add missing __iomem and __user tags to fix sparse warnings (Logan Gunthorpe) Miscellaneous: - Replace http:// links with https:// (Alexander A. Klimov) - Replace lkml.org, spinics, gmane with lore.kernel.org (Bjorn Helgaas) - Remove unused pci_lost_interrupt() (Heiner Kallweit) - Move PCI_VENDOR_ID_REDHAT definition to pci_ids.h (Huacai Chen) - Fix kerneldoc warnings (Krzysztof Kozlowski)" * tag 'pci-v5.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (113 commits) PCI: Fix kerneldoc warnings PCI: xilinx-cpm: Add Versal CPM Root Port driver PCI: xilinx-cpm: Add YAML schemas for Versal CPM Root Port PCI: Set bridge map_irq and swizzle_irq to default functions PCI: Move DT resource setup into devm_pci_alloc_host_bridge() PCI: rcar-gen2: Convert to use modern host bridge probe functions PCI: Remove dev_err() when handing an error from platform_get_irq() MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe misc: pci_endpoint_test: Add J721E in pci_device_id table PCI: j721e: Add TI J721E PCIe driver PCI: switchtec: Add missing __iomem tag to fix sparse warnings PCI: switchtec: Add missing __iomem and __user tags to fix sparse warnings PCI: rpadlpar: Make functions static PCI/P2PDMA: Allow P2PDMA on AMD Zen and newer CPUs PCI: Release IVRS table in AMD ACS quirk PCI: Announce device after early fixups PCI: Mark AMD Navi10 GPU rev 0x00 ATS as broken PCI: Remove unused pci_lost_interrupt() dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC ...
This commit is contained in:
commit
049eb096da
131 changed files with 2917 additions and 1757 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
94
Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
Normal file
94
Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
Normal file
|
@ -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";
|
||||
};
|
||||
};
|
113
Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
Normal file
113
Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
99
Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
Normal file
99
Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
Normal file
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -13295,12 +13295,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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -627,7 +627,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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -2560,7 +2560,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;
|
||||
}
|
||||
}
|
||||
|
@ -4738,12 +4738,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;
|
||||
|
@ -4751,7 +4751,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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1256,7 +1256,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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -15585,7 +15585,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);
|
||||
|
||||
|
|
|
@ -4593,7 +4593,7 @@ static int __maybe_unused ice_resume(struct device *dev)
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -79,7 +79,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);
|
||||
|
||||
|
@ -2190,7 +2190,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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1229,7 +1229,7 @@ void efx_fini_mcdi_logging(struct efx_nic *efx)
|
|||
* 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -188,7 +188,8 @@ void pci_pri_init(struct pci_dev *pdev)
|
|||
|
||||
/**
|
||||
* pci_enable_pri - Enable PRI capability
|
||||
* @ pdev: PCI device structure
|
||||
* @pdev: PCI device structure
|
||||
* @reqs: outstanding requests
|
||||
*
|
||||
* Returns 0 on success, negative value on error
|
||||
*/
|
||||
|
@ -325,6 +326,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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
485
drivers/pci/controller/cadence/pci-j721e.c
Normal file
485
drivers/pci/controller/cadence/pci-j721e.c
Normal file
|
@ -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);
|
|
@ -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,
|
||||
|
@ -156,7 +161,7 @@ static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size);
|
||||
cdns_pcie_set_outbound_region(pcie, 0, fn, r, false, addr, pci_addr, size);
|
||||
|
||||
set_bit(r, &ep->ob_region_map);
|
||||
ep->ob_addr[r] = 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;
|
||||
|
@ -239,7 +289,7 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
|
|||
if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
|
||||
ep->irq_pci_fn != fn)) {
|
||||
/* First region was reserved for IRQ writes. */
|
||||
cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0,
|
||||
cdns_pcie_set_outbound_region_for_normal_msg(pcie, 0, fn, 0,
|
||||
ep->irq_phys_addr);
|
||||
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
|
||||
ep->irq_pci_fn = fn;
|
||||
|
@ -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) |
|
||||
|
@ -318,7 +370,7 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
|
|||
if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
|
||||
ep->irq_pci_fn != fn)) {
|
||||
/* First region was reserved for IRQ writes. */
|
||||
cdns_pcie_set_outbound_region(pcie, fn, 0,
|
||||
cdns_pcie_set_outbound_region(pcie, 0, fn, 0,
|
||||
false,
|
||||
ep->irq_phys_addr,
|
||||
pci_addr & ~pci_addr_mask,
|
||||
|
@ -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,
|
||||
|
@ -408,8 +518,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
|
|||
|
||||
pcie->is_rc = false;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
|
||||
pcie->reg_base = devm_ioremap_resource(dev, res);
|
||||
pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
|
||||
if (IS_ERR(pcie->reg_base)) {
|
||||
dev_err(dev, "missing \"reg\"\n");
|
||||
return PTR_ERR(pcie->reg_base);
|
||||
|
@ -440,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);
|
||||
|
@ -449,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,
|
||||
|
@ -466,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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -20,7 +32,7 @@ static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
|
|||
unsigned int busn = bus->number;
|
||||
u32 addr0, desc0;
|
||||
|
||||
if (busn == rc->bus_range->start) {
|
||||
if (pci_is_root_bus(bus)) {
|
||||
/*
|
||||
* Only the root port (devfn == 0) is connected to this bus.
|
||||
* All other PCI devices are behind some bridge hence on another
|
||||
|
@ -50,7 +62,7 @@ static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
|
|||
* The bus number was already set once for all in desc1 by
|
||||
* cdns_pcie_host_init_address_translation().
|
||||
*/
|
||||
if (busn == rc->bus_range->start + 1)
|
||||
if (busn == bridge->busnr + 1)
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
|
||||
else
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
|
||||
|
@ -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,19 +118,230 @@ 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 resource *mem_res = pcie->mem_res;
|
||||
struct resource *bus_range = rc->bus_range;
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
|
||||
struct resource *cfg_res = rc->cfg_res;
|
||||
struct device *dev = pcie->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_pci_range_parser parser;
|
||||
struct of_pci_range range;
|
||||
struct resource_entry *entry;
|
||||
u64 cpu_addr = cfg_res->start;
|
||||
u32 addr0, addr1, desc1;
|
||||
u64 cpu_addr;
|
||||
int r, err;
|
||||
int r, err, busnr = 0;
|
||||
|
||||
entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
|
||||
if (entry)
|
||||
busnr = entry->res->start;
|
||||
|
||||
/*
|
||||
* Reserve region 0 for PCI configure space accesses:
|
||||
|
@ -121,81 +349,74 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
|
|||
* cdns_pci_map_bus(), other region registers are set here once for all.
|
||||
*/
|
||||
addr1 = 0; /* Should be programmed to zero. */
|
||||
desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
|
||||
desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
|
||||
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);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
|
||||
|
||||
err = of_pci_range_parser_init(&parser, np);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
r = 1;
|
||||
for_each_of_pci_range(&parser, &range) {
|
||||
bool is_io;
|
||||
resource_list_for_each_entry(entry, &bridge->windows) {
|
||||
struct resource *res = entry->res;
|
||||
u64 pci_addr = res->start - entry->offset;
|
||||
|
||||
if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
|
||||
is_io = false;
|
||||
else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
|
||||
is_io = true;
|
||||
if (resource_type(res) == IORESOURCE_IO)
|
||||
cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
|
||||
true,
|
||||
pci_pio_to_address(res->start),
|
||||
pci_addr,
|
||||
resource_size(res));
|
||||
else
|
||||
continue;
|
||||
cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
|
||||
false,
|
||||
res->start,
|
||||
pci_addr,
|
||||
resource_size(res));
|
||||
|
||||
cdns_pcie_set_outbound_region(pcie, 0, r, is_io,
|
||||
range.cpu_addr,
|
||||
range.pci_addr,
|
||||
range.size);
|
||||
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;
|
||||
}
|
||||
|
||||
static int cdns_pcie_host_init(struct device *dev,
|
||||
struct list_head *resources,
|
||||
struct cdns_pcie_rc *rc)
|
||||
{
|
||||
struct resource *bus_range = NULL;
|
||||
int err;
|
||||
|
||||
/* Parse our PCI ranges and request their resources */
|
||||
err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rc->bus_range = bus_range;
|
||||
rc->pcie.bus = bus_range->start;
|
||||
|
||||
err = cdns_pcie_host_init_root_port(rc);
|
||||
if (err)
|
||||
goto err_out;
|
||||
return err;
|
||||
|
||||
err = cdns_pcie_host_init_address_translation(rc);
|
||||
if (err)
|
||||
goto err_out;
|
||||
return cdns_pcie_host_init_address_translation(rc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
int retries;
|
||||
|
||||
err_out:
|
||||
pci_free_resource_list(resources);
|
||||
return err;
|
||||
/* 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)
|
||||
|
@ -204,7 +425,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct list_head resources;
|
||||
enum cdns_pcie_rp_bar bar;
|
||||
struct cdns_pcie *pcie;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
@ -216,17 +437,13 @@ 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);
|
||||
|
||||
rc->device_id = 0xffff;
|
||||
of_property_read_u32(np, "device-id", &rc->device_id);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
|
||||
pcie->reg_base = devm_ioremap_resource(dev, res);
|
||||
pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
|
||||
if (IS_ERR(pcie->reg_base)) {
|
||||
dev_err(dev, "missing \"reg\"\n");
|
||||
return PTR_ERR(pcie->reg_base);
|
||||
|
@ -234,40 +451,36 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
|
|||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
|
||||
rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(rc->cfg_base)) {
|
||||
dev_err(dev, "missing \"cfg\"\n");
|
||||
if (IS_ERR(rc->cfg_base))
|
||||
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_init(dev, &resources, rc);
|
||||
ret = cdns_pcie_host_wait_for_link(pcie);
|
||||
if (ret)
|
||||
goto err_init;
|
||||
dev_dbg(dev, "PCIe link never came up\n");
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
bridge->busnr = pcie->bus;
|
||||
bridge->ops = &cdns_pcie_host_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
|
||||
rc->avail_ib_bar[bar] = true;
|
||||
|
||||
ret = cdns_pcie_host_init(dev, rc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!bridge->ops)
|
||||
bridge->ops = &cdns_pcie_host_ops;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0)
|
||||
goto err_host_probe;
|
||||
goto err_init;
|
||||
|
||||
return 0;
|
||||
|
||||
err_host_probe:
|
||||
pci_free_resource_list(&resources);
|
||||
|
||||
err_init:
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "pcie-cadence.h"
|
||||
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
|
||||
u32 r, bool is_io,
|
||||
u64 cpu_addr, u64 pci_addr, size_t size)
|
||||
{
|
||||
|
@ -60,7 +60,7 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
|||
/* The device and function numbers are always 0. */
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
|
||||
CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
|
||||
} else {
|
||||
/*
|
||||
* Use captured values for bus and device numbers but still
|
||||
|
@ -73,7 +73,9 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, 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);
|
||||
|
@ -82,7 +84,8 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
|||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
|
||||
}
|
||||
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
|
||||
u8 busnr, u8 fn,
|
||||
u32 r, u64 cpu_addr)
|
||||
{
|
||||
u32 addr0, addr1, desc0, desc1;
|
||||
|
@ -94,13 +97,15 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
|
|||
if (pcie->is_rc) {
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
|
||||
CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
|
||||
} else {
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
|
|
@ -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,23 +251,31 @@ 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;
|
||||
struct resource *mem_res;
|
||||
struct device *dev;
|
||||
bool is_rc;
|
||||
u8 bus;
|
||||
int phy_count;
|
||||
struct phy **phy;
|
||||
struct device_link **link;
|
||||
const struct cdns_pcie_common_ops *ops;
|
||||
const struct cdns_pcie_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -248,22 +284,28 @@ struct cdns_pcie {
|
|||
* @dev: pointer to PCIe device
|
||||
* @cfg_res: start/end offsets in the physical system memory to map PCI
|
||||
* configuration space accesses
|
||||
* @bus_range: first/last buses behind the PCIe host controller
|
||||
* @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;
|
||||
struct resource *bus_range;
|
||||
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];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -282,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;
|
||||
|
@ -293,20 +339,13 @@ 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)
|
||||
{
|
||||
writeb(value, pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
|
||||
{
|
||||
writew(value, pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
|
||||
{
|
||||
writel(value, pcie->reg_base + reg);
|
||||
|
@ -317,30 +356,78 @@ static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
|
|||
return readl(pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
|
||||
{
|
||||
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 void cdns_pcie_write_sz(void __iomem *addr, int size, u32 value)
|
||||
{
|
||||
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,
|
||||
|
@ -349,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)
|
||||
|
@ -364,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
|
||||
|
@ -381,11 +495,12 @@ static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
|
||||
u32 r, bool is_io,
|
||||
u64 cpu_addr, u64 pci_addr, size_t size);
|
||||
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie,
|
||||
u8 busnr, u8 fn,
|
||||
u32 r, u64 cpu_addr);
|
||||
|
||||
void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
|
||||
|
|
|
@ -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,20 +625,16 @@ 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) {
|
||||
dev_err(dev, "missing IRQ resource\n");
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = dra7xx_pcie_init_irq_domain(pp);
|
||||
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);
|
||||
|
||||
|
@ -871,10 +866,8 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
base = devm_platform_ioremap_resource_byname(pdev, "ti_conf");
|
||||
if (IS_ERR(base))
|
||||
|
@ -998,9 +991,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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
*/
|
||||
|
@ -84,14 +84,12 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
|
|||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct device *dev = pci->dev;
|
||||
struct resource *res;
|
||||
|
||||
ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
|
||||
if (!ep->mem_res)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
|
||||
ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ep->mem_res->elbi_base))
|
||||
return PTR_ERR(ep->mem_res->elbi_base);
|
||||
|
||||
|
@ -402,10 +400,9 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
|
|||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 1);
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq\n");
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
|
||||
IRQF_SHARED, "exynos-pcie", ep);
|
||||
if (ret) {
|
||||
|
@ -415,10 +412,8 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get msi irq\n");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
pp->ops = &exynos_pcie_host_ops;
|
||||
|
|
|
@ -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>
|
||||
*/
|
||||
|
@ -868,10 +868,8 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get MSI irq\n");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
pp->ops = &imx6_pcie_host_ops;
|
||||
|
@ -1269,7 +1267,7 @@ static void imx6_pcie_quirk(struct pci_dev *dev)
|
|||
if (bus->dev.parent->parent->driver != &imx6_pcie_driver.driver)
|
||||
return;
|
||||
|
||||
if (bus->number == pp->root_bus_nr) {
|
||||
if (pci_is_root_bus(bus)) {
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -440,7 +440,7 @@ static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
|||
|
||||
reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
|
||||
CFG_FUNC(PCI_FUNC(devfn));
|
||||
if (bus->parent->number != pp->root_bus_nr)
|
||||
if (!pci_is_root_bus(bus->parent))
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
|
@ -457,7 +457,7 @@ static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
|||
|
||||
reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
|
||||
CFG_FUNC(PCI_FUNC(devfn));
|
||||
if (bus->parent->number != pp->root_bus_nr)
|
||||
if (!pci_is_root_bus(bus->parent))
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
|
@ -1250,10 +1250,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
|||
pci->version = version;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED,
|
||||
"ks-pcie-error-irq", ks_pcie);
|
||||
|
@ -1323,8 +1321,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;
|
||||
|
|
|
@ -488,10 +488,8 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get MSI IRQ\n");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
pp->ops = &meson_pcie_host_ops;
|
||||
|
|
|
@ -67,13 +67,8 @@ static int al_pcie_init(struct pci_config_window *cfg)
|
|||
dev_dbg(dev, "Root port dbi res: %pR\n", res);
|
||||
|
||||
al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(al_pcie->dbi_base)) {
|
||||
long err = PTR_ERR(al_pcie->dbi_base);
|
||||
|
||||
dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n",
|
||||
res, err);
|
||||
return err;
|
||||
}
|
||||
if (IS_ERR(al_pcie->dbi_base))
|
||||
return PTR_ERR(al_pcie->dbi_base);
|
||||
|
||||
cfg->priv = al_pcie;
|
||||
|
||||
|
@ -408,10 +403,8 @@ static int al_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
|
||||
if (IS_ERR(pci->dbi_base)) {
|
||||
dev_err(dev, "couldn't remap dbi base %pR\n", dbi_res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
}
|
||||
|
||||
ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
if (!ecam_res) {
|
||||
|
|
|
@ -248,10 +248,8 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
|
|||
pp->ops = &armada8k_pcie_host_ops;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq for port\n");
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, armada8k_pcie_irq_handler,
|
||||
IRQF_SHARED, "armada8k-pcie", pcie);
|
||||
|
@ -317,7 +315,6 @@ static int armada8k_pcie_probe(struct platform_device *pdev)
|
|||
base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, base);
|
||||
if (IS_ERR(pci->dbi_base)) {
|
||||
dev_err(dev, "couldn't remap regs base %p\n", base);
|
||||
ret = PTR_ERR(pci->dbi_base);
|
||||
goto fail_clkreg;
|
||||
}
|
||||
|
|
|
@ -387,10 +387,8 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get MSI irq\n");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
pp->ops = &artpec6_pcie_host_ops;
|
||||
|
@ -455,8 +453,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 +478,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 +507,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);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* Synopsys DesignWare PCIe Endpoint controller driver
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
|
|
|
@ -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>
|
||||
*/
|
||||
|
@ -346,11 +346,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
|||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get the I/O and memory ranges from DT */
|
||||
resource_list_for_each_entry(win, &bridge->windows) {
|
||||
switch (resource_type(win->res)) {
|
||||
|
@ -473,14 +468,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
|||
goto err_free_msi;
|
||||
}
|
||||
|
||||
pp->root_bus_nr = pp->busn->start;
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pp;
|
||||
bridge->busnr = pp->root_bus_nr;
|
||||
bridge->ops = &dw_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret)
|
||||
|
@ -529,7 +518,7 @@ static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
|||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||
|
||||
if (bus->parent->number == pp->root_bus_nr) {
|
||||
if (pci_is_root_bus(bus->parent)) {
|
||||
type = PCIE_ATU_TYPE_CFG0;
|
||||
cpu_addr = pp->cfg0_base;
|
||||
cfg_size = pp->cfg0_size;
|
||||
|
@ -585,13 +574,11 @@ static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus,
|
|||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/* If there is no link, then there is no device */
|
||||
if (bus->number != pp->root_bus_nr) {
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
if (!dw_pcie_link_up(pci))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Access only one slot on each root port */
|
||||
if (bus->number == pp->root_bus_nr && dev > 0)
|
||||
} else if (dev > 0)
|
||||
/* Access only one slot on each root port */
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
@ -607,7 +594,7 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (bus->number == pp->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return dw_pcie_rd_own_conf(pp, where, size, val);
|
||||
|
||||
return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val);
|
||||
|
@ -621,7 +608,7 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (bus->number == pp->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return dw_pcie_wr_own_conf(pp, where, size, val);
|
||||
|
||||
return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
*/
|
||||
|
|
|
@ -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>
|
||||
*/
|
||||
|
@ -173,7 +173,6 @@ struct dw_pcie_host_ops {
|
|||
};
|
||||
|
||||
struct pcie_port {
|
||||
u8 root_bus_nr;
|
||||
u64 cfg0_base;
|
||||
void __iomem *va_cfg0_base;
|
||||
u32 cfg0_size;
|
||||
|
|
|
@ -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 = ®_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 = ®_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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -402,10 +399,8 @@ static int histb_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "Failed to get MSI IRQ\n");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
hipcie->phy = devm_phy_get(dev, "phy");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -455,11 +450,8 @@ static int kirin_pcie_add_msi(struct dw_pcie *pci,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get MSI IRQ (%d)\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
pci->pp.msi_irq = irq;
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -198,10 +198,9 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
|
|||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq\n");
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler,
|
||||
IRQF_SHARED | IRQF_NO_THREAD,
|
||||
"spear1340-pcie", spear13xx_pcie);
|
||||
|
@ -273,7 +272,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
|
|||
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
|
||||
if (IS_ERR(pci->dbi_base)) {
|
||||
dev_err(dev, "couldn't remap dbi base %p\n", dbi_base);
|
||||
ret = PTR_ERR(pci->dbi_base);
|
||||
goto fail_clk;
|
||||
}
|
||||
|
|
|
@ -2189,10 +2189,8 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
pp->irq = platform_get_irq_byname(pdev, "intr");
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "Failed to get \"intr\" interrupt\n");
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
pcie->bpmp = tegra_bpmp_get(dev);
|
||||
if (IS_ERR(pcie->bpmp))
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -170,10 +170,9 @@ static int ls_pcie_g4_interrupt_init(struct mobiveil_pcie *mv_pci)
|
|||
int ret;
|
||||
|
||||
pcie->irq = platform_get_irq_byname(pdev, "intr");
|
||||
if (pcie->irq < 0) {
|
||||
dev_err(dev, "Can't get 'intr' IRQ, errno = %d\n", pcie->irq);
|
||||
if (pcie->irq < 0)
|
||||
return pcie->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pcie->irq, ls_pcie_g4_isr,
|
||||
IRQF_SHARED, pdev->name, pcie);
|
||||
if (ret) {
|
||||
|
|
|
@ -29,18 +29,15 @@
|
|||
|
||||
static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
|
||||
{
|
||||
struct mobiveil_pcie *pcie = bus->sysdata;
|
||||
struct mobiveil_root_port *rp = &pcie->rp;
|
||||
|
||||
/* Only one device down on each root port */
|
||||
if ((bus->number == rp->root_bus_nr) && (devfn > 0))
|
||||
if (pci_is_root_bus(bus) && (devfn > 0))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Do not read more than one device on the bus directly
|
||||
* attached to RC
|
||||
*/
|
||||
if ((bus->primary == rp->root_bus_nr) && (PCI_SLOT(devfn) > 0))
|
||||
if ((bus->primary == to_pci_host_bridge(bus->bridge)->busnr) && (PCI_SLOT(devfn) > 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -61,7 +58,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
|
|||
return NULL;
|
||||
|
||||
/* RC config access */
|
||||
if (bus->number == rp->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return pcie->csr_axi_slave_base + where;
|
||||
|
||||
/*
|
||||
|
@ -522,10 +519,8 @@ static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie)
|
|||
mobiveil_pcie_enable_msi(pcie);
|
||||
|
||||
rp->irq = platform_get_irq(pdev, 0);
|
||||
if (rp->irq < 0) {
|
||||
dev_err(dev, "failed to map IRQ: %d\n", rp->irq);
|
||||
if (rp->irq < 0)
|
||||
return rp->irq;
|
||||
}
|
||||
|
||||
/* initialize the IRQ domains */
|
||||
ret = mobiveil_pcie_init_irq_domain(pcie);
|
||||
|
@ -569,8 +564,6 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
|
|||
struct mobiveil_root_port *rp = &pcie->rp;
|
||||
struct pci_host_bridge *bridge = rp->bridge;
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct pci_bus *bus;
|
||||
struct pci_bus *child;
|
||||
int ret;
|
||||
|
||||
ret = mobiveil_pcie_parse_dt(pcie);
|
||||
|
@ -582,14 +575,6 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
|
|||
if (!mobiveil_pcie_is_bridge(pcie))
|
||||
return -ENODEV;
|
||||
|
||||
/* parse the host bridge base addresses from the device tree file */
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Getting bridge resources failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* configure all inbound and outbound windows and prepare the RC for
|
||||
* config access
|
||||
|
@ -607,12 +592,8 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
|
|||
}
|
||||
|
||||
/* Initialize bridge */
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->busnr = rp->root_bus_nr;
|
||||
bridge->ops = &mobiveil_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = mobiveil_bringup_link(pcie);
|
||||
if (ret) {
|
||||
|
@ -620,17 +601,5 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* setup the kernel resources for the newly added PCIe root bus */
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,6 @@ struct mobiveil_rp_ops {
|
|||
};
|
||||
|
||||
struct mobiveil_root_port {
|
||||
char root_bus_nr;
|
||||
void __iomem *config_axi_slave_base; /* endpoint config base */
|
||||
struct resource *ob_io_res;
|
||||
struct mobiveil_rp_ops *ops;
|
||||
|
|
|
@ -195,7 +195,6 @@ struct advk_pcie {
|
|||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
struct mutex msi_used_lock;
|
||||
u16 msi_msg;
|
||||
int root_bus_nr;
|
||||
int link_gen;
|
||||
struct pci_bridge_emul bridge;
|
||||
struct gpio_desc *reset_gpio;
|
||||
|
@ -641,7 +640,14 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
|
|||
static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
|
||||
int devfn)
|
||||
{
|
||||
if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0)
|
||||
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;
|
||||
|
@ -659,7 +665,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
|||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (bus->number == pcie->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return pci_bridge_emul_conf_read(&pcie->bridge, where,
|
||||
size, val);
|
||||
|
||||
|
@ -670,7 +676,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
|||
/* Program the control register */
|
||||
reg = advk_readl(pcie, PIO_CTRL);
|
||||
reg &= ~PIO_CTRL_TYPE_MASK;
|
||||
if (bus->primary == pcie->root_bus_nr)
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
reg |= PCIE_CONFIG_RD_TYPE0;
|
||||
else
|
||||
reg |= PCIE_CONFIG_RD_TYPE1;
|
||||
|
@ -688,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);
|
||||
|
||||
|
@ -715,7 +723,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
if (!advk_pcie_valid_device(pcie, bus, devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (bus->number == pcie->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return pci_bridge_emul_conf_write(&pcie->bridge, where,
|
||||
size, val);
|
||||
|
||||
|
@ -729,7 +737,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
/* Program the control register */
|
||||
reg = advk_readl(pcie, PIO_CTRL);
|
||||
reg &= ~PIO_CTRL_TYPE_MASK;
|
||||
if (bus->primary == pcie->root_bus_nr)
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
reg |= PCIE_CONFIG_WR_TYPE0;
|
||||
else
|
||||
reg |= PCIE_CONFIG_WR_TYPE1;
|
||||
|
@ -1105,7 +1113,6 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct advk_pcie *pcie;
|
||||
struct resource *res, *bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret, irq;
|
||||
|
||||
|
@ -1116,8 +1123,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
|||
pcie = pci_host_bridge_priv(bridge);
|
||||
pcie->pdev = pdev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pcie->base = devm_ioremap_resource(dev, res);
|
||||
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pcie->base))
|
||||
return PTR_ERR(pcie->base);
|
||||
|
||||
|
@ -1133,14 +1139,6 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, &bus);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to parse resources\n");
|
||||
return ret;
|
||||
}
|
||||
pcie->root_bus_nr = bus->start;
|
||||
|
||||
pcie->reset_gpio = devm_gpiod_get_from_of_node(dev, dev->of_node,
|
||||
"reset-gpios", 0,
|
||||
GPIOD_OUT_LOW,
|
||||
|
@ -1184,12 +1182,8 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &advk_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -422,7 +422,6 @@ static int faraday_pci_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
const struct faraday_pci_variant *variant =
|
||||
of_device_get_match_data(dev);
|
||||
struct resource *regs;
|
||||
struct resource_entry *win;
|
||||
struct faraday_pci *p;
|
||||
struct resource *io;
|
||||
|
@ -437,12 +436,7 @@ static int faraday_pci_probe(struct platform_device *pdev)
|
|||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
host->dev.parent = dev;
|
||||
host->ops = &faraday_pci_ops;
|
||||
host->busnr = 0;
|
||||
host->msi = NULL;
|
||||
host->map_irq = of_irq_parse_and_map_pci;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
p = pci_host_bridge_priv(host);
|
||||
host->sysdata = p;
|
||||
p->dev = dev;
|
||||
|
@ -465,16 +459,10 @@ static int faraday_pci_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
p->base = devm_ioremap_resource(dev, regs);
|
||||
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p->base))
|
||||
return PTR_ERR(p->base);
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
|
||||
&host->dma_ranges, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
win = resource_list_first_type(&host->windows, IORESOURCE_IO);
|
||||
if (win) {
|
||||
io = win->res;
|
||||
|
|
|
@ -21,39 +21,32 @@ static void gen_pci_unmap_cfg(void *ptr)
|
|||
}
|
||||
|
||||
static struct pci_config_window *gen_pci_init(struct device *dev,
|
||||
struct list_head *resources, const struct pci_ecam_ops *ops)
|
||||
struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops)
|
||||
{
|
||||
int err;
|
||||
struct resource cfgres;
|
||||
struct resource *bus_range = NULL;
|
||||
struct resource_entry *bus;
|
||||
struct pci_config_window *cfg;
|
||||
|
||||
/* Parse our PCI ranges and request their resources */
|
||||
err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = of_address_to_resource(dev->of_node, 0, &cfgres);
|
||||
if (err) {
|
||||
dev_err(dev, "missing \"reg\" property\n");
|
||||
goto err_out;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
cfg = pci_ecam_create(dev, &cfgres, bus_range, ops);
|
||||
if (IS_ERR(cfg)) {
|
||||
err = PTR_ERR(cfg);
|
||||
goto err_out;
|
||||
}
|
||||
bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
|
||||
if (!bus)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
cfg = pci_ecam_create(dev, &cfgres, bus->res, ops);
|
||||
if (IS_ERR(cfg))
|
||||
return cfg;
|
||||
|
||||
err = devm_add_action_or_reset(dev, gen_pci_unmap_cfg, cfg);
|
||||
if (err) {
|
||||
goto err_out;
|
||||
}
|
||||
return cfg;
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err_out:
|
||||
pci_free_resource_list(resources);
|
||||
return ERR_PTR(err);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
int pci_host_common_probe(struct platform_device *pdev)
|
||||
|
@ -61,9 +54,7 @@ int pci_host_common_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_config_window *cfg;
|
||||
struct list_head resources;
|
||||
const struct pci_ecam_ops *ops;
|
||||
int ret;
|
||||
|
||||
ops = of_device_get_match_data(&pdev->dev);
|
||||
if (!ops)
|
||||
|
@ -76,7 +67,7 @@ int pci_host_common_probe(struct platform_device *pdev)
|
|||
of_pci_check_probe_only();
|
||||
|
||||
/* Parse and map our Configuration Space windows */
|
||||
cfg = gen_pci_init(dev, &resources, ops);
|
||||
cfg = gen_pci_init(dev, bridge, ops);
|
||||
if (IS_ERR(cfg))
|
||||
return PTR_ERR(cfg);
|
||||
|
||||
|
@ -84,32 +75,22 @@ int pci_host_common_probe(struct platform_device *pdev)
|
|||
if (!pci_has_flag(PCI_PROBE_ONLY))
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = cfg;
|
||||
bridge->busnr = cfg->busr.start;
|
||||
bridge->ops = (struct pci_ops *)&ops->pci_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0) {
|
||||
pci_free_resource_list(&resources);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, bridge);
|
||||
|
||||
platform_set_drvdata(pdev, bridge->bus);
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_host_common_probe);
|
||||
|
||||
int pci_host_common_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_bus *bus = platform_get_drvdata(pdev);
|
||||
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_root_bus(bus);
|
||||
pci_remove_root_bus(bus);
|
||||
pci_stop_root_bus(bridge->bus);
|
||||
pci_remove_root_bus(bridge->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -218,14 +218,6 @@ static int loongson_pci_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get bridge resources\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = priv;
|
||||
bridge->ops = &loongson_pci_ops;
|
||||
bridge->map_irq = loongson_map_irq;
|
||||
|
|
|
@ -71,7 +71,6 @@ struct mvebu_pcie {
|
|||
struct platform_device *pdev;
|
||||
struct mvebu_pcie_port *ports;
|
||||
struct msi_controller *msi;
|
||||
struct list_head resources;
|
||||
struct resource io;
|
||||
struct resource realio;
|
||||
struct resource mem;
|
||||
|
@ -105,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)
|
||||
|
@ -149,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)
|
||||
|
@ -203,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)
|
||||
|
@ -708,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, ®s);
|
||||
ret = of_address_to_resource(np, 0, &port->regs);
|
||||
if (ret)
|
||||
return (void __iomem *)ERR_PTR(ret);
|
||||
|
||||
return devm_ioremap_resource(&pdev->dev, ®s);
|
||||
return devm_ioremap_resource(&pdev->dev, &port->regs);
|
||||
}
|
||||
|
||||
#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03)
|
||||
|
@ -961,17 +968,16 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
|
|||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&pcie->resources);
|
||||
|
||||
/* Get the bus range */
|
||||
ret = of_pci_parse_bus_range(np, &pcie->busn);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to parse bus-range property: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
pci_add_resource(&pcie->resources, &pcie->busn);
|
||||
pci_add_resource(&bridge->windows, &pcie->busn);
|
||||
|
||||
/* Get the PCIe memory aperture */
|
||||
mvebu_mbus_get_pcie_mem_aperture(&pcie->mem);
|
||||
|
@ -981,7 +987,7 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
|
|||
}
|
||||
|
||||
pcie->mem.name = "PCI MEM";
|
||||
pci_add_resource(&pcie->resources, &pcie->mem);
|
||||
pci_add_resource(&bridge->windows, &pcie->mem);
|
||||
|
||||
/* Get the PCIe IO aperture */
|
||||
mvebu_mbus_get_pcie_io_aperture(&pcie->io);
|
||||
|
@ -994,10 +1000,10 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
|
|||
resource_size(&pcie->io) - 1);
|
||||
pcie->realio.name = "PCI I/O";
|
||||
|
||||
pci_add_resource(&pcie->resources, &pcie->realio);
|
||||
pci_add_resource(&bridge->windows, &pcie->realio);
|
||||
}
|
||||
|
||||
return devm_request_pci_bus_resources(dev, &pcie->resources);
|
||||
return devm_request_pci_bus_resources(dev, &bridge->windows);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1118,13 +1124,8 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
pcie->nports = i;
|
||||
|
||||
list_splice_init(&pcie->resources, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &mvebu_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->align_resource = mvebu_pcie_align_resource;
|
||||
bridge->msi = pcie->msi;
|
||||
|
||||
|
|
|
@ -98,22 +98,17 @@ struct rcar_pci_priv {
|
|||
void __iomem *reg;
|
||||
struct resource mem_res;
|
||||
struct resource *cfg_res;
|
||||
unsigned busnr;
|
||||
int irq;
|
||||
unsigned long window_size;
|
||||
unsigned long window_addr;
|
||||
unsigned long window_pci;
|
||||
};
|
||||
|
||||
/* PCI configuration space operations */
|
||||
static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct pci_sys_data *sys = bus->sysdata;
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
struct rcar_pci_priv *priv = bus->sysdata;
|
||||
int slot, val;
|
||||
|
||||
if (sys->busnr != bus->number || PCI_FUNC(devfn))
|
||||
if (!pci_is_root_bus(bus) || PCI_FUNC(devfn))
|
||||
return NULL;
|
||||
|
||||
/* Only one EHCI/OHCI device built-in */
|
||||
|
@ -132,20 +127,6 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
|
|||
return priv->reg + (slot >> 1) * 0x100 + where;
|
||||
}
|
||||
|
||||
/* PCI interrupt mapping */
|
||||
static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
struct pci_sys_data *sys = dev->bus->sysdata;
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
int irq;
|
||||
|
||||
irq = of_irq_parse_and_map_pci(dev, slot, pin);
|
||||
if (!irq)
|
||||
irq = priv->irq;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_DEBUG
|
||||
/* if debug enabled, then attach an error handler irq to the bridge */
|
||||
|
||||
|
@ -189,19 +170,33 @@ static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { }
|
|||
#endif
|
||||
|
||||
/* PCI host controller setup */
|
||||
static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
static void rcar_pci_setup(struct rcar_pci_priv *priv)
|
||||
{
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(priv);
|
||||
struct device *dev = priv->dev;
|
||||
void __iomem *reg = priv->reg;
|
||||
struct resource_entry *entry;
|
||||
unsigned long window_size;
|
||||
unsigned long window_addr;
|
||||
unsigned long window_pci;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
|
||||
if (!entry) {
|
||||
window_addr = 0x40000000;
|
||||
window_pci = 0x40000000;
|
||||
window_size = SZ_1G;
|
||||
} else {
|
||||
window_addr = entry->res->start;
|
||||
window_pci = entry->res->start - entry->offset;
|
||||
window_size = resource_size(entry->res);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
|
||||
dev_info(dev, "PCI: bus%u revision %x\n", sys->busnr, val);
|
||||
dev_info(dev, "PCI: revision %x\n", val);
|
||||
|
||||
/* Disable Direct Power Down State and assert reset */
|
||||
val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
|
||||
|
@ -214,7 +209,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
|||
RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
|
||||
|
||||
/* Setup PCIAHB window1 size */
|
||||
switch (priv->window_size) {
|
||||
switch (window_size) {
|
||||
case SZ_2G:
|
||||
val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
|
||||
break;
|
||||
|
@ -226,8 +221,8 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
|||
break;
|
||||
default:
|
||||
pr_warn("unknown window size %ld - defaulting to 256M\n",
|
||||
priv->window_size);
|
||||
priv->window_size = SZ_256M;
|
||||
window_size);
|
||||
window_size = SZ_256M;
|
||||
/* fall-through */
|
||||
case SZ_256M:
|
||||
val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
|
||||
|
@ -245,7 +240,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
|||
iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
|
||||
|
||||
/* PCI-AHB mapping */
|
||||
iowrite32(priv->window_addr | RCAR_PCIAHB_PREFETCH16,
|
||||
iowrite32(window_addr | RCAR_PCIAHB_PREFETCH16,
|
||||
reg + RCAR_PCIAHB_WIN1_CTR_REG);
|
||||
|
||||
/* AHB-PCI mapping: OHCI/EHCI registers */
|
||||
|
@ -256,7 +251,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
|||
iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
|
||||
reg + RCAR_AHBPCI_WIN1_CTR_REG);
|
||||
/* Set PCI-AHB Window1 address */
|
||||
iowrite32(priv->window_pci | PCI_BASE_ADDRESS_MEM_PREFETCH,
|
||||
iowrite32(window_pci | PCI_BASE_ADDRESS_MEM_PREFETCH,
|
||||
reg + PCI_BASE_ADDRESS_1);
|
||||
/* Set AHB-PCI bridge PCI communication area address */
|
||||
val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
|
||||
|
@ -271,18 +266,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
|||
iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
|
||||
reg + RCAR_PCI_INT_ENABLE_REG);
|
||||
|
||||
if (priv->irq > 0)
|
||||
rcar_pci_setup_errirq(priv);
|
||||
|
||||
/* Add PCI resources */
|
||||
pci_add_resource(&sys->resources, &priv->mem_res);
|
||||
ret = devm_request_pci_bus_resources(dev, &sys->resources);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Setup bus number based on platform device id / of bus-range */
|
||||
sys->busnr = priv->busnr;
|
||||
return 1;
|
||||
rcar_pci_setup_errirq(priv);
|
||||
}
|
||||
|
||||
static struct pci_ops rcar_pci_ops = {
|
||||
|
@ -291,55 +275,20 @@ static struct pci_ops rcar_pci_ops = {
|
|||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct device *dev = pci->dev;
|
||||
struct of_pci_range range;
|
||||
struct of_pci_range_parser parser;
|
||||
int index = 0;
|
||||
|
||||
/* Failure to parse is ok as we fall back to defaults */
|
||||
if (of_pci_dma_range_parser_init(&parser, np))
|
||||
return 0;
|
||||
|
||||
/* Get the dma-ranges from DT */
|
||||
for_each_of_pci_range(&parser, &range) {
|
||||
/* Hardware only allows one inbound 32-bit range */
|
||||
if (index)
|
||||
return -EINVAL;
|
||||
|
||||
pci->window_addr = (unsigned long)range.cpu_addr;
|
||||
pci->window_pci = (unsigned long)range.pci_addr;
|
||||
pci->window_size = (unsigned long)range.size;
|
||||
|
||||
/* Catch HW limitations */
|
||||
if (!(range.flags & IORESOURCE_PREFETCH)) {
|
||||
dev_err(dev, "window must be prefetchable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pci->window_addr) {
|
||||
u32 lowaddr = 1 << (ffs(pci->window_addr) - 1);
|
||||
|
||||
if (lowaddr < pci->window_size) {
|
||||
dev_err(dev, "invalid window size/addr\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_pci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *cfg_res, *mem_res;
|
||||
struct rcar_pci_priv *priv;
|
||||
struct pci_host_bridge *bridge;
|
||||
void __iomem *reg;
|
||||
struct hw_pci hw;
|
||||
void *hw_private[1];
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*priv));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = pci_host_bridge_priv(bridge);
|
||||
bridge->sysdata = priv;
|
||||
|
||||
cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg = devm_ioremap_resource(dev, cfg_res);
|
||||
|
@ -353,10 +302,6 @@ static int rcar_pci_probe(struct platform_device *pdev)
|
|||
if (mem_res->start & 0xFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct rcar_pci_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->mem_res = *mem_res;
|
||||
priv->cfg_res = cfg_res;
|
||||
|
||||
|
@ -369,44 +314,13 @@ static int rcar_pci_probe(struct platform_device *pdev)
|
|||
return priv->irq;
|
||||
}
|
||||
|
||||
/* default window addr and size if not specified in DT */
|
||||
priv->window_addr = 0x40000000;
|
||||
priv->window_pci = 0x40000000;
|
||||
priv->window_size = SZ_1G;
|
||||
bridge->ops = &rcar_pci_ops;
|
||||
|
||||
if (dev->of_node) {
|
||||
struct resource busnr;
|
||||
int ret;
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
ret = of_pci_parse_bus_range(dev->of_node, &busnr);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to parse bus-range\n");
|
||||
return ret;
|
||||
}
|
||||
rcar_pci_setup(priv);
|
||||
|
||||
priv->busnr = busnr.start;
|
||||
if (busnr.end != busnr.start)
|
||||
dev_warn(dev, "only one bus number supported\n");
|
||||
|
||||
ret = rcar_pci_parse_map_dma_ranges(priv, dev->of_node);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to parse dma-range\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
priv->busnr = pdev->id;
|
||||
}
|
||||
|
||||
hw_private[0] = priv;
|
||||
memset(&hw, 0, sizeof(hw));
|
||||
hw.nr_controllers = ARRAY_SIZE(hw_private);
|
||||
hw.io_optional = 1;
|
||||
hw.private_data = hw_private;
|
||||
hw.map_irq = rcar_pci_map_irq;
|
||||
hw.ops = &rcar_pci_ops;
|
||||
hw.setup = rcar_pci_setup;
|
||||
pci_common_init_dev(dev, &hw);
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static const struct of_device_id rcar_pci_of_match[] = {
|
||||
|
|
|
@ -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;
|
||||
|
@ -1462,7 +1437,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
|||
{
|
||||
struct device *dev = pcie->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *pads, *afi, *res;
|
||||
struct resource *res;
|
||||
const struct tegra_pcie_soc *soc = pcie->soc;
|
||||
int err;
|
||||
|
||||
|
@ -1486,15 +1461,13 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
|||
}
|
||||
}
|
||||
|
||||
pads = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pads");
|
||||
pcie->pads = devm_ioremap_resource(dev, pads);
|
||||
pcie->pads = devm_platform_ioremap_resource_byname(pdev, "pads");
|
||||
if (IS_ERR(pcie->pads)) {
|
||||
err = PTR_ERR(pcie->pads);
|
||||
goto phys_put;
|
||||
}
|
||||
|
||||
afi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "afi");
|
||||
pcie->afi = devm_ioremap_resource(dev, afi);
|
||||
pcie->afi = devm_platform_ioremap_resource_byname(pdev, "afi");
|
||||
if (IS_ERR(pcie->afi)) {
|
||||
err = PTR_ERR(pcie->afi);
|
||||
goto phys_put;
|
||||
|
@ -1520,10 +1493,8 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
|||
|
||||
/* request interrupt */
|
||||
err = platform_get_irq_byname(pdev, "intr");
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to get IRQ: %d\n", err);
|
||||
if (err < 0)
|
||||
goto phys_put;
|
||||
}
|
||||
|
||||
pcie->irq = err;
|
||||
|
||||
|
@ -1738,10 +1709,8 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
|
|||
}
|
||||
|
||||
err = platform_get_irq_byname(pdev, "msi");
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to get IRQ: %d\n", err);
|
||||
if (err < 0)
|
||||
goto free_irq_domain;
|
||||
}
|
||||
|
||||
msi->irq = err;
|
||||
|
||||
|
@ -2025,7 +1994,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),
|
||||
|
@ -2033,14 +2002,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),
|
||||
|
@ -2050,11 +2016,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;
|
||||
|
||||
|
@ -2416,7 +2379,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,
|
||||
|
@ -2446,7 +2408,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,
|
||||
|
@ -2459,8 +2420,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,
|
||||
|
@ -2470,7 +2429,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,
|
||||
|
@ -2494,7 +2452,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 = {
|
||||
|
@ -2536,7 +2493,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,
|
||||
|
@ -2670,8 +2626,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct pci_host_bridge *host;
|
||||
struct tegra_pcie *pcie;
|
||||
struct pci_bus *child;
|
||||
struct resource *bus;
|
||||
int err;
|
||||
|
||||
host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
|
||||
|
@ -2686,12 +2640,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
INIT_LIST_HEAD(&pcie->ports);
|
||||
pcie->dev = dev;
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &host->windows, NULL, &bus);
|
||||
if (err) {
|
||||
dev_err(dev, "Getting bridge resources failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegra_pcie_parse_dt(pcie);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -2715,26 +2663,15 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
goto pm_runtime_put;
|
||||
}
|
||||
|
||||
host->busnr = bus->start;
|
||||
host->dev.parent = &pdev->dev;
|
||||
host->ops = &tegra_pcie_ops;
|
||||
host->map_irq = tegra_pcie_map_irq;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
err = pci_scan_root_bus_bridge(host);
|
||||
err = pci_host_probe(host);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to register host: %d\n", err);
|
||||
goto pm_runtime_put;
|
||||
}
|
||||
|
||||
pci_bus_size_bridges(host->bus);
|
||||
pci_bus_assign_resources(host->bus);
|
||||
|
||||
list_for_each_entry(child, &host->bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(host->bus);
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
||||
err = tegra_pcie_debugfs_init(pcie);
|
||||
if (err < 0)
|
||||
|
|
|
@ -239,7 +239,6 @@ struct v3_pci {
|
|||
struct device *dev;
|
||||
void __iomem *base;
|
||||
void __iomem *config_base;
|
||||
struct pci_bus *bus;
|
||||
u32 config_mem;
|
||||
u32 non_pre_mem;
|
||||
u32 pre_mem;
|
||||
|
@ -585,8 +584,6 @@ static int v3_pci_setup_resource(struct v3_pci *v3,
|
|||
}
|
||||
break;
|
||||
case IORESOURCE_BUS:
|
||||
dev_dbg(dev, "BUS %pR\n", win->res);
|
||||
host->busnr = win->res->start;
|
||||
break;
|
||||
default:
|
||||
dev_info(dev, "Unknown resource type %lu\n",
|
||||
|
@ -724,12 +721,7 @@ static int v3_pci_probe(struct platform_device *pdev)
|
|||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
host->dev.parent = dev;
|
||||
host->ops = &v3_pci_ops;
|
||||
host->busnr = 0;
|
||||
host->msi = NULL;
|
||||
host->map_irq = of_irq_parse_and_map_pci;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
v3 = pci_host_bridge_priv(host);
|
||||
host->sysdata = v3;
|
||||
v3->dev = dev;
|
||||
|
@ -770,17 +762,11 @@ static int v3_pci_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(v3->config_base))
|
||||
return PTR_ERR(v3->config_base);
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
|
||||
&host->dma_ranges, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get and request error IRQ resource */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "unable to obtain PCIv3 error IRQ\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, v3_irq, 0,
|
||||
"PCIv3 error", v3);
|
||||
if (ret < 0) {
|
||||
|
@ -904,17 +890,7 @@ static int v3_pci_probe(struct platform_device *pdev)
|
|||
val |= V3_SYSTEM_M_LOCK;
|
||||
writew(val, v3->base + V3_SYSTEM);
|
||||
|
||||
ret = pci_scan_root_bus_bridge(host);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register host: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
v3->bus = host->bus;
|
||||
|
||||
pci_bus_assign_resources(v3->bus);
|
||||
pci_bus_add_devices(v3->bus);
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(host);
|
||||
}
|
||||
|
||||
static const struct of_device_id v3_pci_of_match[] = {
|
||||
|
|
|
@ -67,23 +67,20 @@ static int versatile_pci_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct resource_entry *entry;
|
||||
int ret, i, myslot = -1, mem = 1;
|
||||
int i, myslot = -1, mem = 1;
|
||||
u32 val;
|
||||
void __iomem *local_pci_cfg_base;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, 0);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
versatile_pci_base = devm_ioremap_resource(dev, res);
|
||||
versatile_pci_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(versatile_pci_base))
|
||||
return PTR_ERR(versatile_pci_base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
versatile_cfg_base[0] = devm_ioremap_resource(dev, res);
|
||||
versatile_cfg_base[0] = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(versatile_cfg_base[0]))
|
||||
return PTR_ERR(versatile_cfg_base[0]);
|
||||
|
||||
|
@ -92,11 +89,6 @@ static int versatile_pci_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(versatile_cfg_base[1]))
|
||||
return PTR_ERR(versatile_cfg_base[1]);
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
resource_list_for_each_entry(entry, &bridge->windows) {
|
||||
if (resource_type(entry->res) == IORESOURCE_MEM) {
|
||||
writel(entry->res->start >> 28, PCI_IMAP(mem));
|
||||
|
@ -154,28 +146,11 @@ static int versatile_pci_probe(struct platform_device *pdev)
|
|||
*/
|
||||
writel(0, versatile_cfg_base[0] + PCI_INTERRUPT_LINE);
|
||||
|
||||
pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = NULL;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &pci_versatile_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static const struct of_device_id versatile_pci_of_match[] = {
|
||||
|
|
|
@ -478,8 +478,6 @@ static int xgene_msi_probe(struct platform_device *pdev)
|
|||
for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) {
|
||||
virt_msir = platform_get_irq(pdev, irq_index);
|
||||
if (virt_msir < 0) {
|
||||
dev_err(&pdev->dev, "Cannot translate IRQ index %d\n",
|
||||
irq_index);
|
||||
rc = virt_msir;
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -355,8 +355,7 @@ static int xgene_pcie_map_reg(struct xgene_pcie_port *port,
|
|||
if (IS_ERR(port->csr_base))
|
||||
return PTR_ERR(port->csr_base);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
|
||||
port->cfg_base = devm_ioremap_resource(dev, res);
|
||||
port->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
|
||||
if (IS_ERR(port->cfg_base))
|
||||
return PTR_ERR(port->cfg_base);
|
||||
port->cfg_addr = res->start;
|
||||
|
@ -591,7 +590,6 @@ static int xgene_pcie_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct device_node *dn = dev->of_node;
|
||||
struct xgene_pcie_port *port;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
|
@ -616,33 +614,14 @@ static int xgene_pcie_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xgene_pcie_setup(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = port;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &xgene_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static const struct of_device_id xgene_pcie_match_table[] = {
|
||||
|
|
|
@ -228,8 +228,7 @@ static int altera_msi_probe(struct platform_device *pdev)
|
|||
mutex_init(&msi->lock);
|
||||
msi->pdev = pdev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
|
||||
msi->csr_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
msi->csr_base = devm_platform_ioremap_resource_byname(pdev, "csr");
|
||||
if (IS_ERR(msi->csr_base)) {
|
||||
dev_err(&pdev->dev, "failed to map csr memory\n");
|
||||
return PTR_ERR(msi->csr_base);
|
||||
|
@ -256,7 +255,6 @@ static int altera_msi_probe(struct platform_device *pdev)
|
|||
|
||||
msi->irq = platform_get_irq(pdev, 0);
|
||||
if (msi->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to map IRQ: %d\n", msi->irq);
|
||||
ret = msi->irq;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -694,29 +694,23 @@ static void altera_pcie_irq_teardown(struct altera_pcie *pcie)
|
|||
|
||||
static int altera_pcie_parse_dt(struct altera_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct platform_device *pdev = pcie->pdev;
|
||||
struct resource *cra;
|
||||
struct resource *hip;
|
||||
|
||||
cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra");
|
||||
pcie->cra_base = devm_ioremap_resource(dev, cra);
|
||||
pcie->cra_base = devm_platform_ioremap_resource_byname(pdev, "Cra");
|
||||
if (IS_ERR(pcie->cra_base))
|
||||
return PTR_ERR(pcie->cra_base);
|
||||
|
||||
if (pcie->pcie_data->version == ALTERA_PCIE_V2) {
|
||||
hip = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Hip");
|
||||
pcie->hip_base = devm_ioremap_resource(&pdev->dev, hip);
|
||||
pcie->hip_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "Hip");
|
||||
if (IS_ERR(pcie->hip_base))
|
||||
return PTR_ERR(pcie->hip_base);
|
||||
}
|
||||
|
||||
/* setup IRQ */
|
||||
pcie->irq = platform_get_irq(pdev, 0);
|
||||
if (pcie->irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ: %d\n", pcie->irq);
|
||||
if (pcie->irq < 0)
|
||||
return pcie->irq;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie);
|
||||
return 0;
|
||||
|
@ -773,8 +767,6 @@ static int altera_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct altera_pcie *pcie;
|
||||
struct pci_bus *bus;
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
|
@ -799,13 +791,6 @@ static int altera_pcie_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed add resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = altera_pcie_init_irq_domain(pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed creating IRQ Domain\n");
|
||||
|
@ -818,27 +803,11 @@ static int altera_pcie_probe(struct platform_device *pdev)
|
|||
cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
|
||||
altera_pcie_host_init(pcie);
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->busnr = pcie->root_bus_nr;
|
||||
bridge->ops = &altera_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
|
||||
/* Configure PCI Express setting. */
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
return ret;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static int altera_pcie_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -172,7 +172,6 @@ struct brcm_pcie {
|
|||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct pci_bus *root_bus;
|
||||
struct device_node *np;
|
||||
bool ssc;
|
||||
int gen;
|
||||
|
@ -919,9 +918,10 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
|
|||
static int brcm_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct brcm_pcie *pcie = platform_get_drvdata(pdev);
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||
|
||||
pci_stop_root_bus(pcie->root_bus);
|
||||
pci_remove_root_bus(pcie->root_bus);
|
||||
pci_stop_root_bus(bridge->bus);
|
||||
pci_remove_root_bus(bridge->bus);
|
||||
__brcm_pcie_remove(pcie);
|
||||
|
||||
return 0;
|
||||
|
@ -933,8 +933,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||
struct pci_host_bridge *bridge;
|
||||
struct device_node *fw_np;
|
||||
struct brcm_pcie *pcie;
|
||||
struct pci_bus *child;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -959,8 +957,7 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||
pcie->dev = &pdev->dev;
|
||||
pcie->np = np;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pcie->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pcie->base))
|
||||
return PTR_ERR(pcie->base);
|
||||
|
||||
|
@ -973,11 +970,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(pcie->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "could not enable clock\n");
|
||||
|
@ -997,27 +989,12 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
bridge->dev.parent = &pdev->dev;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &brcm_pcie_ops;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0) {
|
||||
dev_err(pcie->dev, "Scanning root bridge failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pci_assign_unassigned_bus_resources(bridge->bus);
|
||||
list_for_each_entry(child, &bridge->bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bridge->bus);
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
pcie->root_bus = bridge->bus;
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
fail:
|
||||
__brcm_pcie_remove(pcie);
|
||||
return ret;
|
||||
|
|
|
@ -95,20 +95,14 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(pcie->phy))
|
||||
return PTR_ERR(pcie->phy);
|
||||
|
||||
ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to get PCI host bridge resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PAXC doesn't support legacy IRQs, skip mapping */
|
||||
switch (pcie->type) {
|
||||
case IPROC_PCIE_PAXC:
|
||||
case IPROC_PCIE_PAXC_V2:
|
||||
pcie->map_irq = 0;
|
||||
break;
|
||||
default:
|
||||
pcie->map_irq = of_irq_parse_and_map_pci;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = iproc_pcie_setup(pcie, &bridge->windows);
|
||||
|
|
|
@ -1470,7 +1470,6 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
|||
{
|
||||
struct device *dev;
|
||||
int ret;
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
|
||||
|
||||
dev = pcie->dev;
|
||||
|
@ -1524,28 +1523,16 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
|||
if (iproc_pcie_msi_enable(pcie))
|
||||
dev_info(dev, "not using iProc MSI\n");
|
||||
|
||||
host->busnr = 0;
|
||||
host->dev.parent = dev;
|
||||
host->ops = &iproc_pcie_ops;
|
||||
host->sysdata = pcie;
|
||||
host->map_irq = pcie->map_irq;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(host);
|
||||
ret = pci_host_probe(host);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to scan host: %d\n", ret);
|
||||
goto err_power_off_phy;
|
||||
}
|
||||
|
||||
pci_assign_unassigned_bus_resources(host->bus);
|
||||
|
||||
pcie->root_bus = host->bus;
|
||||
|
||||
list_for_each_entry(child, &host->bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(host->bus);
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off_phy:
|
||||
|
@ -1558,8 +1545,10 @@ EXPORT_SYMBOL(iproc_pcie_setup);
|
|||
|
||||
int iproc_pcie_remove(struct iproc_pcie *pcie)
|
||||
{
|
||||
pci_stop_root_bus(pcie->root_bus);
|
||||
pci_remove_root_bus(pcie->root_bus);
|
||||
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
|
||||
|
||||
pci_stop_root_bus(host->bus);
|
||||
pci_remove_root_bus(host->bus);
|
||||
|
||||
iproc_pcie_msi_disable(pcie);
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ struct iproc_msi;
|
|||
* @reg_offsets: register offsets
|
||||
* @base: PCIe host controller I/O register base
|
||||
* @base_addr: PCIe host controller register base physical address
|
||||
* @root_bus: pointer to root bus
|
||||
* @phy: optional PHY device that controls the Serdes
|
||||
* @map_irq: function callback to map interrupts
|
||||
* @ep_is_internal: indicates an internal emulated endpoint device is connected
|
||||
|
@ -85,7 +84,6 @@ struct iproc_pcie {
|
|||
void __iomem *base;
|
||||
phys_addr_t base_addr;
|
||||
struct resource mem;
|
||||
struct pci_bus *root_bus;
|
||||
struct phy *phy;
|
||||
int (*map_irq)(const struct pci_dev *, u8, u8);
|
||||
bool ep_is_internal;
|
||||
|
|
|
@ -209,7 +209,6 @@ struct mtk_pcie_port {
|
|||
* @mem: non-prefetchable memory resource
|
||||
* @ports: pointer to PCIe port information
|
||||
* @soc: pointer to SoC-dependent operations
|
||||
* @busnr: root bus number
|
||||
*/
|
||||
struct mtk_pcie {
|
||||
struct device *dev;
|
||||
|
@ -218,7 +217,6 @@ struct mtk_pcie {
|
|||
|
||||
struct list_head ports;
|
||||
const struct mtk_pcie_soc *soc;
|
||||
unsigned int busnr;
|
||||
};
|
||||
|
||||
static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
|
||||
|
@ -905,7 +903,6 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
|
|||
int slot)
|
||||
{
|
||||
struct mtk_pcie_port *port;
|
||||
struct resource *regs;
|
||||
struct device *dev = pcie->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
char name[10];
|
||||
|
@ -916,8 +913,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
|
|||
return -ENOMEM;
|
||||
|
||||
snprintf(name, sizeof(name), "port%d", slot);
|
||||
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
port->base = devm_ioremap_resource(dev, regs);
|
||||
port->base = devm_platform_ioremap_resource_byname(pdev, name);
|
||||
if (IS_ERR(port->base)) {
|
||||
dev_err(dev, "failed to map port%d base\n", slot);
|
||||
return PTR_ERR(port->base);
|
||||
|
@ -1031,18 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
|
|||
struct device *dev = pcie->dev;
|
||||
struct device_node *node = dev->of_node, *child;
|
||||
struct mtk_pcie_port *port, *tmp;
|
||||
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
|
||||
struct list_head *windows = &host->windows;
|
||||
struct resource *bus;
|
||||
int err;
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, windows,
|
||||
&host->dma_ranges, &bus);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pcie->busnr = bus->start;
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
int slot;
|
||||
|
||||
|
@ -1096,11 +1082,7 @@ static int mtk_pcie_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
host->busnr = pcie->busnr;
|
||||
host->dev.parent = pcie->dev;
|
||||
host->ops = pcie->soc->ops;
|
||||
host->map_irq = of_irq_parse_and_map_pci;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
host->sysdata = pcie;
|
||||
|
||||
err = pci_host_probe(host);
|
||||
|
|
|
@ -53,8 +53,6 @@ struct rcar_pcie_host {
|
|||
struct device *dev;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
struct list_head resources;
|
||||
int root_bus_nr;
|
||||
struct clk *bus_clk;
|
||||
struct rcar_msi msi;
|
||||
int (*phy_init_fn)(struct rcar_pcie_host *host);
|
||||
|
@ -100,22 +98,14 @@ static int rcar_pcie_config_access(struct rcar_pcie_host *host,
|
|||
if (dev != 0)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (access_type == RCAR_PCI_ACCESS_READ) {
|
||||
if (access_type == RCAR_PCI_ACCESS_READ)
|
||||
*data = rcar_pci_read_reg(pcie, PCICONF(index));
|
||||
} else {
|
||||
/* Keep an eye out for changes to the root bus number */
|
||||
if (pci_is_root_bus(bus) && (reg == PCI_PRIMARY_BUS))
|
||||
host->root_bus_nr = *data & 0xff;
|
||||
|
||||
else
|
||||
rcar_pci_write_reg(pcie, *data, PCICONF(index));
|
||||
}
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
if (host->root_bus_nr < 0)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
/* Clear errors */
|
||||
rcar_pci_write_reg(pcie, rcar_pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
|
||||
|
||||
|
@ -124,7 +114,7 @@ static int rcar_pcie_config_access(struct rcar_pcie_host *host,
|
|||
PCIE_CONF_DEV(dev) | PCIE_CONF_FUNC(func) | reg, PCIECAR);
|
||||
|
||||
/* Enable the configuration access */
|
||||
if (bus->parent->number == host->root_bus_nr)
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR);
|
||||
else
|
||||
rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR);
|
||||
|
@ -212,38 +202,6 @@ static struct pci_ops rcar_pcie_ops = {
|
|||
.write = rcar_pcie_write_conf,
|
||||
};
|
||||
|
||||
static int rcar_pcie_setup(struct list_head *resource,
|
||||
struct rcar_pcie_host *host)
|
||||
{
|
||||
struct resource_entry *win;
|
||||
int i = 0;
|
||||
|
||||
/* Setup PCI resources */
|
||||
resource_list_for_each_entry(win, &host->resources) {
|
||||
struct resource *res = win->res;
|
||||
|
||||
if (!res->flags)
|
||||
continue;
|
||||
|
||||
switch (resource_type(res)) {
|
||||
case IORESOURCE_IO:
|
||||
case IORESOURCE_MEM:
|
||||
rcar_pcie_set_outbound(&host->pcie, i, win);
|
||||
i++;
|
||||
break;
|
||||
case IORESOURCE_BUS:
|
||||
host->root_bus_nr = res->start;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
pci_add_resource(resource, res);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void rcar_pcie_force_speedup(struct rcar_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
|
@ -301,6 +259,7 @@ done:
|
|||
static void rcar_pcie_hw_enable(struct rcar_pcie_host *host)
|
||||
{
|
||||
struct rcar_pcie *pcie = &host->pcie;
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
|
||||
struct resource_entry *win;
|
||||
LIST_HEAD(res);
|
||||
int i = 0;
|
||||
|
@ -309,7 +268,7 @@ static void rcar_pcie_hw_enable(struct rcar_pcie_host *host)
|
|||
rcar_pcie_force_speedup(pcie);
|
||||
|
||||
/* Setup PCI resources */
|
||||
resource_list_for_each_entry(win, &host->resources) {
|
||||
resource_list_for_each_entry(win, &bridge->windows) {
|
||||
struct resource *res = win->res;
|
||||
|
||||
if (!res->flags)
|
||||
|
@ -328,42 +287,17 @@ static void rcar_pcie_hw_enable(struct rcar_pcie_host *host)
|
|||
static int rcar_pcie_enable(struct rcar_pcie_host *host)
|
||||
{
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
|
||||
struct rcar_pcie *pcie = &host->pcie;
|
||||
struct device *dev = pcie->dev;
|
||||
struct pci_bus *bus, *child;
|
||||
int ret;
|
||||
|
||||
/* Try setting 5 GT/s link speed */
|
||||
rcar_pcie_force_speedup(pcie);
|
||||
|
||||
rcar_pcie_setup(&bridge->windows, host);
|
||||
rcar_pcie_hw_enable(host);
|
||||
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = host;
|
||||
bridge->busnr = host->root_bus_nr;
|
||||
bridge->ops = &rcar_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
bridge->msi = &host->msi.chip;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static int phy_wait_for_ack(struct rcar_pcie *pcie)
|
||||
|
@ -968,7 +902,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|||
int err;
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = pci_alloc_host_bridge(sizeof(*host));
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*host));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -977,16 +911,11 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|||
pcie->dev = dev;
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &host->resources,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (err)
|
||||
goto err_free_bridge;
|
||||
|
||||
pm_runtime_enable(pcie->dev);
|
||||
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);
|
||||
|
@ -1057,13 +986,7 @@ err_unmap_msi_irqs:
|
|||
|
||||
err_pm_put:
|
||||
pm_runtime_put(dev);
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
pci_free_resource_list(&host->resources);
|
||||
|
||||
err_free_bridge:
|
||||
pci_free_host_bridge(bridge);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
/**
|
||||
* struct rockchip_pcie_ep - private data for PCIe endpoint controller driver
|
||||
* @rockchip: Rockchip PCIe controller
|
||||
* @epc: PCI EPC device
|
||||
* @max_regions: maximum number of regions supported by hardware
|
||||
* @ob_region_map: bitmask of mapped outbound regions
|
||||
* @ob_addr: base addresses in the AXI bus where the outbound regions start
|
||||
|
|
|
@ -72,14 +72,14 @@ static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip,
|
|||
struct pci_bus *bus, int dev)
|
||||
{
|
||||
/* access only one slot on each root port */
|
||||
if (bus->number == rockchip->root_bus_nr && dev > 0)
|
||||
if (pci_is_root_bus(bus) && dev > 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* do not read more than one device on the bus directly attached
|
||||
* to RC's downstream side.
|
||||
*/
|
||||
if (bus->primary == rockchip->root_bus_nr && dev > 0)
|
||||
if (pci_is_root_bus(bus->parent) && dev > 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
@ -170,7 +170,7 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
|
|||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
}
|
||||
|
||||
if (bus->parent->number == rockchip->root_bus_nr)
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
rockchip_pcie_cfg_configuration_accesses(rockchip,
|
||||
AXI_WRAPPER_TYPE0_CFG);
|
||||
else
|
||||
|
@ -201,7 +201,7 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
|
|||
if (!IS_ALIGNED(busdev, size))
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
|
||||
if (bus->parent->number == rockchip->root_bus_nr)
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
rockchip_pcie_cfg_configuration_accesses(rockchip,
|
||||
AXI_WRAPPER_TYPE0_CFG);
|
||||
else
|
||||
|
@ -230,7 +230,7 @@ static int rockchip_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
|||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (bus->number == rockchip->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return rockchip_pcie_rd_own_conf(rockchip, where, size, val);
|
||||
|
||||
return rockchip_pcie_rd_other_conf(rockchip, bus, devfn, where, size,
|
||||
|
@ -245,7 +245,7 @@ static int rockchip_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
|||
if (!rockchip_pcie_valid_device(rockchip, bus, PCI_SLOT(devfn)))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (bus->number == rockchip->root_bus_nr)
|
||||
if (pci_is_root_bus(bus))
|
||||
return rockchip_pcie_wr_own_conf(rockchip, where, size, val);
|
||||
|
||||
return rockchip_pcie_wr_other_conf(rockchip, bus, devfn, where, size,
|
||||
|
@ -549,10 +549,8 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "sys");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing sys IRQ resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
|
||||
IRQF_SHARED, "pcie-sys", rockchip);
|
||||
|
@ -562,20 +560,16 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "legacy");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing legacy IRQ resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(irq,
|
||||
rockchip_pcie_legacy_int_handler,
|
||||
rockchip);
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "client");
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing client IRQ resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
|
||||
IRQF_SHARED, "pcie-client", rockchip);
|
||||
|
@ -949,9 +943,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct rockchip_pcie *rockchip;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource *bus_res;
|
||||
int err;
|
||||
|
||||
if (!dev->of_node)
|
||||
|
@ -991,13 +983,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|||
if (err < 0)
|
||||
goto err_deinit_port;
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, &bus_res);
|
||||
if (err)
|
||||
goto err_remove_irq_domain;
|
||||
|
||||
rockchip->root_bus_nr = bus_res->start;
|
||||
|
||||
err = rockchip_pcie_cfg_atu(rockchip);
|
||||
if (err)
|
||||
goto err_remove_irq_domain;
|
||||
|
@ -1008,27 +993,13 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|||
goto err_remove_irq_domain;
|
||||
}
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = rockchip;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &rockchip_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
err = pci_scan_root_bus_bridge(bridge);
|
||||
err = pci_host_probe(bridge);
|
||||
if (err < 0)
|
||||
goto err_remove_irq_domain;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
rockchip->root_bus = bus;
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
|
||||
err_remove_irq_domain:
|
||||
|
@ -1051,9 +1022,10 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rockchip);
|
||||
|
||||
pci_stop_root_bus(rockchip->root_bus);
|
||||
pci_remove_root_bus(rockchip->root_bus);
|
||||
pci_stop_root_bus(bridge->bus);
|
||||
pci_remove_root_bus(bridge->bus);
|
||||
irq_domain_remove(rockchip->irq_domain);
|
||||
|
||||
rockchip_pcie_deinit_phys(rockchip);
|
||||
|
|
|
@ -45,9 +45,8 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"apb-base");
|
||||
rockchip->apb_base = devm_ioremap_resource(dev, regs);
|
||||
rockchip->apb_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "apb-base");
|
||||
if (IS_ERR(rockchip->apb_base))
|
||||
return PTR_ERR(rockchip->apb_base);
|
||||
|
||||
|
|
|
@ -298,12 +298,10 @@ struct rockchip_pcie {
|
|||
struct gpio_desc *ep_gpio;
|
||||
u32 lanes;
|
||||
u8 lanes_map;
|
||||
u8 root_bus_nr;
|
||||
int link_gen;
|
||||
struct device *dev;
|
||||
struct irq_domain *irq_domain;
|
||||
int offset;
|
||||
struct pci_bus *root_bus;
|
||||
void __iomem *msg_region;
|
||||
phys_addr_t msg_bus_addr;
|
||||
bool is_rc;
|
||||
|
|
|
@ -273,10 +273,8 @@ static int tango_pcie_probe(struct platform_device *pdev)
|
|||
writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset);
|
||||
|
||||
virq = platform_get_irq(pdev, 1);
|
||||
if (virq < 0) {
|
||||
dev_err(dev, "Failed to map IRQ\n");
|
||||
if (virq < 0)
|
||||
return virq;
|
||||
}
|
||||
|
||||
irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie);
|
||||
if (!irq_dom) {
|
||||
|
|
611
drivers/pci/controller/pcie-xilinx-cpm.c
Normal file
611
drivers/pci/controller/pcie-xilinx-cpm.c
Normal file
|
@ -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);
|
|
@ -166,7 +166,6 @@ struct nwl_pcie {
|
|||
int irq_misc;
|
||||
u32 ecam_value;
|
||||
u8 last_busno;
|
||||
u8 root_busno;
|
||||
struct nwl_msi msi;
|
||||
struct irq_domain *legacy_irq_domain;
|
||||
raw_spinlock_t leg_mask_lock;
|
||||
|
@ -217,13 +216,11 @@ static bool nwl_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
|
|||
struct nwl_pcie *pcie = bus->sysdata;
|
||||
|
||||
/* Check link before accessing downstream ports */
|
||||
if (bus->number != pcie->root_busno) {
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
if (!nwl_pcie_link_up(pcie))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Only one device down on each root port */
|
||||
if (bus->number == pcie->root_busno && devfn > 0)
|
||||
} else if (devfn > 0)
|
||||
/* Only one device down on each root port */
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -586,7 +583,6 @@ static int nwl_pcie_enable_msi(struct nwl_pcie *pcie)
|
|||
/* Get msi_1 IRQ number */
|
||||
msi->irq_msi1 = platform_get_irq_byname(pdev, "msi1");
|
||||
if (msi->irq_msi1 < 0) {
|
||||
dev_err(dev, "failed to get IRQ#%d\n", msi->irq_msi1);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -597,7 +593,6 @@ static int nwl_pcie_enable_msi(struct nwl_pcie *pcie)
|
|||
/* Get msi_0 IRQ number */
|
||||
msi->irq_msi0 = platform_get_irq_byname(pdev, "msi0");
|
||||
if (msi->irq_msi0 < 0) {
|
||||
dev_err(dev, "failed to get IRQ#%d\n", msi->irq_msi0);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
@ -728,11 +723,8 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
|
|||
|
||||
/* Get misc IRQ number */
|
||||
pcie->irq_misc = platform_get_irq_byname(pdev, "misc");
|
||||
if (pcie->irq_misc < 0) {
|
||||
dev_err(dev, "failed to get misc IRQ %d\n",
|
||||
pcie->irq_misc);
|
||||
if (pcie->irq_misc < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, pcie->irq_misc,
|
||||
nwl_pcie_misc_handler, IRQF_SHARED,
|
||||
|
@ -797,10 +789,8 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie,
|
|||
|
||||
/* Get intx IRQ number */
|
||||
pcie->irq_intx = platform_get_irq_byname(pdev, "intx");
|
||||
if (pcie->irq_intx < 0) {
|
||||
dev_err(dev, "failed to get intx IRQ %d\n", pcie->irq_intx);
|
||||
if (pcie->irq_intx < 0)
|
||||
return pcie->irq_intx;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(pcie->irq_intx,
|
||||
nwl_pcie_leg_handler, pcie);
|
||||
|
@ -817,8 +807,6 @@ static int nwl_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct nwl_pcie *pcie;
|
||||
struct pci_bus *bus;
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
int err;
|
||||
|
||||
|
@ -843,25 +831,14 @@ static int nwl_pcie_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (err) {
|
||||
dev_err(dev, "Getting bridge resources failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nwl_pcie_init_irq_domain(pcie);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed creating IRQ Domain\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
bridge->busnr = pcie->root_busno;
|
||||
bridge->ops = &nwl_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
err = nwl_pcie_enable_msi(pcie);
|
||||
|
@ -871,17 +848,7 @@ static int nwl_pcie_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
err = pci_scan_root_bus_bridge(bridge);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static struct platform_driver nwl_pcie_driver = {
|
||||
|
|
|
@ -98,7 +98,6 @@
|
|||
* @reg_base: IO Mapped Register Base
|
||||
* @irq: Interrupt number
|
||||
* @msi_pages: MSI pages
|
||||
* @root_busno: Root Bus number
|
||||
* @dev: Device pointer
|
||||
* @msi_domain: MSI IRQ domain pointer
|
||||
* @leg_domain: Legacy IRQ domain pointer
|
||||
|
@ -108,7 +107,6 @@ struct xilinx_pcie_port {
|
|||
void __iomem *reg_base;
|
||||
u32 irq;
|
||||
unsigned long msi_pages;
|
||||
u8 root_busno;
|
||||
struct device *dev;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *leg_domain;
|
||||
|
@ -162,14 +160,13 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
|
|||
struct xilinx_pcie_port *port = bus->sysdata;
|
||||
|
||||
/* Check if link is up when trying to access downstream ports */
|
||||
if (bus->number != port->root_busno)
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
if (!xilinx_pcie_link_up(port))
|
||||
return false;
|
||||
|
||||
/* Only one device down on each root port */
|
||||
if (bus->number == port->root_busno && devfn > 0)
|
||||
} else if (devfn > 0) {
|
||||
/* Only one device down on each root port */
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -616,7 +613,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct xilinx_pcie_port *port;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
int err;
|
||||
|
||||
|
@ -645,35 +641,14 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
|
||||
&bridge->dma_ranges, NULL);
|
||||
if (err) {
|
||||
dev_err(dev, "Getting bridge resources failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = port;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &xilinx_pcie_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
xilinx_pcie_msi_chip.dev = dev;
|
||||
bridge->msi = &xilinx_pcie_msi_chip;
|
||||
#endif
|
||||
err = pci_scan_root_bus_bridge(bridge);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static const struct of_device_id xilinx_pcie_of_match[] = {
|
||||
|
|
|
@ -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, ®);
|
||||
|
||||
/* "SHDW" */
|
||||
if (pos && reg == 0x53484457) {
|
||||
pci_read_config_dword(vmd->dev, pos + 8, ®);
|
||||
pci_read_config_dword(vmd->dev, pos + 12, ®u);
|
||||
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, ®);
|
||||
pci_read_config_dword(vmd->dev, pos + 20, ®u);
|
||||
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
|
||||
|
@ -720,16 +748,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);
|
||||
|
|
|
@ -181,7 +181,7 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
|
|||
|
||||
/**
|
||||
* pci_epf_test_clean_dma_chan() - Function to cleanup EPF test DMA channel
|
||||
* @epf: the EPF test device that performs data transfer operation
|
||||
* @epf_test: the EPF test device that performs data transfer operation
|
||||
*
|
||||
* Helper to cleanup EPF test DMA channel.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* configfs to configure the PCI endpoint
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* PCI Endpoint *Controller* (EPC) library
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* PCI Endpoint *Controller* Address Space Management
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
/*
|
||||
* PCI Endpoint *Function* (EPF) library
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
|
@ -71,6 +71,7 @@ EXPORT_SYMBOL_GPL(pci_epf_bind);
|
|||
|
||||
/**
|
||||
* pci_epf_free_space() - free the allocated PCI EPF register space
|
||||
* @epf: the EPF device from whom to free the memory
|
||||
* @addr: the virtual address of the PCI EPF register space
|
||||
* @bar: the BAR number corresponding to the register space
|
||||
*
|
||||
|
@ -96,6 +97,7 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
|
|||
|
||||
/**
|
||||
* pci_epf_alloc_space() - allocate memory for the PCI EPF register space
|
||||
* @epf: the EPF device to whom allocate the memory
|
||||
* @size: the size of the memory that has to be allocated
|
||||
* @bar: the BAR number corresponding to the allocated register space
|
||||
* @align: alignment size for the allocation region
|
||||
|
|
|
@ -61,7 +61,7 @@ static acpi_status acpi_run_oshp(acpi_handle handle)
|
|||
|
||||
/**
|
||||
* acpi_get_hp_hw_control_from_firmware
|
||||
* @dev: the pci_dev of the bridge that has a hotplug controller
|
||||
* @pdev: the pci_dev of the bridge that has a hotplug controller
|
||||
*
|
||||
* Attempt to take hotplug control from firmware.
|
||||
*/
|
||||
|
@ -191,7 +191,7 @@ check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
|
||||
/**
|
||||
* acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots
|
||||
* @handle - handle of the PCI bus to scan
|
||||
* @handle: handle of the PCI bus to scan
|
||||
*
|
||||
* Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise.
|
||||
*/
|
||||
|
|
|
@ -153,6 +153,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
|||
|
||||
/**
|
||||
* pciehp_check_presence() - synthesize event if presence has changed
|
||||
* @ctrl: controller to check
|
||||
*
|
||||
* On probe and resume, an explicit presence check is necessary to bring up an
|
||||
* occupied slot or bring down an unoccupied slot. This can't be triggered by
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue