mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-15 08:44:14 +08:00
pci-v5.10-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAl+QUFkUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vw6SQ/9FHiAlHIa48/l5ZweqAuN3XnU8hoO sqMoJE8eqTkIYIT0aQdW6b1sDB0YE6b4UVxzg+UL/E0qYeJqgIUakig7QkyyF1qU aT5hq2ic+lk88G7AAxK3kgQGPk+JvP1EFIyOu6HBWzzDDzgLme1Iuh/5ulc2/lo+ E4biy0WOnI8vMfCieXGK4bSpc17Rn0+3N4cuVwZXBlntsvicE90VqeWBzqti1sk5 R6gkZuW+EIUNHHL7TLlkCeYZq6QNbXWzhfKCiaGW2wW4eJ4Ek1/ncQjyTbCFytKU 7OIYvrH20XO3L5GEfJ5fdbWErI1dRpoHO4NmhWljyBcVh44VYnM2ixhA7TuJ+TOk OtMbtoJAlP+QDlVdAW6rmRYmMPLFK/AQl5Aq7ftY22b2rYXqP20BobPy2MpDT71T sGC8z0ABl/ijo23g3I+3/2VzP/RzGhZJ0ZqagrXj8jHtg8SVy2fLcR5nr/dlrgFk TG83zML6ui1KViyx5nzElaEtw18aTqP61CNQxijQtNoYwKBTtRKNTrdRr4Qo7Hi6 6S+No3+4z8Kf8d90y0LkJQqr7JRkG6nI3AhXHO3rxXpXJOD2+QzlpwBZTQnASqq7 3kC1doUPmN97rFUYPQWWyOs6xSMcGbGIz8Uus3shH6yDtNxgpnIVoctH55hTEh6w nSY/4ssIfzJxZCE= =RCFo -----END PGP SIGNATURE----- Merge tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: "Enumeration: - Print IRQ number used by PCIe Link Bandwidth Notification (Dongdong Liu) - Add schedule point in pci_read_config() to reduce max latency (Jiang Biao) - Add Kconfig options for MPS/MRRS strategy (Jim Quinlan) Resource management: - Fix pci_iounmap() memory leak when !CONFIG_GENERIC_IOMAP (Lorenzo Pieralisi) PCIe native device hotplug: - Reduce noisiness on hot removal (Lukas Wunner) Power management: - Revert "PCI/PM: Apply D2 delay as milliseconds, not microseconds" that was done on the basis of spec typo (Bjorn Helgaas) - Rename pci_dev.d3_delay to d3hot_delay to remove D3hot/D3cold ambiguity (Krzysztof Wilczyński) - Remove unused pcibios_pm_ops (Vaibhav Gupta) IOMMU: - Enable Translation Blocking for external devices to harden against DMA attacks (Rajat Jain) Error handling: - Add an ACPI APEI notifier chain for vendor CPER records to enable device-specific error handling (Shiju Jose) ASPM: - Remove struct aspm_register_info to simplify code (Saheed O. Bolarinwa) Amlogic Meson PCIe controller driver: - Build as module by default (Kevin Hilman) Ampere Altra PCIe controller driver: - Add MCFG quirk to work around non-standard ECAM implementation (Tuan Phan) Broadcom iProc PCIe controller driver: - Set affinity mask on MSI interrupts (Mark Tomlinson) Broadcom STB PCIe controller driver: - Make PCIE_BRCMSTB depend on ARCH_BRCMSTB (Jim Quinlan) - Add DT bindings for more Brcmstb chips (Jim Quinlan) - Add bcm7278 register info (Jim Quinlan) - Add bcm7278 PERST# support (Jim Quinlan) - Add suspend and resume pm_ops (Jim Quinlan) - Add control of rescal reset (Jim Quinlan) - Set additional internal memory DMA viewport sizes (Jim Quinlan) - Accommodate MSI for older chips (Jim Quinlan) - Set bus max burst size by chip type (Jim Quinlan) - Add support for bcm7211, bcm7216, bcm7445, bcm7278 (Jim Quinlan) Freescale i.MX6 PCIe controller driver: - Use dev_err_probe() to reduce redundant messages (Anson Huang) Freescale Layerscape PCIe controller driver: - Enforce 4K DMA buffer alignment in endpoint test (Hou Zhiqiang) - Add DT compatible strings for ls1088a, ls2088a (Xiaowei Bao) - Add endpoint support for ls1088a, ls2088a (Xiaowei Bao) - Add endpoint test support for lS1088a (Xiaowei Bao) - Add MSI-X support for ls1088a (Xiaowei Bao) HiSilicon HIP PCIe controller driver: - Handle HIP-specific errors via ACPI APEI (Yicong Yang) HiSilicon Kirin PCIe controller driver: - Return -EPROBE_DEFER if the GPIO isn't ready (Bean Huo) Intel VMD host bridge driver: - Factor out physical offset, bus offset, IRQ domain, IRQ allocation (Jon Derrick) - Use generic PCI PM correctly (Jon Derrick) Marvell Aardvark PCIe controller driver: - Fix compilation on s390 (Pali Rohár) - Implement driver 'remove' function and allow to build it as module (Pali Rohár) - Move PCIe reset card code to advk_pcie_train_link() (Pali Rohár) - Convert mvebu a3700 internal SMCC firmware return codes to errno (Pali Rohár) - Fix initialization with old Marvell's Arm Trusted Firmware (Pali Rohár) Microsoft Hyper-V host bridge driver: - Fix hibernation in case interrupts are not re-created (Dexuan Cui) NVIDIA Tegra PCIe controller driver: - Stop checking return value of debugfs_create() functions (Greg Kroah-Hartman) - Convert to use DEFINE_SEQ_ATTRIBUTE macro (Liu Shixin) Qualcomm PCIe controller driver: - Reset PCIe to work around Qsdk U-Boot issue (Ansuel Smith) Renesas R-Car PCIe controller driver: - Add DT documentation for r8a774a1, r8a774b1, r8a774e1 endpoints (Lad Prabhakar) - Add RZ/G2M, RZ/G2N, RZ/G2H IDs to endpoint test (Lad Prabhakar) - Add DT support for r8a7742 (Lad Prabhakar) Socionext UniPhier Pro5 controller driver: - Add DT descriptions of iATU register (host and endpoint) (Kunihiko Hayashi) Synopsys DesignWare PCIe controller driver: - Add link up check in dw_child_pcie_ops.map_bus() (racy, but seems unavoidable) (Hou Zhiqiang) - Fix endpoint Header Type check so multi-function devices work (Hou Zhiqiang) - Skip PCIE_MSI_INTR0* programming if MSI is disabled (Jisheng Zhang) - Stop leaking MSI page in suspend/resume (Jisheng Zhang) - Add common iATU register support instead of keystone-specific code (Kunihiko Hayashi) - Major config space access and other cleanups in dwc core and drivers that use it (al, exynos, histb, imx6, intel-gw, keystone, kirin, meson, qcom, tegra) (Rob Herring) - Add multiple PFs support for endpoint (Xiaowei Bao) - Add MSI-X doorbell mode in endpoint mode (Xiaowei Bao) Miscellaneous: - Use fallthrough pseudo-keyword (Gustavo A. R. Silva) - Fix "0 used as NULL pointer" warnings (Gustavo Pimentel) - Fix "cast truncates bits from constant value" warnings (Gustavo Pimentel) - Remove redundant zeroing for sg_init_table() (Julia Lawall) - Use scnprintf(), not snprintf(), in sysfs "show" functions (Krzysztof Wilczyński) - Remove unused assignments (Krzysztof Wilczyński) - Fix "0 used as NULL pointer" warning (Krzysztof Wilczyński) - Simplify bool comparisons (Krzysztof Wilczyński) - Use for_each_child_of_node() and for_each_node_by_name() (Qinglang Miao) - Simplify return expressions (Qinglang Miao)" * tag 'pci-v5.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (147 commits) PCI: vmd: Update VMD PM to correctly use generic PCI PM PCI: vmd: Create IRQ allocation helper PCI: vmd: Create IRQ Domain configuration helper PCI: vmd: Create bus offset configuration helper PCI: vmd: Create physical offset helper PCI: v3-semi: Remove unneeded break PCI: dwc: Add link up check in dw_child_pcie_ops.map_bus() PCI/ASPM: Remove struct pcie_link_state.l1ss PCI/ASPM: Remove struct aspm_register_info.l1ss_cap PCI/ASPM: Pass L1SS Capabilities value, not struct aspm_register_info PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl1 PCI/ASPM: Remove struct aspm_register_info.l1ss_ctl2 (unused) PCI/ASPM: Remove struct aspm_register_info.l1ss_cap_ptr PCI/ASPM: Remove struct aspm_register_info.latency_encoding PCI/ASPM: Remove struct aspm_register_info.enabled PCI/ASPM: Remove struct aspm_register_info.support PCI/ASPM: Use 'parent' and 'child' for readability PCI/ASPM: Move LTR path check to where it's used PCI/ASPM: Move pci_clear_and_set_dword() earlier PCI: dwc: Fix MSI page leakage in suspend/resume ...
This commit is contained in:
commit
00937f36b0
@ -9,12 +9,15 @@ title: Brcmstb PCIe Host Controller Device Tree Bindings
|
||||
maintainers:
|
||||
- Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pci/pci-bus.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm2711-pcie # The Raspberry Pi 4
|
||||
items:
|
||||
- enum:
|
||||
- brcm,bcm2711-pcie # The Raspberry Pi 4
|
||||
- brcm,bcm7211-pcie # Broadcom STB version of RPi4
|
||||
- brcm,bcm7278-pcie # Broadcom 7278 Arm
|
||||
- brcm,bcm7216-pcie # Broadcom 7216 Arm
|
||||
- brcm,bcm7445-pcie # Broadcom 7445 Arm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -34,10 +37,12 @@ properties:
|
||||
- const: msi
|
||||
|
||||
ranges:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
dma-ranges:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
@ -58,8 +63,31 @@ properties:
|
||||
|
||||
aspm-no-l0s: true
|
||||
|
||||
resets:
|
||||
description: for "brcm,bcm7216-pcie", must be a valid reset
|
||||
phandle pointing to the RESCAL reset controller provider node.
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: rescal
|
||||
|
||||
brcm,scb-sizes:
|
||||
description: u64 giving the 64bit PCIe memory
|
||||
viewport size of a memory controller. There may be up to
|
||||
three controllers, and each size must be a power of two
|
||||
with a size greater or equal to the amount of memory the
|
||||
controller supports. Note that each memory controller
|
||||
may have two component regions -- base and extended -- so
|
||||
this information cannot be deduced from the dma-ranges.
|
||||
$ref: /schemas/types.yaml#/definitions/uint64-array
|
||||
items:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
required:
|
||||
- reg
|
||||
- ranges
|
||||
- dma-ranges
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
@ -68,6 +96,18 @@ required:
|
||||
- interrupt-map
|
||||
- msi-controller
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pci/pci-bus.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: brcm,bcm7216-pcie
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@ -93,7 +133,9 @@ examples:
|
||||
msi-parent = <&pcie0>;
|
||||
msi-controller;
|
||||
ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>;
|
||||
dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x0 0x80000000>;
|
||||
dma-ranges = <0x42000000 0x1 0x00000000 0x0 0x40000000 0x0 0x80000000>,
|
||||
<0x42000000 0x1 0x80000000 0x3 0x00000000 0x0 0x80000000>;
|
||||
brcm,enable-ssc;
|
||||
brcm,scb-sizes = <0x0000000080000000 0x0000000080000000>;
|
||||
};
|
||||
};
|
||||
|
@ -24,6 +24,8 @@ Required properties:
|
||||
"fsl,ls1028a-pcie"
|
||||
EP mode:
|
||||
"fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
"fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
"fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
- reg: base addresses and lengths of the PCIe controller register blocks.
|
||||
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||
entry for each entry in the interrupt-names property.
|
||||
|
@ -14,8 +14,12 @@ maintainers:
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: renesas,r8a774c0-pcie-ep
|
||||
- const: renesas,rcar-gen3-pcie-ep
|
||||
- enum:
|
||||
- renesas,r8a774a1-pcie-ep # RZ/G2M
|
||||
- renesas,r8a774b1-pcie-ep # RZ/G2N
|
||||
- renesas,r8a774c0-pcie-ep # RZ/G2E
|
||||
- renesas,r8a774e1-pcie-ep # RZ/G2H
|
||||
- const: renesas,rcar-gen3-pcie-ep # R-Car Gen3 and RZ/G2
|
||||
|
||||
reg:
|
||||
maxItems: 5
|
||||
|
@ -1,7 +1,8 @@
|
||||
* Renesas R-Car PCIe interface
|
||||
|
||||
Required properties:
|
||||
compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
|
||||
compatible: "renesas,pcie-r8a7742" for the R8A7742 SoC;
|
||||
"renesas,pcie-r8a7743" for the R8A7743 SoC;
|
||||
"renesas,pcie-r8a7744" for the R8A7744 SoC;
|
||||
"renesas,pcie-r8a774a1" for the R8A774A1 SoC;
|
||||
"renesas,pcie-r8a774b1" for the R8A774B1 SoC;
|
||||
|
@ -23,14 +23,22 @@ properties:
|
||||
const: socionext,uniphier-pro5-pcie-ep
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
minItems: 4
|
||||
maxItems: 5
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
oneOf:
|
||||
- items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
- items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
- const: atu
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
@ -16,6 +16,7 @@ Required properties:
|
||||
"dbi" - controller configuration registers
|
||||
"link" - SoC-specific glue layer registers
|
||||
"config" - PCIe configuration space
|
||||
"atu" - iATU registers for DWC version 4.80 or later
|
||||
- clocks: A phandle to the clock gate for PCIe glue layer including
|
||||
the host controller.
|
||||
- resets: A phandle to the reset line for PCIe glue layer including
|
||||
|
@ -320,7 +320,7 @@ that these callbacks operate on::
|
||||
unsigned int d2_support:1; /* Low power state D2 is supported */
|
||||
unsigned int no_d1d2:1; /* D1 and D2 are forbidden */
|
||||
unsigned int wakeup_prepared:1; /* Device prepared for wake up */
|
||||
unsigned int d3_delay; /* D3->D0 transition time in ms */
|
||||
unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */
|
||||
...
|
||||
};
|
||||
|
||||
|
@ -17,10 +17,8 @@ struct pci_host_bridge;
|
||||
struct device;
|
||||
|
||||
struct hw_pci {
|
||||
struct msi_controller *msi_ctrl;
|
||||
struct pci_ops *ops;
|
||||
int nr_controllers;
|
||||
unsigned int io_optional:1;
|
||||
void **private_data;
|
||||
int (*setup)(int nr, struct pci_sys_data *);
|
||||
int (*scan)(int nr, struct pci_host_bridge *);
|
||||
@ -28,11 +26,6 @@ struct hw_pci {
|
||||
void (*postinit)(void);
|
||||
u8 (*swizzle)(struct pci_dev *dev, u8 *pin);
|
||||
int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
|
||||
resource_size_t (*align_resource)(struct pci_dev *dev,
|
||||
const struct resource *res,
|
||||
resource_size_t start,
|
||||
resource_size_t size,
|
||||
resource_size_t align);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -394,8 +394,7 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
|
||||
int io_optional)
|
||||
static int pcibios_init_resource(int busnr, struct pci_sys_data *sys)
|
||||
{
|
||||
int ret;
|
||||
struct resource_entry *window;
|
||||
@ -405,14 +404,6 @@ static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
|
||||
&iomem_resource, sys->mem_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a platform says I/O port support is optional, we don't add
|
||||
* the default I/O space. The platform is responsible for adding
|
||||
* any I/O space it needs.
|
||||
*/
|
||||
if (io_optional)
|
||||
return 0;
|
||||
|
||||
resource_list_for_each_entry(window, &sys->resources)
|
||||
if (resource_type(window->res) == IORESOURCE_IO)
|
||||
return 0;
|
||||
@ -462,7 +453,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
|
||||
|
||||
if (ret > 0) {
|
||||
|
||||
ret = pcibios_init_resource(nr, sys, hw->io_optional);
|
||||
ret = pcibios_init_resource(nr, sys);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
break;
|
||||
@ -480,9 +471,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
|
||||
bridge->sysdata = sys;
|
||||
bridge->busnr = sys->busnr;
|
||||
bridge->ops = hw->ops;
|
||||
bridge->msi = hw->msi_ctrl;
|
||||
bridge->align_resource =
|
||||
hw->align_resource;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
}
|
||||
|
@ -11,6 +11,13 @@
|
||||
#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz)
|
||||
#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz)
|
||||
|
||||
/*
|
||||
* Bus number may be embedded in the higher bits of the physical address.
|
||||
* This is why we have no bus number argument to ioremap().
|
||||
*/
|
||||
void __iomem *ioremap(phys_addr_t offset, size_t size);
|
||||
void iounmap(volatile void __iomem *addr);
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
||||
static inline void _memset_io(volatile void __iomem *dst,
|
||||
@ -121,14 +128,6 @@ static inline void sbus_memcpy_toio(volatile void __iomem *dst,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* Bus number may be embedded in the higher bits of the physical address.
|
||||
* This is why we have no bus number argument to ioremap().
|
||||
*/
|
||||
void __iomem *ioremap(phys_addr_t offset, size_t size);
|
||||
void iounmap(volatile void __iomem *addr);
|
||||
/* Create a virtual mapping cookie for an IO port range */
|
||||
void __iomem *ioport_map(unsigned long port, unsigned int nr);
|
||||
void ioport_unmap(void __iomem *);
|
||||
@ -148,8 +147,6 @@ static inline int sbus_can_burst64(void)
|
||||
struct device;
|
||||
void sbus_set_sbus64(struct device *, int);
|
||||
|
||||
#endif
|
||||
|
||||
#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1
|
||||
|
||||
|
||||
|
@ -587,7 +587,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26d, pci_invalid_bar);
|
||||
static void pci_fixup_amd_ehci_pme(struct pci_dev *dev)
|
||||
{
|
||||
dev_info(&dev->dev, "PME# does not work under D3, disabling it\n");
|
||||
dev->pme_support &= ~((PCI_PM_CAP_PME_D3 | PCI_PM_CAP_PME_D3cold)
|
||||
dev->pme_support &= ~((PCI_PM_CAP_PME_D3hot | PCI_PM_CAP_PME_D3cold)
|
||||
>> PCI_PM_CAP_PME_SHIFT);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x7808, pci_fixup_amd_ehci_pme);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/io_apic.h>
|
||||
#include <asm/intel-mid.h>
|
||||
#include <asm/acpi.h>
|
||||
|
||||
#define PCIE_CAP_OFFSET 0x100
|
||||
|
||||
@ -322,7 +323,7 @@ static void pci_d3delay_fixup(struct pci_dev *dev)
|
||||
*/
|
||||
if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
|
||||
return;
|
||||
dev->d3_delay = 0;
|
||||
dev->d3hot_delay = 0;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
|
||||
|
||||
|
@ -79,6 +79,12 @@
|
||||
((struct acpi_hest_generic_status *) \
|
||||
((struct ghes_estatus_node *)(estatus_node) + 1))
|
||||
|
||||
#define GHES_VENDOR_ENTRY_LEN(gdata_len) \
|
||||
(sizeof(struct ghes_vendor_record_entry) + (gdata_len))
|
||||
#define GHES_GDATA_FROM_VENDOR_ENTRY(vendor_entry) \
|
||||
((struct acpi_hest_generic_data *) \
|
||||
((struct ghes_vendor_record_entry *)(vendor_entry) + 1))
|
||||
|
||||
/*
|
||||
* NMI-like notifications vary by architecture, before the compiler can prune
|
||||
* unused static functions it needs a value for these enums.
|
||||
@ -123,6 +129,12 @@ static DEFINE_MUTEX(ghes_list_mutex);
|
||||
*/
|
||||
static DEFINE_SPINLOCK(ghes_notify_lock_irq);
|
||||
|
||||
struct ghes_vendor_record_entry {
|
||||
struct work_struct work;
|
||||
int error_severity;
|
||||
char vendor_record[];
|
||||
};
|
||||
|
||||
static struct gen_pool *ghes_estatus_pool;
|
||||
static unsigned long ghes_estatus_pool_size_request;
|
||||
|
||||
@ -511,6 +523,56 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
|
||||
|
||||
int ghes_register_vendor_record_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&vendor_record_notify_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ghes_register_vendor_record_notifier);
|
||||
|
||||
void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
|
||||
{
|
||||
blocking_notifier_chain_unregister(&vendor_record_notify_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
|
||||
|
||||
static void ghes_vendor_record_work_func(struct work_struct *work)
|
||||
{
|
||||
struct ghes_vendor_record_entry *entry;
|
||||
struct acpi_hest_generic_data *gdata;
|
||||
u32 len;
|
||||
|
||||
entry = container_of(work, struct ghes_vendor_record_entry, work);
|
||||
gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
|
||||
|
||||
blocking_notifier_call_chain(&vendor_record_notify_list,
|
||||
entry->error_severity, gdata);
|
||||
|
||||
len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
|
||||
gen_pool_free(ghes_estatus_pool, (unsigned long)entry, len);
|
||||
}
|
||||
|
||||
static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
|
||||
int sev)
|
||||
{
|
||||
struct acpi_hest_generic_data *copied_gdata;
|
||||
struct ghes_vendor_record_entry *entry;
|
||||
u32 len;
|
||||
|
||||
len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
|
||||
entry = (void *)gen_pool_alloc(ghes_estatus_pool, len);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
copied_gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
|
||||
memcpy(copied_gdata, gdata, acpi_hest_get_record_size(gdata));
|
||||
entry->error_severity = sev;
|
||||
|
||||
INIT_WORK(&entry->work, ghes_vendor_record_work_func);
|
||||
schedule_work(&entry->work);
|
||||
}
|
||||
|
||||
static bool ghes_do_proc(struct ghes *ghes,
|
||||
const struct acpi_hest_generic_status *estatus)
|
||||
{
|
||||
@ -549,6 +611,7 @@ static bool ghes_do_proc(struct ghes *ghes,
|
||||
} else {
|
||||
void *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
ghes_defer_non_standard_event(gdata, sev);
|
||||
log_non_standard_event(sec_type, fru_id, fru_text,
|
||||
sec_sev, err,
|
||||
gdata->error_data_length);
|
||||
|
@ -142,6 +142,26 @@ static struct mcfg_fixup mcfg_quirks[] = {
|
||||
XGENE_V2_ECAM_MCFG(4, 0),
|
||||
XGENE_V2_ECAM_MCFG(4, 1),
|
||||
XGENE_V2_ECAM_MCFG(4, 2),
|
||||
|
||||
#define ALTRA_ECAM_QUIRK(rev, seg) \
|
||||
{ "Ampere", "Altra ", rev, seg, MCFG_BUS_ANY, &pci_32b_read_ops }
|
||||
|
||||
ALTRA_ECAM_QUIRK(1, 0),
|
||||
ALTRA_ECAM_QUIRK(1, 1),
|
||||
ALTRA_ECAM_QUIRK(1, 2),
|
||||
ALTRA_ECAM_QUIRK(1, 3),
|
||||
ALTRA_ECAM_QUIRK(1, 4),
|
||||
ALTRA_ECAM_QUIRK(1, 5),
|
||||
ALTRA_ECAM_QUIRK(1, 6),
|
||||
ALTRA_ECAM_QUIRK(1, 7),
|
||||
ALTRA_ECAM_QUIRK(1, 8),
|
||||
ALTRA_ECAM_QUIRK(1, 9),
|
||||
ALTRA_ECAM_QUIRK(1, 10),
|
||||
ALTRA_ECAM_QUIRK(1, 11),
|
||||
ALTRA_ECAM_QUIRK(1, 12),
|
||||
ALTRA_ECAM_QUIRK(1, 13),
|
||||
ALTRA_ECAM_QUIRK(1, 14),
|
||||
ALTRA_ECAM_QUIRK(1, 15),
|
||||
};
|
||||
|
||||
static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
|
||||
@ -280,5 +300,5 @@ void __init pci_mmcfg_late_init(void)
|
||||
{
|
||||
int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
|
||||
if (err)
|
||||
pr_err("Failed to parse MCFG (%d)\n", err);
|
||||
pr_debug("Failed to parse MCFG (%d)\n", err);
|
||||
}
|
||||
|
@ -755,7 +755,7 @@ static int _ish_hw_reset(struct ishtp_device *dev)
|
||||
csr |= PCI_D3hot;
|
||||
pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
|
||||
|
||||
mdelay(pdev->d3_delay);
|
||||
mdelay(pdev->d3hot_delay);
|
||||
|
||||
csr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||
csr |= PCI_D0;
|
||||
|
@ -70,11 +70,15 @@
|
||||
|
||||
#define PCI_DEVICE_ID_TI_J721E 0xb00d
|
||||
#define PCI_DEVICE_ID_TI_AM654 0xb00c
|
||||
#define PCI_DEVICE_ID_LS1088A 0x80c0
|
||||
|
||||
#define is_am654_pci_dev(pdev) \
|
||||
((pdev)->device == PCI_DEVICE_ID_TI_AM654)
|
||||
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774A1 0x0028
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774B1 0x002b
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
|
||||
|
||||
static DEFINE_IDA(pci_endpoint_test_ida);
|
||||
|
||||
@ -945,13 +949,20 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
|
||||
.driver_data = (kernel_ulong_t)&am654_data
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
|
||||
.driver_data = (kernel_ulong_t)&j721e_data,
|
||||
},
|
||||
|
@ -5105,7 +5105,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
INIT_WORK(&hw->restart_work, sky2_restart);
|
||||
|
||||
pci_set_drvdata(pdev, hw);
|
||||
pdev->d3_delay = 300;
|
||||
pdev->d3hot_delay = 300;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -190,6 +190,68 @@ config PCI_HYPERV
|
||||
The PCI device frontend driver allows the kernel to import arbitrary
|
||||
PCI devices from a PCI backend to support PCI driver domains.
|
||||
|
||||
choice
|
||||
prompt "PCI Express hierarchy optimization setting"
|
||||
default PCIE_BUS_DEFAULT
|
||||
depends on PCI && EXPERT
|
||||
help
|
||||
MPS (Max Payload Size) and MRRS (Max Read Request Size) are PCIe
|
||||
device parameters that affect performance and the ability to
|
||||
support hotplug and peer-to-peer DMA.
|
||||
|
||||
The following choices set the MPS and MRRS optimization strategy
|
||||
at compile-time. The choices are the same as those offered for
|
||||
the kernel command-line parameter 'pci', i.e.,
|
||||
'pci=pcie_bus_tune_off', 'pci=pcie_bus_safe',
|
||||
'pci=pcie_bus_perf', and 'pci=pcie_bus_peer2peer'.
|
||||
|
||||
This is a compile-time setting and can be overridden by the above
|
||||
command-line parameters. If unsure, choose PCIE_BUS_DEFAULT.
|
||||
|
||||
config PCIE_BUS_TUNE_OFF
|
||||
bool "Tune Off"
|
||||
depends on PCI
|
||||
help
|
||||
Use the BIOS defaults; don't touch MPS at all. This is the same
|
||||
as booting with 'pci=pcie_bus_tune_off'.
|
||||
|
||||
config PCIE_BUS_DEFAULT
|
||||
bool "Default"
|
||||
depends on PCI
|
||||
help
|
||||
Default choice; ensure that the MPS matches upstream bridge.
|
||||
|
||||
config PCIE_BUS_SAFE
|
||||
bool "Safe"
|
||||
depends on PCI
|
||||
help
|
||||
Use largest MPS that boot-time devices support. If you have a
|
||||
closed system with no possibility of adding new devices, this
|
||||
will use the largest MPS that's supported by all devices. This
|
||||
is the same as booting with 'pci=pcie_bus_safe'.
|
||||
|
||||
config PCIE_BUS_PERFORMANCE
|
||||
bool "Performance"
|
||||
depends on PCI
|
||||
help
|
||||
Use MPS and MRRS for best performance. Ensure that a given
|
||||
device's MPS is no larger than its parent MPS, which allows us to
|
||||
keep all switches/bridges to the max MPS supported by their
|
||||
parent. This is the same as booting with 'pci=pcie_bus_perf'.
|
||||
|
||||
config PCIE_BUS_PEER2PEER
|
||||
bool "Peer2peer"
|
||||
depends on PCI
|
||||
help
|
||||
Set MPS = 128 for all devices. MPS configuration effected by the
|
||||
other options could cause the MPS on one root port to be
|
||||
different than that of the MPS on another, which may cause
|
||||
hot-added devices or peer-to-peer DMA to fail. Set MPS to the
|
||||
smallest possible value (128B) system-wide to avoid these issues.
|
||||
This is the same as booting with 'pci=pcie_bus_peer2peer'.
|
||||
|
||||
endchoice
|
||||
|
||||
source "drivers/pci/hotplug/Kconfig"
|
||||
source "drivers/pci/controller/Kconfig"
|
||||
source "drivers/pci/endpoint/Kconfig"
|
||||
|
@ -12,7 +12,7 @@ config PCI_MVEBU
|
||||
select PCI_BRIDGE_EMUL
|
||||
|
||||
config PCI_AARDVARK
|
||||
bool "Aardvark PCIe controller"
|
||||
tristate "Aardvark PCIe controller"
|
||||
depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
@ -273,9 +273,10 @@ config VMD
|
||||
|
||||
config PCIE_BRCMSTB
|
||||
tristate "Broadcom Brcmstb PCIe host controller"
|
||||
depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
default ARCH_BRCMSTB
|
||||
help
|
||||
Say Y here to enable PCIe host controller support for
|
||||
Broadcom STB based SoCs, like the Raspberry Pi 4.
|
||||
@ -297,6 +298,13 @@ config PCI_LOONGSON
|
||||
Say Y here if you want to enable PCI controller support on
|
||||
Loongson systems.
|
||||
|
||||
config PCIE_HISI_ERR
|
||||
depends on ACPI_APEI_GHES && (ARM64 || COMPILE_TEST)
|
||||
bool "HiSilicon HIP PCIe controller error handling driver"
|
||||
help
|
||||
Say Y here if you want error handling support
|
||||
for the PCIe controller's errors on HiSilicon HIP SoCs
|
||||
|
||||
source "drivers/pci/controller/dwc/Kconfig"
|
||||
source "drivers/pci/controller/mobiveil/Kconfig"
|
||||
source "drivers/pci/controller/cadence/Kconfig"
|
||||
|
@ -31,6 +31,7 @@ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
|
||||
obj-$(CONFIG_VMD) += vmd.o
|
||||
obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
|
||||
obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
|
||||
obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o
|
||||
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
|
||||
obj-y += dwc/
|
||||
obj-y += mobiveil/
|
||||
|
@ -328,7 +328,6 @@ static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
|
||||
cdns_pcie_ep_assert_intx(ep, fn, intx, true);
|
||||
/*
|
||||
* The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
|
||||
* from drivers/pci/dwc/pci-dra7xx.c
|
||||
*/
|
||||
mdelay(1);
|
||||
cdns_pcie_ep_assert_intx(ep, fn, intx, false);
|
||||
|
@ -337,7 +337,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
|
||||
struct resource_entry *entry;
|
||||
u64 cpu_addr = cfg_res->start;
|
||||
u32 addr0, addr1, desc1;
|
||||
int r, err, busnr = 0;
|
||||
int r, busnr = 0;
|
||||
|
||||
entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
|
||||
if (entry)
|
||||
@ -383,11 +383,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
|
||||
r++;
|
||||
}
|
||||
|
||||
err = cdns_pcie_host_map_dma_ranges(rc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return cdns_pcie_host_map_dma_ranges(rc);
|
||||
}
|
||||
|
||||
static int cdns_pcie_host_init(struct device *dev,
|
||||
|
@ -237,8 +237,9 @@ config PCIE_HISI_STB
|
||||
Say Y here if you want PCIe controller support on HiSilicon STB SoCs
|
||||
|
||||
config PCI_MESON
|
||||
bool "MESON PCIe controller"
|
||||
tristate "MESON PCIe controller"
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
default m if ARCH_MESON
|
||||
select PCIE_DW_HOST
|
||||
help
|
||||
Say Y here if you want to enable PCI controller support on Amlogic
|
||||
|
@ -73,8 +73,6 @@
|
||||
#define LINK_UP BIT(16)
|
||||
#define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define PCIECTRL_TI_CONF_INTX_ASSERT 0x0124
|
||||
#define PCIECTRL_TI_CONF_INTX_DEASSERT 0x0128
|
||||
|
||||
@ -91,7 +89,6 @@ struct dra7xx_pcie {
|
||||
void __iomem *base; /* DT ti_conf */
|
||||
int phy_count; /* DT phy-names count */
|
||||
struct phy **phy;
|
||||
int link_gen;
|
||||
struct irq_domain *irq_domain;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
@ -142,33 +139,12 @@ static int dra7xx_pcie_establish_link(struct dw_pcie *pci)
|
||||
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u32 reg;
|
||||
u32 exp_cap_off = EXP_CAP_ID_OFFSET;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(dev, "link is already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dra7xx->link_gen == 1) {
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
|
||||
4, ®);
|
||||
if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCAP, 4, reg);
|
||||
}
|
||||
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
|
||||
2, ®);
|
||||
if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCTL2, 2, reg);
|
||||
}
|
||||
}
|
||||
|
||||
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
|
||||
reg |= LTSSM_EN;
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
|
||||
@ -490,7 +466,9 @@ static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
|
||||
static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
u32 ctrl, num_ctrls;
|
||||
int ret;
|
||||
|
||||
pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
|
||||
|
||||
@ -506,7 +484,21 @@ static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
|
||||
~0);
|
||||
}
|
||||
|
||||
return dw_pcie_allocate_domains(pp);
|
||||
ret = dw_pcie_allocate_domains(pp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
ret = dma_mapping_error(dev, pp->msi_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to map MSI data\n");
|
||||
pp->msi_data = 0;
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
|
||||
@ -937,10 +929,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
reg &= ~LTSSM_EN;
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
|
||||
|
||||
dra7xx->link_gen = of_pci_get_max_link_speed(np);
|
||||
if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2)
|
||||
dra7xx->link_gen = 2;
|
||||
|
||||
switch (mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) {
|
||||
|
@ -336,32 +336,37 @@ static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, false);
|
||||
}
|
||||
|
||||
static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
exynos_pcie_sideband_dbi_r_mode(ep, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
exynos_pcie_sideband_dbi_r_mode(ep, false);
|
||||
return ret;
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, false);
|
||||
return ret;
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops exynos_pci_ops = {
|
||||
.read = exynos_pcie_rd_own_conf,
|
||||
.write = exynos_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static int exynos_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
@ -379,6 +384,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
|
||||
pp->bridge->ops = &exynos_pci_ops;
|
||||
|
||||
exynos_pcie_establish_link(ep);
|
||||
exynos_pcie_enable_interrupts(ep);
|
||||
|
||||
@ -386,8 +393,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
|
||||
.rd_own_conf = exynos_pcie_rd_own_conf,
|
||||
.wr_own_conf = exynos_pcie_wr_own_conf,
|
||||
.host_init = exynos_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,6 @@ struct imx6_pcie {
|
||||
u32 tx_deemph_gen2_6db;
|
||||
u32 tx_swing_full;
|
||||
u32 tx_swing_low;
|
||||
int link_gen;
|
||||
struct regulator *vpcie;
|
||||
void __iomem *phy_base;
|
||||
|
||||
@ -94,15 +93,6 @@ struct imx6_pcie {
|
||||
#define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200
|
||||
#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX)
|
||||
|
||||
/* PCIe Root Complex registers (memory-mapped) */
|
||||
#define PCIE_RC_IMX6_MSI_CAP 0x50
|
||||
#define PCIE_RC_LCR 0x7c
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
|
||||
|
||||
#define PCIE_RC_LCSR 0x80
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
|
||||
@ -116,8 +106,6 @@ struct imx6_pcie {
|
||||
#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
|
||||
#define PCIE_PHY_STAT_ACK BIT(16)
|
||||
|
||||
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
|
||||
|
||||
/* PHY registers (not memory-mapped) */
|
||||
#define PCIE_PHY_ATEOVRD 0x10
|
||||
#define PCIE_PHY_ATEOVRD_EN BIT(2)
|
||||
@ -761,6 +749,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = imx6_pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
@ -769,10 +758,10 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
* started in Gen2 mode, there is a possibility the devices on the
|
||||
* bus will not be detected at all. This happens with PCIe switches.
|
||||
*/
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
|
||||
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
|
||||
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
|
||||
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
|
||||
tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
tmp &= ~PCI_EXP_LNKCAP_SLS;
|
||||
tmp |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
|
||||
|
||||
/* Start LTSSM. */
|
||||
imx6_pcie_ltssm_enable(dev);
|
||||
@ -781,12 +770,12 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
if (ret)
|
||||
goto err_reset_phy;
|
||||
|
||||
if (imx6_pcie->link_gen == 2) {
|
||||
if (pci->link_gen == 2) {
|
||||
/* Allow Gen2 mode after the link is up. */
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
|
||||
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
|
||||
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
|
||||
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
|
||||
tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
tmp &= ~PCI_EXP_LNKCAP_SLS;
|
||||
tmp |= PCI_EXP_LNKCAP_SLS_5_0GB;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
|
||||
|
||||
/*
|
||||
* Start Directed Speed Change so the best possible
|
||||
@ -824,8 +813,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
dev_info(dev, "Link: Gen2 disabled\n");
|
||||
}
|
||||
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
|
||||
dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
|
||||
tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
|
||||
dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS);
|
||||
return 0;
|
||||
|
||||
err_reset_phy:
|
||||
@ -847,9 +836,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
|
||||
imx6_setup_phy_mpll(imx6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
imx6_pcie_establish_link(imx6_pcie);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1073,38 +1060,33 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
/* Fetch clocks */
|
||||
imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
|
||||
if (IS_ERR(imx6_pcie->pcie_phy)) {
|
||||
dev_err(dev, "pcie_phy clock source missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie_phy);
|
||||
}
|
||||
if (IS_ERR(imx6_pcie->pcie_phy))
|
||||
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy),
|
||||
"pcie_phy clock source missing or invalid\n");
|
||||
|
||||
imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
|
||||
if (IS_ERR(imx6_pcie->pcie_bus)) {
|
||||
dev_err(dev, "pcie_bus clock source missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie_bus);
|
||||
}
|
||||
if (IS_ERR(imx6_pcie->pcie_bus))
|
||||
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus),
|
||||
"pcie_bus clock source missing or invalid\n");
|
||||
|
||||
imx6_pcie->pcie = devm_clk_get(dev, "pcie");
|
||||
if (IS_ERR(imx6_pcie->pcie)) {
|
||||
dev_err(dev, "pcie clock source missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie);
|
||||
}
|
||||
if (IS_ERR(imx6_pcie->pcie))
|
||||
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie),
|
||||
"pcie clock source missing or invalid\n");
|
||||
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
imx6_pcie->pcie_inbound_axi = devm_clk_get(dev,
|
||||
"pcie_inbound_axi");
|
||||
if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
|
||||
dev_err(dev, "pcie_inbound_axi clock missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie_inbound_axi);
|
||||
}
|
||||
if (IS_ERR(imx6_pcie->pcie_inbound_axi))
|
||||
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_inbound_axi),
|
||||
"pcie_inbound_axi clock missing or invalid\n");
|
||||
break;
|
||||
case IMX8MQ:
|
||||
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
|
||||
if (IS_ERR(imx6_pcie->pcie_aux)) {
|
||||
dev_err(dev, "pcie_aux clock source missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie_aux);
|
||||
}
|
||||
if (IS_ERR(imx6_pcie->pcie_aux))
|
||||
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
|
||||
"pcie_aux clock source missing or invalid\n");
|
||||
fallthrough;
|
||||
case IMX7D:
|
||||
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
|
||||
@ -1165,10 +1147,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
imx6_pcie->tx_swing_low = 127;
|
||||
|
||||
/* Limit link speed */
|
||||
ret = of_property_read_u32(node, "fsl,max-link-speed",
|
||||
&imx6_pcie->link_gen);
|
||||
if (ret)
|
||||
imx6_pcie->link_gen = 1;
|
||||
pci->link_gen = 1;
|
||||
ret = of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen);
|
||||
|
||||
imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie");
|
||||
if (IS_ERR(imx6_pcie->vpcie)) {
|
||||
@ -1188,11 +1168,10 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP +
|
||||
PCI_MSI_FLAGS);
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
|
||||
val |= PCI_MSI_FLAGS_ENABLE;
|
||||
dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS,
|
||||
val);
|
||||
dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -96,8 +96,6 @@
|
||||
#define LEG_EP 0x1
|
||||
#define RC 0x2
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define KS_PCIE_SYSCLOCKOUTEN BIT(0)
|
||||
|
||||
#define AM654_PCIE_DEV_TYPE_MASK 0x3
|
||||
@ -123,7 +121,6 @@ struct keystone_pcie {
|
||||
|
||||
int msi_host_irq;
|
||||
int num_lanes;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
struct device_link **link;
|
||||
struct device_node *msi_intc_np;
|
||||
@ -397,13 +394,17 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
|
||||
static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
u32 val;
|
||||
u32 num_viewport = ks_pcie->num_viewport;
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u64 start = pp->mem->start;
|
||||
u64 end = pp->mem->end;
|
||||
u32 num_viewport = pci->num_viewport;
|
||||
u64 start, end;
|
||||
struct resource *mem;
|
||||
int i;
|
||||
|
||||
mem = resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM)->res;
|
||||
start = mem->start;
|
||||
end = mem->end;
|
||||
|
||||
/* Disable BARs for inbound access */
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
@ -430,10 +431,10 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
||||
ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
|
||||
}
|
||||
|
||||
static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 *val)
|
||||
static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 reg;
|
||||
@ -444,36 +445,29 @@ static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
return dw_pcie_read(pp->va_cfg0_base + where, size, val);
|
||||
return pp->va_cfg0_base + where;
|
||||
}
|
||||
|
||||
static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 reg;
|
||||
|
||||
reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
|
||||
CFG_FUNC(PCI_FUNC(devfn));
|
||||
if (!pci_is_root_bus(bus->parent))
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
return dw_pcie_write(pp->va_cfg0_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops ks_child_pcie_ops = {
|
||||
.map_bus = ks_pcie_other_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
|
||||
* ks_pcie_v3_65_add_bus() - keystone add_bus post initialization
|
||||
*
|
||||
* This sets BAR0 to enable inbound access for MSI_IRQ register
|
||||
*/
|
||||
static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
|
||||
static int ks_pcie_v3_65_add_bus(struct pci_bus *bus)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
|
||||
if (!pci_is_root_bus(bus))
|
||||
return 0;
|
||||
|
||||
/* Configure and set up BAR0 */
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
|
||||
@ -488,8 +482,17 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
|
||||
* be sufficient. Use physical address to avoid any conflicts.
|
||||
*/
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_ops ks_pcie_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
.add_bus = ks_pcie_v3_65_add_bus,
|
||||
};
|
||||
|
||||
/**
|
||||
* ks_pcie_link_up() - Check if link up
|
||||
*/
|
||||
@ -807,6 +810,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
int ret;
|
||||
|
||||
pp->bridge->ops = &ks_pcie_ops;
|
||||
pp->bridge->child_ops = &ks_child_pcie_ops;
|
||||
|
||||
ret = ks_pcie_config_legacy_irq(ks_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -842,11 +848,8 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops ks_pcie_host_ops = {
|
||||
.rd_other_conf = ks_pcie_rd_other_conf,
|
||||
.wr_other_conf = ks_pcie_wr_other_conf,
|
||||
.host_init = ks_pcie_host_init,
|
||||
.msi_host_init = ks_pcie_msi_host_init,
|
||||
.scan_bus = ks_pcie_v3_65_scan_bus,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
|
||||
@ -867,16 +870,8 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(pp->va_cfg0_base))
|
||||
return PTR_ERR(pp->va_cfg0_base);
|
||||
|
||||
pp->va_cfg1_base = pp->va_cfg0_base;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
@ -886,18 +881,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
dw_pcie_read(base + reg, size, &val);
|
||||
ks_pcie_clear_dbi_mode(ks_pcie);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size, u32 val)
|
||||
{
|
||||
@ -912,7 +895,6 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
|
||||
.start_link = ks_pcie_start_link,
|
||||
.stop_link = ks_pcie_stop_link,
|
||||
.link_up = ks_pcie_link_up,
|
||||
.read_dbi2 = ks_pcie_am654_read_dbi2,
|
||||
.write_dbi2 = ks_pcie_am654_write_dbi2,
|
||||
};
|
||||
|
||||
@ -1125,31 +1107,6 @@ static int ks_pcie_am654_set_mode(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= link_speed;
|
||||
dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= link_speed;
|
||||
dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2,
|
||||
val);
|
||||
}
|
||||
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
|
||||
.host_ops = &ks_pcie_host_ops,
|
||||
.version = 0x365A,
|
||||
@ -1197,13 +1154,10 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
struct keystone_pcie *ks_pcie;
|
||||
struct device_link **link;
|
||||
struct gpio_desc *gpiod;
|
||||
void __iomem *atu_base;
|
||||
struct resource *res;
|
||||
unsigned int version;
|
||||
void __iomem *base;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
int link_speed;
|
||||
u32 num_lanes;
|
||||
char name[10];
|
||||
int ret;
|
||||
@ -1320,29 +1274,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
if (pci->version >= 0x480A) {
|
||||
atu_base = devm_platform_ioremap_resource_byname(pdev, "atu");
|
||||
if (IS_ERR(atu_base)) {
|
||||
ret = PTR_ERR(atu_base);
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
pci->atu_base = atu_base;
|
||||
|
||||
if (pci->version >= 0x480A)
|
||||
ret = ks_pcie_am654_set_mode(dev, mode);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
} else {
|
||||
else
|
||||
ret = ks_pcie_set_mode(dev);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
link_speed = of_pci_get_max_link_speed(np);
|
||||
if (link_speed < 0)
|
||||
link_speed = 2;
|
||||
|
||||
ks_pcie_set_link_speed(pci, link_speed);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
|
||||
switch (mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
@ -1351,12 +1288,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to read *num-viewport* property\n");
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
/*
|
||||
* "Power Sequencing and Reset Signal Timings" table in
|
||||
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
|
||||
@ -1370,7 +1301,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
gpiod_set_value_cansleep(gpiod, 1);
|
||||
}
|
||||
|
||||
ks_pcie->num_viewport = num_viewport;
|
||||
pci->pp.ops = host_ops;
|
||||
ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
|
||||
if (ret < 0)
|
||||
|
@ -20,50 +20,58 @@
|
||||
|
||||
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
|
||||
|
||||
struct ls_pcie_ep {
|
||||
struct dw_pcie *pci;
|
||||
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
struct ls_pcie_ep_drvdata {
|
||||
u32 func_offset;
|
||||
const struct dw_pcie_ep_ops *ops;
|
||||
const struct dw_pcie_ops *dw_pcie_ops;
|
||||
};
|
||||
|
||||
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
struct ls_pcie_ep {
|
||||
struct dw_pcie *pci;
|
||||
struct pci_epc_features *ls_epc;
|
||||
const struct ls_pcie_ep_drvdata *drvdata;
|
||||
};
|
||||
|
||||
static int ls_pcie_establish_link(struct dw_pcie *pci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops ls_pcie_ep_ops = {
|
||||
static const struct dw_pcie_ops dw_ls_pcie_ep_ops = {
|
||||
.start_link = ls_pcie_establish_link,
|
||||
};
|
||||
|
||||
static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||
{ .compatible = "fsl,ls-pcie-ep",},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct pci_epc_features ls_pcie_epc_features = {
|
||||
.linkup_notifier = false,
|
||||
.msi_capable = true,
|
||||
.msix_capable = false,
|
||||
.bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
|
||||
};
|
||||
|
||||
static const struct pci_epc_features*
|
||||
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &ls_pcie_epc_features;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
|
||||
return pcie->ls_epc;
|
||||
}
|
||||
|
||||
static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
enum pci_barno bar;
|
||||
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
|
||||
if (!ep_func)
|
||||
return;
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
||||
pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
|
||||
pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
|
||||
}
|
||||
|
||||
static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num)
|
||||
enum pci_epc_irq_type type, u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
@ -73,21 +81,51 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||
case PCI_EPC_IRQ_MSIX:
|
||||
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
|
||||
return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
|
||||
interrupt_num);
|
||||
default:
|
||||
dev_err(pci->dev, "UNKNOWN IRQ type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
|
||||
WARN_ON(func_no && !pcie->drvdata->func_offset);
|
||||
return pcie->drvdata->func_offset * func_no;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
|
||||
.ep_init = ls_pcie_ep_init,
|
||||
.raise_irq = ls_pcie_ep_raise_irq,
|
||||
.get_features = ls_pcie_ep_get_features,
|
||||
.func_conf_select = ls_pcie_ep_func_conf_select,
|
||||
};
|
||||
|
||||
static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
|
||||
.ops = &ls_pcie_ep_ops,
|
||||
.dw_pcie_ops = &dw_ls_pcie_ep_ops,
|
||||
};
|
||||
|
||||
static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
|
||||
.func_offset = 0x20000,
|
||||
.ops = &ls_pcie_ep_ops,
|
||||
.dw_pcie_ops = &dw_ls_pcie_ep_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||
{ .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
|
||||
{ .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
|
||||
{ .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||
struct platform_device *pdev)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
@ -96,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||
int ret;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
ep->ops = pcie->drvdata->ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
@ -119,6 +157,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci;
|
||||
struct ls_pcie_ep *pcie;
|
||||
struct pci_epc_features *ls_epc;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
@ -130,15 +169,26 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
if (!pci)
|
||||
return -ENOMEM;
|
||||
|
||||
ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
|
||||
if (!ls_epc)
|
||||
return -ENOMEM;
|
||||
|
||||
pcie->drvdata = of_device_get_match_data(dev);
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = pcie->drvdata->dw_pcie_ops;
|
||||
|
||||
ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
|
||||
|
||||
pcie->pci = pci;
|
||||
pcie->ls_epc = ls_epc;
|
||||
|
||||
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
|
||||
pci->dev = dev;
|
||||
pci->ops = &ls_pcie_ep_ops;
|
||||
pcie->pci = pci;
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
|
@ -17,37 +17,13 @@
|
||||
#include <linux/resource.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define to_meson_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
/* External local bus interface registers */
|
||||
#define PLR_OFFSET 0x700
|
||||
#define PCIE_PORT_LINK_CTRL_OFF (PLR_OFFSET + 0x10)
|
||||
#define FAST_LINK_MODE BIT(7)
|
||||
#define LINK_CAPABLE_MASK GENMASK(21, 16)
|
||||
#define LINK_CAPABLE_X1 BIT(16)
|
||||
|
||||
#define PCIE_GEN2_CTRL_OFF (PLR_OFFSET + 0x10c)
|
||||
#define NUM_OF_LANES_MASK GENMASK(12, 8)
|
||||
#define NUM_OF_LANES_X1 BIT(8)
|
||||
#define DIRECT_SPEED_CHANGE BIT(17)
|
||||
|
||||
#define TYPE1_HDR_OFFSET 0x0
|
||||
#define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04)
|
||||
#define PCI_IO_EN BIT(0)
|
||||
#define PCI_MEM_SPACE_EN BIT(1)
|
||||
#define PCI_BUS_MASTER_EN BIT(2)
|
||||
|
||||
#define PCIE_BASE_ADDR0 (TYPE1_HDR_OFFSET + 0x10)
|
||||
#define PCIE_BASE_ADDR1 (TYPE1_HDR_OFFSET + 0x14)
|
||||
|
||||
#define PCIE_CAP_OFFSET 0x70
|
||||
#define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08)
|
||||
#define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5)
|
||||
#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
|
||||
#define PCIE_CAP_MAX_READ_REQ_MASK GENMASK(14, 12)
|
||||
#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
|
||||
|
||||
/* PCIe specific config registers */
|
||||
@ -77,11 +53,6 @@ enum pcie_data_rate {
|
||||
PCIE_GEN4
|
||||
};
|
||||
|
||||
struct meson_pcie_mem_res {
|
||||
void __iomem *elbi_base;
|
||||
void __iomem *cfg_base;
|
||||
};
|
||||
|
||||
struct meson_pcie_clk_res {
|
||||
struct clk *clk;
|
||||
struct clk *port_clk;
|
||||
@ -95,7 +66,7 @@ struct meson_pcie_rc_reset {
|
||||
|
||||
struct meson_pcie {
|
||||
struct dw_pcie pci;
|
||||
struct meson_pcie_mem_res mem_res;
|
||||
void __iomem *cfg_base;
|
||||
struct meson_pcie_clk_res clk_res;
|
||||
struct meson_pcie_rc_reset mrst;
|
||||
struct gpio_desc *reset_gpio;
|
||||
@ -134,28 +105,18 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
|
||||
struct meson_pcie *mp,
|
||||
const char *id)
|
||||
{
|
||||
struct device *dev = mp->pci.dev;
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
|
||||
|
||||
return devm_ioremap_resource(dev, res);
|
||||
}
|
||||
|
||||
static int meson_pcie_get_mems(struct platform_device *pdev,
|
||||
struct meson_pcie *mp)
|
||||
{
|
||||
mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
|
||||
if (IS_ERR(mp->mem_res.elbi_base))
|
||||
return PTR_ERR(mp->mem_res.elbi_base);
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
|
||||
mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
|
||||
if (IS_ERR(mp->mem_res.cfg_base))
|
||||
return PTR_ERR(mp->mem_res.cfg_base);
|
||||
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
|
||||
if (IS_ERR(mp->cfg_base))
|
||||
return PTR_ERR(mp->cfg_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -253,24 +214,14 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, mp->mem_res.elbi_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
|
||||
{
|
||||
return readl(mp->mem_res.elbi_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
|
||||
{
|
||||
return readl(mp->mem_res.cfg_base + reg);
|
||||
return readl(mp->cfg_base + reg);
|
||||
}
|
||||
|
||||
static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, mp->mem_res.cfg_base + reg);
|
||||
writel(val, mp->cfg_base + reg);
|
||||
}
|
||||
|
||||
static void meson_pcie_assert_reset(struct meson_pcie *mp)
|
||||
@ -287,25 +238,6 @@ static void meson_pcie_init_dw(struct meson_pcie *mp)
|
||||
val = meson_cfg_readl(mp, PCIE_CFG0);
|
||||
val |= APP_LTSSM_ENABLE;
|
||||
meson_cfg_writel(mp, val, PCIE_CFG0);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
|
||||
val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE);
|
||||
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
|
||||
val |= LINK_CAPABLE_X1;
|
||||
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
|
||||
val &= ~NUM_OF_LANES_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
|
||||
val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
|
||||
meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
|
||||
|
||||
meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
|
||||
meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
|
||||
}
|
||||
|
||||
static int meson_size_to_payload(struct meson_pcie *mp, int size)
|
||||
@ -327,37 +259,34 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size)
|
||||
|
||||
static void meson_set_max_payload(struct meson_pcie *mp, int size)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
u32 val;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int max_payload_size = meson_size_to_payload(mp, size);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_PAYLOAD;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
}
|
||||
|
||||
static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
u32 val;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int max_rd_req_size = meson_size_to_payload(mp, size);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
}
|
||||
|
||||
static inline void meson_enable_memory_space(struct meson_pcie *mp)
|
||||
{
|
||||
/* Set the RC Bus Master, Memory Space and I/O Space enables */
|
||||
meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
|
||||
PCIE_STATUS_COMMAND);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
}
|
||||
|
||||
static int meson_pcie_establish_link(struct meson_pcie *mp)
|
||||
@ -370,26 +299,18 @@ static int meson_pcie_establish_link(struct meson_pcie *mp)
|
||||
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
meson_enable_memory_space(mp);
|
||||
|
||||
meson_pcie_assert_reset(mp);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
}
|
||||
|
||||
static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
|
||||
static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(&mp->pci.pp);
|
||||
}
|
||||
|
||||
static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
return ret;
|
||||
|
||||
@ -410,13 +331,11 @@ static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops meson_pci_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = meson_pcie_rd_own_conf,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static int meson_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
@ -463,18 +382,18 @@ static int meson_pcie_host_init(struct pcie_port *pp)
|
||||
struct meson_pcie *mp = to_meson_pcie(pci);
|
||||
int ret;
|
||||
|
||||
pp->bridge->ops = &meson_pci_ops;
|
||||
|
||||
ret = meson_pcie_establish_link(mp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
meson_pcie_enable_interrupts(mp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops meson_pcie_host_ops = {
|
||||
.rd_own_conf = meson_pcie_rd_own_conf,
|
||||
.wr_own_conf = meson_pcie_wr_own_conf,
|
||||
.host_init = meson_pcie_host_init,
|
||||
};
|
||||
|
||||
@ -493,7 +412,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
|
||||
}
|
||||
|
||||
pp->ops = &meson_pcie_host_ops;
|
||||
pci->dbi_base = mp->mem_res.elbi_base;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
@ -522,6 +440,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
|
||||
pci = &mp->pci;
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
pci->num_lanes = 1;
|
||||
|
||||
mp->phy = devm_phy_get(dev, "pcie");
|
||||
if (IS_ERR(mp->phy)) {
|
||||
@ -589,6 +508,7 @@ static const struct of_device_id meson_pcie_of_match[] = {
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_pcie_of_match);
|
||||
|
||||
static struct platform_driver meson_pcie_driver = {
|
||||
.probe = meson_pcie_probe,
|
||||
@ -598,4 +518,8 @@ static struct platform_driver meson_pcie_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(meson_pcie_driver);
|
||||
module_platform_driver(meson_pcie_driver);
|
||||
|
||||
MODULE_AUTHOR("Yue Wang <yue.wang@amlogic.com>");
|
||||
MODULE_DESCRIPTION("Amlogic PCIe Controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -217,14 +217,15 @@ static inline void al_pcie_target_bus_set(struct al_pcie *pcie,
|
||||
reg);
|
||||
}
|
||||
|
||||
static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
|
||||
unsigned int busnr,
|
||||
unsigned int devfn)
|
||||
static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct al_pcie *pcie = to_al_pcie(to_dw_pcie_from_pp(pp));
|
||||
unsigned int busnr = bus->number;
|
||||
struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
|
||||
unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
|
||||
unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
|
||||
struct pcie_port *pp = &pcie->pci->pp;
|
||||
void __iomem *pci_base_addr;
|
||||
|
||||
pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
|
||||
@ -240,52 +241,14 @@ static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
|
||||
target_bus_cfg->reg_mask);
|
||||
}
|
||||
|
||||
return pci_base_addr;
|
||||
return pci_base_addr + where;
|
||||
}
|
||||
|
||||
static int al_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
unsigned int busnr = bus->number;
|
||||
void __iomem *pci_addr;
|
||||
int rc;
|
||||
|
||||
pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
|
||||
|
||||
rc = dw_pcie_read(pci_addr + where, size, val);
|
||||
|
||||
dev_dbg(pci->dev, "%d-byte config read from %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
|
||||
size, pci_domain_nr(bus), bus->number,
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn), where,
|
||||
(pci_addr + where), *val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int al_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
unsigned int busnr = bus->number;
|
||||
void __iomem *pci_addr;
|
||||
int rc;
|
||||
|
||||
pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
|
||||
|
||||
rc = dw_pcie_write(pci_addr + where, size, val);
|
||||
|
||||
dev_dbg(pci->dev, "%d-byte config write to %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
|
||||
size, pci_domain_nr(bus), bus->number,
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn), where,
|
||||
(pci_addr + where), val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static struct pci_ops al_child_pci_ops = {
|
||||
.map_bus = al_pcie_conf_addr_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
{
|
||||
@ -297,6 +260,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
u8 secondary_bus;
|
||||
u32 cfg_control;
|
||||
u32 reg;
|
||||
struct resource *bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
|
||||
|
||||
target_bus_cfg = &pcie->target_bus_cfg;
|
||||
|
||||
@ -310,13 +274,13 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
target_bus_cfg->ecam_mask = ecam_bus_mask;
|
||||
/* This portion is taken from the cfg_target_bus reg */
|
||||
target_bus_cfg->reg_mask = ~target_bus_cfg->ecam_mask;
|
||||
target_bus_cfg->reg_val = pp->busn->start & target_bus_cfg->reg_mask;
|
||||
target_bus_cfg->reg_val = bus->start & target_bus_cfg->reg_mask;
|
||||
|
||||
al_pcie_target_bus_set(pcie, target_bus_cfg->reg_val,
|
||||
target_bus_cfg->reg_mask);
|
||||
|
||||
secondary_bus = pp->busn->start + 1;
|
||||
subordinate_bus = pp->busn->end;
|
||||
secondary_bus = bus->start + 1;
|
||||
subordinate_bus = bus->end;
|
||||
|
||||
/* Set the valid values of secondary and subordinate buses */
|
||||
cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl +
|
||||
@ -339,6 +303,8 @@ static int al_pcie_host_init(struct pcie_port *pp)
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
int rc;
|
||||
|
||||
pp->bridge->child_ops = &al_child_pci_ops;
|
||||
|
||||
rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -353,8 +319,6 @@ static int al_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops al_pcie_host_ops = {
|
||||
.rd_other_conf = al_pcie_rd_other_conf,
|
||||
.wr_other_conf = al_pcie_wr_other_conf,
|
||||
.host_init = al_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -44,13 +44,6 @@ struct artpec_pcie_of_data {
|
||||
|
||||
static const struct of_device_id artpec6_pcie_of_match[];
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
|
||||
#define ACK_F_ASPM_CTRL_OFF (PL_OFFSET + 0xc)
|
||||
#define ACK_N_FTS_MASK GENMASK(15, 8)
|
||||
#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK)
|
||||
|
||||
/* ARTPEC-6 specific registers */
|
||||
#define PCIECFG 0x18
|
||||
#define PCIECFG_DBG_OEN BIT(24)
|
||||
@ -289,30 +282,6 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie)
|
||||
}
|
||||
}
|
||||
|
||||
static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
u32 val;
|
||||
|
||||
if (artpec6_pcie->variant != ARTPEC7)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Increase the N_FTS (Number of Fast Training Sequences)
|
||||
* to be transmitted when transitioning from L0s to L0.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF);
|
||||
val &= ~ACK_N_FTS_MASK;
|
||||
val |= ACK_N_FTS(180);
|
||||
dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val);
|
||||
|
||||
/*
|
||||
* Set the Number of Fast Training Sequences that the core
|
||||
* advertises as its N_FTS during Gen2 or Gen3 link training.
|
||||
*/
|
||||
dw_pcie_link_set_n_fts(pci, 180);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
u32 val;
|
||||
@ -346,29 +315,23 @@ static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
}
|
||||
|
||||
static int artpec6_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
|
||||
if (artpec6_pcie->variant == ARTPEC7) {
|
||||
pci->n_fts[0] = 180;
|
||||
pci->n_fts[1] = 180;
|
||||
}
|
||||
artpec6_pcie_assert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
artpec6_pcie_establish_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
artpec6_pcie_enable_interrupts(artpec6_pcie);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -412,7 +375,6 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <linux/pci-epc.h>
|
||||
#include <linux/pci-epf.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
|
||||
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct pci_epc *epc = ep->epc;
|
||||
@ -28,12 +30,39 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify);
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
|
||||
int flags)
|
||||
struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
list_for_each_entry(ep_func, &ep->func_list, list) {
|
||||
if (ep_func->func_no == func_no)
|
||||
return ep_func;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
if (ep->ops->func_conf_select)
|
||||
func_offset = ep->ops->func_conf_select(ep, func_no);
|
||||
|
||||
return func_offset;
|
||||
}
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
|
||||
enum pci_barno bar, int flags)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
@ -46,7 +75,53 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
|
||||
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
__dw_pcie_ep_reset_bar(pci, bar, 0);
|
||||
u8 func_no, funcs;
|
||||
|
||||
funcs = pci->ep.epc->max_functions;
|
||||
|
||||
for (func_no = 0; func_no < funcs; func_no++)
|
||||
__dw_pcie_ep_reset_bar(pci, func_no, bar, 0);
|
||||
}
|
||||
|
||||
static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 cap_ptr, u8 cap)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
u8 cap_id, next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
if (!cap_ptr)
|
||||
return 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr);
|
||||
cap_id = (reg & 0x00ff);
|
||||
|
||||
if (cap_id > PCI_CAP_ID_MAX)
|
||||
return 0;
|
||||
|
||||
if (cap_id == cap)
|
||||
return cap_ptr;
|
||||
|
||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
u8 next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST);
|
||||
next_cap_ptr = (reg & 0x00ff);
|
||||
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||
@ -54,28 +129,31 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid);
|
||||
dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid);
|
||||
dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code);
|
||||
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid);
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code);
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE,
|
||||
hdr->subclass_code | hdr->baseclass_code << 8);
|
||||
dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE,
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE,
|
||||
hdr->cache_line_size);
|
||||
dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID,
|
||||
hdr->subsys_vendor_id);
|
||||
dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN,
|
||||
hdr->interrupt_pin);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
dma_addr_t cpu_addr,
|
||||
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_barno bar, dma_addr_t cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int ret;
|
||||
@ -88,7 +166,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr,
|
||||
ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr,
|
||||
as_type);
|
||||
if (ret < 0) {
|
||||
dev_err(pci->dev, "Failed to program IB window\n");
|
||||
@ -101,7 +179,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
||||
static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
phys_addr_t phys_addr,
|
||||
u64 pci_addr, size_t size)
|
||||
{
|
||||
u32 free_win;
|
||||
@ -113,8 +192,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM,
|
||||
phys_addr, pci_addr, size);
|
||||
dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM,
|
||||
phys_addr, pci_addr, size);
|
||||
|
||||
set_bit(free_win, ep->ob_window_map);
|
||||
ep->outbound_addr[free_win] = phys_addr;
|
||||
@ -130,7 +209,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_barno bar = epf_bar->barno;
|
||||
u32 atu_index = ep->bar_to_atu[bar];
|
||||
|
||||
__dw_pcie_ep_reset_bar(pci, bar, epf_bar->flags);
|
||||
__dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags);
|
||||
|
||||
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
|
||||
clear_bit(atu_index, ep->ib_window_map);
|
||||
@ -147,14 +226,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
|
||||
size_t size = epf_bar->size;
|
||||
int flags = epf_bar->flags;
|
||||
enum dw_pcie_as_type as_type;
|
||||
u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
|
||||
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
as_type = DW_PCIE_AS_MEM;
|
||||
else
|
||||
as_type = DW_PCIE_AS_IO;
|
||||
|
||||
ret = dw_pcie_ep_inbound_atu(ep, bar, epf_bar->phys_addr, as_type);
|
||||
ret = dw_pcie_ep_inbound_atu(ep, func_no, bar,
|
||||
epf_bar->phys_addr, as_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -213,7 +298,7 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size);
|
||||
ret = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size);
|
||||
if (ret) {
|
||||
dev_err(pci->dev, "Failed to enable address\n");
|
||||
return ret;
|
||||
@ -227,11 +312,16 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
if (!(val & PCI_MSI_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
@ -246,11 +336,16 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSI_FLAGS_QMASK;
|
||||
val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
|
||||
@ -266,11 +361,16 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msix_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
if (!(val & PCI_MSIX_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
@ -286,23 +386,28 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msix_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSIX_FLAGS_QSIZE;
|
||||
val |= interrupts;
|
||||
dw_pcie_writew_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_TABLE;
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
|
||||
val = offset | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_PBA;
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA;
|
||||
val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
@ -385,31 +490,36 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
struct pci_epc *epc = ep->epc;
|
||||
unsigned int aligned_offset;
|
||||
unsigned int func_offset = 0;
|
||||
u16 msg_ctrl, msg_data;
|
||||
u32 msg_addr_lower, msg_addr_upper, reg;
|
||||
u64 msg_addr;
|
||||
bool has_upper;
|
||||
int ret;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
/* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
msg_ctrl = dw_pcie_readw_dbi(pci, reg);
|
||||
has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
|
||||
reg = ep->msi_cap + PCI_MSI_ADDRESS_LO;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
|
||||
msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
|
||||
if (has_upper) {
|
||||
reg = ep->msi_cap + PCI_MSI_ADDRESS_HI;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
|
||||
msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
|
||||
reg = ep->msi_cap + PCI_MSI_DATA_64;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64;
|
||||
msg_data = dw_pcie_readw_dbi(pci, reg);
|
||||
} else {
|
||||
msg_addr_upper = 0;
|
||||
reg = ep->msi_cap + PCI_MSI_DATA_32;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32;
|
||||
msg_data = dw_pcie_readw_dbi(pci, reg);
|
||||
}
|
||||
aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
|
||||
@ -427,12 +537,33 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
u32 msg_data;
|
||||
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) |
|
||||
(interrupt_num - 1);
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
struct pci_epf_msix_tbl *msix_tbl;
|
||||
struct pci_epc *epc = ep->epc;
|
||||
unsigned int func_offset = 0;
|
||||
u32 reg, msg_data, vec_ctrl;
|
||||
unsigned int aligned_offset;
|
||||
u32 tbl_offset;
|
||||
@ -440,7 +571,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
int ret;
|
||||
u8 bir;
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_TABLE;
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
|
||||
tbl_offset = dw_pcie_readl_dbi(pci, reg);
|
||||
bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
|
||||
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
|
||||
@ -505,7 +642,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
|
||||
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
|
||||
PCI_HEADER_TYPE_MASK;
|
||||
if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
|
||||
dev_err(pci->dev,
|
||||
"PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
|
||||
@ -513,23 +651,21 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
|
||||
ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
|
||||
|
||||
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
if (offset) {
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
|
||||
nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -539,11 +675,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
int ret;
|
||||
void *addr;
|
||||
u8 func_no;
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct pci_epc_features *epc_features;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
INIT_LIST_HEAD(&ep->func_list);
|
||||
|
||||
if (!pci->dbi_base || !pci->dbi_base2) {
|
||||
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
|
||||
@ -590,6 +730,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
return -ENOMEM;
|
||||
ep->outbound_addr = addr;
|
||||
|
||||
if (pci->link_gen < 1)
|
||||
pci->link_gen = of_pci_get_max_link_speed(np);
|
||||
|
||||
epc = devm_pci_epc_create(dev, &epc_ops);
|
||||
if (IS_ERR(epc)) {
|
||||
dev_err(dev, "Failed to create epc device\n");
|
||||
@ -599,13 +742,27 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->epc = epc;
|
||||
epc_set_drvdata(epc, ep);
|
||||
|
||||
if (ep->ops->ep_init)
|
||||
ep->ops->ep_init(ep);
|
||||
|
||||
ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
|
||||
if (ret < 0)
|
||||
epc->max_functions = 1;
|
||||
|
||||
for (func_no = 0; func_no < epc->max_functions; func_no++) {
|
||||
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
|
||||
if (!ep_func)
|
||||
return -ENOMEM;
|
||||
|
||||
ep_func->func_no = func_no;
|
||||
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
|
||||
PCI_CAP_ID_MSI);
|
||||
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
|
||||
PCI_CAP_ID_MSIX);
|
||||
|
||||
list_add_tail(&ep_func->list, &ep->func_list);
|
||||
}
|
||||
|
||||
if (ep->ops->ep_init)
|
||||
ep->ops->ep_init(ep);
|
||||
|
||||
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
|
||||
ep->page_size);
|
||||
if (ret < 0) {
|
||||
|
@ -20,30 +20,7 @@
|
||||
#include "pcie-designware.h"
|
||||
|
||||
static struct pci_ops dw_pcie_ops;
|
||||
|
||||
static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci;
|
||||
|
||||
if (pp->ops->rd_own_conf)
|
||||
return pp->ops->rd_own_conf(pp, where, size, val);
|
||||
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
return dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci;
|
||||
|
||||
if (pp->ops->wr_own_conf)
|
||||
return pp->ops->wr_own_conf(pp, where, size, val);
|
||||
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops dw_child_pcie_ops;
|
||||
|
||||
static void dw_msi_ack_irq(struct irq_data *d)
|
||||
{
|
||||
@ -82,13 +59,13 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
||||
unsigned long val;
|
||||
u32 status, num_ctrls;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
for (i = 0; i < num_ctrls; i++) {
|
||||
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS +
|
||||
(i * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, &status);
|
||||
status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
|
||||
(i * MSI_REG_CTRL_BLOCK_SIZE));
|
||||
if (!status)
|
||||
continue;
|
||||
|
||||
@ -148,6 +125,7 @@ static int dw_pci_msi_set_affinity(struct irq_data *d,
|
||||
static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
@ -158,8 +136,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -167,6 +144,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
@ -177,8 +155,7 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -186,13 +163,14 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
static void dw_pci_bottom_ack(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
|
||||
}
|
||||
|
||||
static struct irq_chip dw_pci_msi_bottom_irq_chip = {
|
||||
@ -288,32 +266,26 @@ void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
irq_domain_remove(pp->msi_domain);
|
||||
irq_domain_remove(pp->irq_domain);
|
||||
|
||||
if (pp->msi_page)
|
||||
__free_page(pp->msi_page);
|
||||
if (pp->msi_data) {
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
dma_unmap_single_attrs(dev, pp->msi_data, sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
u64 msi_target;
|
||||
u64 msi_target = (u64)pp->msi_data;
|
||||
|
||||
pp->msi_page = alloc_page(GFP_KERNEL);
|
||||
pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, pp->msi_data)) {
|
||||
dev_err(dev, "Failed to map MSI data\n");
|
||||
__free_page(pp->msi_page);
|
||||
pp->msi_page = NULL;
|
||||
if (!IS_ENABLED(CONFIG_PCI_MSI))
|
||||
return;
|
||||
}
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
/* Program the msi_data */
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
|
||||
lower_32_bits(msi_target));
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
|
||||
upper_32_bits(msi_target));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
|
||||
|
||||
@ -324,20 +296,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource_entry *win;
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource *cfg_res;
|
||||
u32 hdr_type;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_init(&pci->pp.lock);
|
||||
|
||||
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
if (cfg_res) {
|
||||
pp->cfg0_size = resource_size(cfg_res) >> 1;
|
||||
pp->cfg1_size = resource_size(cfg_res) >> 1;
|
||||
pp->cfg0_size = resource_size(cfg_res);
|
||||
pp->cfg0_base = cfg_res->start;
|
||||
pp->cfg1_base = cfg_res->start + pp->cfg0_size;
|
||||
} else if (!pp->va_cfg0_base) {
|
||||
dev_err(dev, "Missing *config* reg space\n");
|
||||
}
|
||||
@ -346,47 +314,33 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
pp->bridge = bridge;
|
||||
|
||||
/* Get the I/O and memory ranges from DT */
|
||||
resource_list_for_each_entry(win, &bridge->windows) {
|
||||
switch (resource_type(win->res)) {
|
||||
case IORESOURCE_IO:
|
||||
pp->io = win->res;
|
||||
pp->io->name = "I/O";
|
||||
pp->io_size = resource_size(pp->io);
|
||||
pp->io_bus_addr = pp->io->start - win->offset;
|
||||
pp->io_base = pci_pio_to_address(pp->io->start);
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
pp->mem = win->res;
|
||||
pp->mem->name = "MEM";
|
||||
pp->mem_size = resource_size(pp->mem);
|
||||
pp->mem_bus_addr = pp->mem->start - win->offset;
|
||||
pp->io_size = resource_size(win->res);
|
||||
pp->io_bus_addr = win->res->start - win->offset;
|
||||
pp->io_base = pci_pio_to_address(win->res->start);
|
||||
break;
|
||||
case 0:
|
||||
pp->cfg = win->res;
|
||||
pp->cfg0_size = resource_size(pp->cfg) >> 1;
|
||||
pp->cfg1_size = resource_size(pp->cfg) >> 1;
|
||||
pp->cfg0_base = pp->cfg->start;
|
||||
pp->cfg1_base = pp->cfg->start + pp->cfg0_size;
|
||||
break;
|
||||
case IORESOURCE_BUS:
|
||||
pp->busn = win->res;
|
||||
dev_err(dev, "Missing *config* reg space\n");
|
||||
pp->cfg0_size = resource_size(win->res);
|
||||
pp->cfg0_base = win->res->start;
|
||||
if (!pci->dbi_base) {
|
||||
pci->dbi_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg0_base,
|
||||
pp->cfg0_size);
|
||||
if (!pci->dbi_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pci->dbi_base) {
|
||||
pci->dbi_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg->start,
|
||||
resource_size(pp->cfg));
|
||||
if (!pci->dbi_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
pp->mem_base = pp->mem->start;
|
||||
|
||||
if (!pp->va_cfg0_base) {
|
||||
pp->va_cfg0_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg0_base, pp->cfg0_size);
|
||||
@ -396,20 +350,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
if (!pp->va_cfg1_base) {
|
||||
pp->va_cfg1_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg1_base,
|
||||
pp->cfg1_size);
|
||||
if (!pp->va_cfg1_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
|
||||
if (ret)
|
||||
pci->num_viewport = 2;
|
||||
|
||||
if (pci->link_gen < 1)
|
||||
pci->link_gen = of_pci_get_max_link_speed(np);
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
/*
|
||||
* If a specific SoC driver needs to change the
|
||||
@ -440,6 +387,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
irq_set_chained_handler_and_data(pp->msi_irq,
|
||||
dw_chained_msi_isr,
|
||||
pp);
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
if (dma_mapping_error(pci->dev, pp->msi_data)) {
|
||||
dev_err(pci->dev, "Failed to map MSI data\n");
|
||||
pp->msi_data = 0;
|
||||
goto err_free_msi;
|
||||
}
|
||||
} else {
|
||||
ret = pp->ops->msi_host_init(pp);
|
||||
if (ret < 0)
|
||||
@ -447,47 +404,21 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set default bus ops */
|
||||
bridge->ops = &dw_pcie_ops;
|
||||
bridge->child_ops = &dw_child_pcie_ops;
|
||||
|
||||
if (pp->ops->host_init) {
|
||||
ret = pp->ops->host_init(pp);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
ret = dw_pcie_rd_own_conf(pp, PCI_HEADER_TYPE, 1, &hdr_type);
|
||||
if (ret != PCIBIOS_SUCCESSFUL) {
|
||||
dev_err(pci->dev, "Failed reading PCI_HEADER_TYPE cfg space reg (ret: 0x%x)\n",
|
||||
ret);
|
||||
ret = pcibios_err_to_errno(ret);
|
||||
goto err_free_msi;
|
||||
}
|
||||
if (hdr_type != PCI_HEADER_TYPE_BRIDGE) {
|
||||
dev_err(pci->dev,
|
||||
"PCIe controller is not set to bridge type (hdr_type: 0x%x)!\n",
|
||||
hdr_type);
|
||||
ret = -EIO;
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
bridge->sysdata = pp;
|
||||
bridge->ops = &dw_pcie_ops;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
|
||||
pp->root_bus = bridge->bus;
|
||||
|
||||
if (pp->ops->scan_bus)
|
||||
pp->ops->scan_bus(pp);
|
||||
|
||||
pci_bus_size_bridges(pp->root_bus);
|
||||
pci_bus_assign_resources(pp->root_bus);
|
||||
|
||||
list_for_each_entry(child, &pp->root_bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(pp->root_bus);
|
||||
return 0;
|
||||
ret = pci_host_probe(bridge);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
err_free_msi:
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
@ -498,47 +429,58 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_init);
|
||||
|
||||
void dw_pcie_host_deinit(struct pcie_port *pp)
|
||||
{
|
||||
pci_stop_root_bus(pp->root_bus);
|
||||
pci_remove_root_bus(pp->root_bus);
|
||||
pci_stop_root_bus(pp->bridge->bus);
|
||||
pci_remove_root_bus(pp->bridge->bus);
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
|
||||
|
||||
static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 *val,
|
||||
bool write)
|
||||
static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
int ret, type;
|
||||
u32 busdev, cfg_size;
|
||||
u64 cpu_addr;
|
||||
void __iomem *va_cfg_base;
|
||||
int type;
|
||||
u32 busdev;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* Checking whether the link is up here is a last line of defense
|
||||
* against platforms that forward errors on the system bus as
|
||||
* SError upon PCI configuration transactions issued when the link
|
||||
* is down. This check is racy by definition and does not stop
|
||||
* the system from triggering an SError if the link goes down
|
||||
* after this check is performed.
|
||||
*/
|
||||
if (!dw_pcie_link_up(pci))
|
||||
return NULL;
|
||||
|
||||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||
|
||||
if (pci_is_root_bus(bus->parent)) {
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
type = PCIE_ATU_TYPE_CFG0;
|
||||
cpu_addr = pp->cfg0_base;
|
||||
cfg_size = pp->cfg0_size;
|
||||
va_cfg_base = pp->va_cfg0_base;
|
||||
} else {
|
||||
else
|
||||
type = PCIE_ATU_TYPE_CFG1;
|
||||
cpu_addr = pp->cfg1_base;
|
||||
cfg_size = pp->cfg1_size;
|
||||
va_cfg_base = pp->va_cfg1_base;
|
||||
}
|
||||
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
type, cpu_addr,
|
||||
busdev, cfg_size);
|
||||
if (write)
|
||||
ret = dw_pcie_write(va_cfg_base + where, size, *val);
|
||||
else
|
||||
ret = dw_pcie_read(va_cfg_base + where, size, val);
|
||||
type, pp->cfg0_base,
|
||||
busdev, pp->cfg0_size);
|
||||
|
||||
if (pci->num_viewport <= 2)
|
||||
return pp->va_cfg0_base + where;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
@ -546,77 +488,45 @@ static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 *val)
|
||||
{
|
||||
if (pp->ops->rd_other_conf)
|
||||
return pp->ops->rd_other_conf(pp, bus, devfn, where,
|
||||
size, val);
|
||||
|
||||
return dw_pcie_access_other_conf(pp, bus, devfn, where, size, val,
|
||||
false);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 val)
|
||||
{
|
||||
if (pp->ops->wr_other_conf)
|
||||
return pp->ops->wr_other_conf(pp, bus, devfn, where,
|
||||
size, val);
|
||||
|
||||
return dw_pcie_access_other_conf(pp, bus, devfn, where, size, &val,
|
||||
true);
|
||||
}
|
||||
|
||||
static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus,
|
||||
int dev)
|
||||
static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
int ret;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/* If there is no link, then there is no device */
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
if (!dw_pcie_link_up(pci))
|
||||
return 0;
|
||||
} else if (dev > 0)
|
||||
/* Access only one slot on each root port */
|
||||
return 0;
|
||||
ret = pci_generic_config_write(bus, devfn, where, size, val);
|
||||
|
||||
return 1;
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 *val)
|
||||
static struct pci_ops dw_child_pcie_ops = {
|
||||
.map_bus = dw_pcie_other_conf_map_bus,
|
||||
.read = dw_pcie_rd_other_conf,
|
||||
.write = dw_pcie_wr_other_conf,
|
||||
};
|
||||
|
||||
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) {
|
||||
*val = 0xffffffff;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (PCI_SLOT(devfn) > 0)
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
|
||||
if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
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);
|
||||
return pci->dbi_base + where;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus);
|
||||
|
||||
static struct pci_ops dw_pcie_ops = {
|
||||
.read = dw_pcie_rd_conf,
|
||||
.write = dw_pcie_wr_conf,
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
@ -632,18 +542,18 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
|
||||
if (!pp->ops->msi_host_init) {
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init) {
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
/* Initialize IRQ Status array */
|
||||
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
|
||||
pp->irq_mask[ctrl] = ~0;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, pp->irq_mask[ctrl]);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
~0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -671,28 +581,32 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
|
||||
|
||||
/*
|
||||
* If the platform provides ->rd_other_conf, it means the platform
|
||||
* uses its own address translation component rather than ATU, so
|
||||
* we should not program the ATU here.
|
||||
* If the platform provides its own child bus config accesses, it means
|
||||
* the platform uses its own address translation component rather than
|
||||
* ATU, so we should not program the ATU here.
|
||||
*/
|
||||
if (!pp->ops->rd_other_conf) {
|
||||
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
|
||||
struct resource_entry *entry =
|
||||
resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, pp->mem_base,
|
||||
pp->mem_bus_addr, pp->mem_size);
|
||||
PCIE_ATU_TYPE_MEM, entry->res->start,
|
||||
entry->res->start - entry->offset,
|
||||
resource_size(entry->res));
|
||||
if (pci->num_viewport > 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
}
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
|
||||
/* Program correct class for RC */
|
||||
dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
|
||||
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
|
||||
|
||||
dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
@ -39,9 +39,7 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
@ -166,21 +167,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
|
||||
|
||||
u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pci->ops->read_dbi2)
|
||||
return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size);
|
||||
|
||||
ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "read DBI address failed\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
{
|
||||
int ret;
|
||||
@ -195,31 +181,31 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
dev_err(pci->dev, "write DBI address failed\n");
|
||||
}
|
||||
|
||||
u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size)
|
||||
static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pci->ops->read_dbi)
|
||||
return pci->ops->read_dbi(pci, pci->atu_base, reg, size);
|
||||
return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
|
||||
|
||||
ret = dw_pcie_read(pci->atu_base + reg, size, &val);
|
||||
ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "Read ATU address failed\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pci->ops->write_dbi) {
|
||||
pci->ops->write_dbi(pci, pci->atu_base, reg, size, val);
|
||||
pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dw_pcie_write(pci->atu_base + reg, size, val);
|
||||
ret = dw_pcie_write(pci->atu_base + reg, 4, val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "Write ATU address failed\n");
|
||||
}
|
||||
@ -239,9 +225,10 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr,
|
||||
u32 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
u64 limit_addr = cpu_addr + size - 1;
|
||||
@ -259,7 +246,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
|
||||
upper_32_bits(pci_addr));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
|
||||
type);
|
||||
type | PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
|
||||
PCIE_ATU_ENABLE);
|
||||
|
||||
@ -278,8 +265,9 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
|
||||
@ -287,8 +275,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
|
||||
|
||||
if (pci->iatu_unroll_enabled) {
|
||||
dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr,
|
||||
pci_addr, size);
|
||||
dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -304,7 +292,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
lower_32_bits(pci_addr));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
|
||||
upper_32_bits(pci_addr));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
|
||||
|
||||
/*
|
||||
@ -321,6 +310,21 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
{
|
||||
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
}
|
||||
|
||||
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size)
|
||||
{
|
||||
__dw_pcie_prog_outbound_atu(pci, func_no, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
}
|
||||
|
||||
static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
|
||||
@ -336,8 +340,8 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int type;
|
||||
@ -359,8 +363,10 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type);
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
|
||||
PCIE_ATU_FUNC_NUM_MATCH_EN |
|
||||
PCIE_ATU_ENABLE |
|
||||
PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
|
||||
@ -381,14 +387,15 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
u64 cpu_addr, enum dw_pcie_as_type as_type)
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int type;
|
||||
u32 retries, val;
|
||||
|
||||
if (pci->iatu_unroll_enabled)
|
||||
return dw_pcie_prog_inbound_atu_unroll(pci, index, bar,
|
||||
return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
|
||||
cpu_addr, as_type);
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
|
||||
@ -407,9 +414,11 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE
|
||||
| PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
|
||||
PCIE_ATU_FUNC_NUM_MATCH_EN |
|
||||
PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
|
||||
/*
|
||||
* Make sure ATU enable takes effect before any subsequent config
|
||||
@ -444,7 +453,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
|
||||
}
|
||||
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci)
|
||||
@ -488,50 +497,41 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
|
||||
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
{
|
||||
u32 reg, val;
|
||||
u32 cap, ctrl2, link_speed;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
|
||||
reg &= ~PCI_EXP_LNKCTL2_TLS;
|
||||
cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
|
||||
ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
|
||||
|
||||
switch (pcie_link_speed[link_gen]) {
|
||||
case PCIE_SPEED_2_5GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_2_5GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
|
||||
break;
|
||||
case PCIE_SPEED_5_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_5_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_8_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_8_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_16_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
|
||||
break;
|
||||
default:
|
||||
/* Use hardware capability */
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
reg &= ~PCI_EXP_LNKCTL2_HASD;
|
||||
reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val);
|
||||
link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
|
||||
ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
|
||||
break;
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
|
||||
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts)
|
||||
{
|
||||
u32 val;
|
||||
cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_N_FTS_MASK;
|
||||
val |= n_fts & PORT_LOGIC_N_FTS_MASK;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts);
|
||||
|
||||
static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
{
|
||||
@ -546,32 +546,58 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
|
||||
void dw_pcie_setup(struct dw_pcie *pci)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
u32 lanes;
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (pci->version >= 0x480A || (!pci->version &&
|
||||
dw_pcie_iatu_unroll_enabled(pci))) {
|
||||
pci->iatu_unroll_enabled = true;
|
||||
if (!pci->atu_base)
|
||||
pci->atu_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "atu");
|
||||
if (IS_ERR(pci->atu_base))
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
}
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
|
||||
"enabled" : "disabled");
|
||||
|
||||
if (pci->link_gen > 0)
|
||||
dw_pcie_link_set_max_speed(pci, pci->link_gen);
|
||||
|
||||
ret = of_property_read_u32(np, "num-lanes", &lanes);
|
||||
if (ret) {
|
||||
dev_dbg(pci->dev, "property num-lanes isn't found\n");
|
||||
/* Configure Gen1 N_FTS */
|
||||
if (pci->n_fts[0]) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
|
||||
val |= PORT_AFR_N_FTS(pci->n_fts[0]);
|
||||
val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
|
||||
}
|
||||
|
||||
/* Configure Gen2+ N_FTS */
|
||||
if (pci->n_fts[1]) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_N_FTS_MASK;
|
||||
val |= pci->n_fts[pci->link_gen - 1];
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val |= PORT_LINK_DLL_LINK_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
of_property_read_u32(np, "num-lanes", &pci->num_lanes);
|
||||
if (!pci->num_lanes) {
|
||||
dev_dbg(pci->dev, "Using h/w default number of lanes\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the number of lanes */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val &= ~PORT_LINK_MODE_MASK;
|
||||
switch (lanes) {
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LINK_MODE_1_LANES;
|
||||
break;
|
||||
@ -585,7 +611,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
val |= PORT_LINK_MODE_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes);
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
@ -593,7 +619,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
/* Set link width speed control register */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (lanes) {
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
|
@ -32,10 +32,18 @@
|
||||
/* Synopsys-specific PCIe configuration registers */
|
||||
#define PCIE_PORT_AFR 0x70C
|
||||
#define PORT_AFR_N_FTS_MASK GENMASK(15, 8)
|
||||
#define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
|
||||
#define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16)
|
||||
#define PORT_AFR_CC_N_FTS(n) FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n)
|
||||
#define PORT_AFR_ENTER_ASPM BIT(30)
|
||||
#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24
|
||||
#define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)
|
||||
#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27
|
||||
#define PORT_AFR_L1_ENTRANCE_LAT_MASK GENMASK(29, 27)
|
||||
|
||||
#define PCIE_PORT_LINK_CONTROL 0x710
|
||||
#define PORT_LINK_DLL_LINK_EN BIT(5)
|
||||
#define PORT_LINK_FAST_LINK_MODE BIT(7)
|
||||
#define PORT_LINK_MODE_MASK GENMASK(21, 16)
|
||||
#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
|
||||
#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
|
||||
@ -80,9 +88,11 @@
|
||||
#define PCIE_ATU_TYPE_IO 0x2
|
||||
#define PCIE_ATU_TYPE_CFG0 0x4
|
||||
#define PCIE_ATU_TYPE_CFG1 0x5
|
||||
#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20)
|
||||
#define PCIE_ATU_CR2 0x908
|
||||
#define PCIE_ATU_ENABLE BIT(31)
|
||||
#define PCIE_ATU_BAR_MODE_ENABLE BIT(30)
|
||||
#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19)
|
||||
#define PCIE_ATU_LOWER_BASE 0x90C
|
||||
#define PCIE_ATU_UPPER_BASE 0x910
|
||||
#define PCIE_ATU_LIMIT 0x914
|
||||
@ -95,6 +105,9 @@
|
||||
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
||||
#define PCIE_DBI_RO_WR_EN BIT(0)
|
||||
|
||||
#define PCIE_MSIX_DOORBELL 0x948
|
||||
#define PCIE_MSIX_DOORBELL_PF_SHIFT 24
|
||||
|
||||
#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20
|
||||
#define PCIE_PL_CHK_REG_CHK_REG_START BIT(0)
|
||||
#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1)
|
||||
@ -160,14 +173,7 @@ enum dw_pcie_device_mode {
|
||||
};
|
||||
|
||||
struct dw_pcie_host_ops {
|
||||
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
|
||||
int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
|
||||
int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 *val);
|
||||
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 val);
|
||||
int (*host_init)(struct pcie_port *pp);
|
||||
void (*scan_bus)(struct pcie_port *pp);
|
||||
void (*set_num_vectors)(struct pcie_port *pp);
|
||||
int (*msi_host_init)(struct pcie_port *pp);
|
||||
};
|
||||
@ -176,30 +182,20 @@ struct pcie_port {
|
||||
u64 cfg0_base;
|
||||
void __iomem *va_cfg0_base;
|
||||
u32 cfg0_size;
|
||||
u64 cfg1_base;
|
||||
void __iomem *va_cfg1_base;
|
||||
u32 cfg1_size;
|
||||
resource_size_t io_base;
|
||||
phys_addr_t io_bus_addr;
|
||||
u32 io_size;
|
||||
u64 mem_base;
|
||||
phys_addr_t mem_bus_addr;
|
||||
u32 mem_size;
|
||||
struct resource *cfg;
|
||||
struct resource *io;
|
||||
struct resource *mem;
|
||||
struct resource *busn;
|
||||
int irq;
|
||||
const struct dw_pcie_host_ops *ops;
|
||||
int msi_irq;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
u16 msi_msg;
|
||||
dma_addr_t msi_data;
|
||||
struct page *msi_page;
|
||||
struct irq_chip *msi_irq_chip;
|
||||
u32 num_vectors;
|
||||
u32 irq_mask[MAX_MSI_CTRLS];
|
||||
struct pci_bus *root_bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
raw_spinlock_t lock;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
|
||||
};
|
||||
@ -215,10 +211,26 @@ struct dw_pcie_ep_ops {
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
|
||||
/*
|
||||
* Provide a method to implement the different func config space
|
||||
* access for different platform, if different func have different
|
||||
* offset, return the offset of func. if use write a register way
|
||||
* return a 0, and implement code in callback function of platform
|
||||
* driver.
|
||||
*/
|
||||
unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_func {
|
||||
struct list_head list;
|
||||
u8 func_no;
|
||||
u8 msi_cap; /* MSI capability offset */
|
||||
u8 msix_cap; /* MSI-X capability offset */
|
||||
};
|
||||
|
||||
struct dw_pcie_ep {
|
||||
struct pci_epc *epc;
|
||||
struct list_head func_list;
|
||||
const struct dw_pcie_ep_ops *ops;
|
||||
phys_addr_t phys_base;
|
||||
size_t addr_size;
|
||||
@ -231,8 +243,6 @@ struct dw_pcie_ep {
|
||||
u32 num_ob_windows;
|
||||
void __iomem *msi_mem;
|
||||
phys_addr_t msi_mem_phys;
|
||||
u8 msi_cap; /* MSI capability offset */
|
||||
u8 msix_cap; /* MSI-X capability offset */
|
||||
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
|
||||
};
|
||||
|
||||
@ -242,8 +252,6 @@ struct dw_pcie_ops {
|
||||
size_t size);
|
||||
void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
int (*link_up)(struct dw_pcie *pcie);
|
||||
@ -263,6 +271,9 @@ struct dw_pcie {
|
||||
struct dw_pcie_ep ep;
|
||||
const struct dw_pcie_ops *ops;
|
||||
unsigned int version;
|
||||
int num_lanes;
|
||||
int link_gen;
|
||||
u8 n_fts[2];
|
||||
};
|
||||
|
||||
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
|
||||
@ -278,20 +289,19 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val);
|
||||
|
||||
u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
int dw_pcie_link_up(struct dw_pcie *pci);
|
||||
void dw_pcie_upconfig_setup(struct dw_pcie *pci);
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen);
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
u64 cpu_addr, enum dw_pcie_as_type as_type);
|
||||
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type);
|
||||
void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
|
||||
enum dw_pcie_region_type type);
|
||||
void dw_pcie_setup(struct dw_pcie *pci);
|
||||
@ -331,21 +341,6 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
dw_pcie_write_dbi2(pci, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return dw_pcie_read_dbi2(pci, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
dw_pcie_write_atu(pci, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return dw_pcie_read_atu(pci, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
|
||||
{
|
||||
u32 reg;
|
||||
@ -376,6 +371,8 @@ void dw_pcie_setup_rc(struct pcie_port *pp);
|
||||
int dw_pcie_host_init(struct pcie_port *pp);
|
||||
void dw_pcie_host_deinit(struct pcie_port *pp);
|
||||
int dw_pcie_allocate_domains(struct pcie_port *pp);
|
||||
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int where);
|
||||
#else
|
||||
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
||||
{
|
||||
@ -407,6 +404,12 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_DW_EP
|
||||
@ -420,7 +423,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num);
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num);
|
||||
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num);
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
|
||||
struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
|
||||
#else
|
||||
static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
{
|
||||
@ -461,8 +468,21 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep,
|
||||
u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* _PCIE_DESIGNWARE_H */
|
||||
|
@ -122,32 +122,37 @@ static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
histb_pcie_dbi_w_mode(&pci->pp, false);
|
||||
}
|
||||
|
||||
static int histb_pcie_rd_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 *val)
|
||||
static int histb_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
histb_pcie_dbi_r_mode(pp, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
histb_pcie_dbi_r_mode(pp, false);
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ret;
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 val)
|
||||
static int histb_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
histb_pcie_dbi_w_mode(pp, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
histb_pcie_dbi_w_mode(pp, false);
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return ret;
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops histb_pci_ops = {
|
||||
.read = histb_pcie_rd_own_conf,
|
||||
.write = histb_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static int histb_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct histb_pcie *hipcie = to_histb_pcie(pci);
|
||||
@ -194,17 +199,15 @@ static int histb_pcie_establish_link(struct pcie_port *pp)
|
||||
|
||||
static int histb_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
histb_pcie_establish_link(pp);
|
||||
pp->bridge->ops = &histb_pci_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
histb_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops histb_pcie_host_ops = {
|
||||
.rd_own_conf = histb_pcie_rd_own_conf,
|
||||
.wr_own_conf = histb_pcie_wr_own_conf,
|
||||
.host_init = histb_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -67,14 +67,9 @@ struct intel_pcie_port {
|
||||
void __iomem *app_base;
|
||||
struct gpio_desc *reset_gpio;
|
||||
u32 rst_intrvl;
|
||||
u32 max_speed;
|
||||
u32 link_gen;
|
||||
u32 max_width;
|
||||
u32 n_fts;
|
||||
struct clk *core_clk;
|
||||
struct reset_control *core_rst;
|
||||
struct phy *phy;
|
||||
u8 pcie_cap_ofst;
|
||||
};
|
||||
|
||||
static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val)
|
||||
@ -134,11 +129,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp)
|
||||
static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 val;
|
||||
u8 offset = lpp->pcie_cap_ofst;
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP);
|
||||
lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val);
|
||||
u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL);
|
||||
|
||||
@ -146,41 +137,29 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
|
||||
pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val);
|
||||
}
|
||||
|
||||
static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp)
|
||||
static void intel_pcie_init_n_fts(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val, mask;
|
||||
|
||||
switch (pcie_link_speed[lpp->max_speed]) {
|
||||
case PCIE_SPEED_8_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN3;
|
||||
switch (pci->link_gen) {
|
||||
case 3:
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN3;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN4;
|
||||
case 4:
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN4;
|
||||
break;
|
||||
default:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
break;
|
||||
}
|
||||
|
||||
mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK;
|
||||
val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) |
|
||||
FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts);
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val);
|
||||
|
||||
/* Port Link Control Register */
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN,
|
||||
PORT_LINK_DLL_LINK_EN);
|
||||
pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
}
|
||||
|
||||
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_ltssm_disable(lpp);
|
||||
intel_pcie_link_setup(lpp);
|
||||
intel_pcie_init_n_fts(&lpp->pci);
|
||||
dw_pcie_setup_rc(&lpp->pci.pp);
|
||||
dw_pcie_upconfig_setup(&lpp->pci);
|
||||
intel_pcie_port_logic_setup(lpp);
|
||||
dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen);
|
||||
dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts);
|
||||
}
|
||||
|
||||
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
|
||||
@ -275,20 +254,11 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_match_string(dev, "device_type", "pci");
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to find pci device type: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(dev, "reset-assert-ms",
|
||||
&lpp->rst_intrvl);
|
||||
if (ret)
|
||||
lpp->rst_intrvl = RESET_INTERVAL_MS;
|
||||
|
||||
ret = of_pci_get_max_link_speed(dev->of_node);
|
||||
lpp->link_gen = ret < 0 ? 0 : ret;
|
||||
|
||||
lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
|
||||
if (IS_ERR(lpp->app_base))
|
||||
return PTR_ERR(lpp->app_base);
|
||||
@ -313,8 +283,9 @@ static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 value;
|
||||
int ret;
|
||||
struct dw_pcie *pci = &lpp->pci;
|
||||
|
||||
if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT)
|
||||
if (pci->link_gen < 3)
|
||||
return 0;
|
||||
|
||||
/* Send PME_TURN_OFF message */
|
||||
@ -343,7 +314,6 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
|
||||
|
||||
static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
struct device *dev = lpp->pci.dev;
|
||||
int ret;
|
||||
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
@ -361,17 +331,6 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
if (!lpp->pcie_cap_ofst) {
|
||||
ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
|
||||
if (!ret) {
|
||||
ret = -ENXIO;
|
||||
dev_err(dev, "Invalid PCIe capability offset\n");
|
||||
goto app_init_err;
|
||||
}
|
||||
|
||||
lpp->pcie_cap_ofst = ret;
|
||||
}
|
||||
|
||||
intel_pcie_rc_setup(lpp);
|
||||
ret = intel_pcie_app_logic_setup(lpp);
|
||||
if (ret)
|
||||
|
@ -330,34 +330,37 @@ static void kirin_pcie_sideband_dbi_r_mode(struct kirin_pcie *kirin_pcie,
|
||||
kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL1_ADDR);
|
||||
}
|
||||
|
||||
static int kirin_pcie_rd_own_conf(struct pcie_port *pp,
|
||||
static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
kirin_pcie_sideband_dbi_r_mode(kirin_pcie, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
kirin_pcie_sideband_dbi_r_mode(kirin_pcie, false);
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ret;
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int kirin_pcie_wr_own_conf(struct pcie_port *pp,
|
||||
static int kirin_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
kirin_pcie_sideband_dbi_w_mode(kirin_pcie, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false);
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return ret;
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops kirin_pci_ops = {
|
||||
.read = kirin_pcie_rd_own_conf,
|
||||
.write = kirin_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static u32 kirin_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size)
|
||||
{
|
||||
@ -423,10 +426,10 @@ static int kirin_pcie_establish_link(struct pcie_port *pp)
|
||||
|
||||
static int kirin_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
kirin_pcie_establish_link(pp);
|
||||
pp->bridge->ops = &kirin_pci_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
kirin_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -438,8 +441,6 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
|
||||
.rd_own_conf = kirin_pcie_rd_own_conf,
|
||||
.wr_own_conf = kirin_pcie_wr_own_conf,
|
||||
.host_init = kirin_pcie_host_init,
|
||||
};
|
||||
|
||||
@ -507,8 +508,12 @@ static int kirin_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node,
|
||||
"reset-gpios", 0);
|
||||
if (kirin_pcie->gpio_id_reset < 0)
|
||||
if (kirin_pcie->gpio_id_reset == -EPROBE_DEFER) {
|
||||
return -EPROBE_DEFER;
|
||||
} else if (!gpio_is_valid(kirin_pcie->gpio_id_reset)) {
|
||||
dev_err(dev, "unable to get a valid gpio pin\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = kirin_pcie_power_on(kirin_pcie);
|
||||
if (ret)
|
||||
|
@ -67,10 +67,6 @@
|
||||
#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c
|
||||
#define CFG_BRIDGE_SB_INIT BIT(0)
|
||||
|
||||
#define PCIE20_CAP 0x70
|
||||
#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
|
||||
|
||||
#define PCIE20_PARF_Q2A_FLUSH 0x1AC
|
||||
@ -193,7 +189,6 @@ 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)
|
||||
@ -302,6 +297,9 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
|
||||
reset_control_assert(res->por_reset);
|
||||
reset_control_assert(res->ext_reset);
|
||||
reset_control_assert(res->phy_reset);
|
||||
|
||||
writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
|
||||
}
|
||||
|
||||
@ -314,6 +312,16 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* reset the PCIe interface as uboot can leave it undefined state */
|
||||
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->ext_reset);
|
||||
reset_control_assert(res->phy_reset);
|
||||
|
||||
writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable regulators\n");
|
||||
@ -394,12 +402,6 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
|
||||
/* 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,
|
||||
pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
|
||||
@ -1017,6 +1019,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
|
||||
struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
@ -1092,14 +1095,14 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
|
||||
|
||||
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);
|
||||
writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
|
||||
|
||||
val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_ASPMS;
|
||||
writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
|
||||
|
||||
writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base +
|
||||
PCIE20_DEVICE_CONTROL2_STATUS2);
|
||||
writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
|
||||
PCI_EXP_DEVCTL2);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1252,7 +1255,8 @@ static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
|
||||
|
||||
static int qcom_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
|
||||
|
||||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
@ -1280,9 +1284,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
qcom_ep_reset_deassert(pcie);
|
||||
|
||||
@ -1399,10 +1401,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
goto err_pm_runtime_put;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -26,7 +26,6 @@ struct spear13xx_pcie {
|
||||
void __iomem *app_base;
|
||||
struct phy *phy;
|
||||
struct clk *clk;
|
||||
bool is_gen1;
|
||||
};
|
||||
|
||||
struct pcie_app_reg {
|
||||
@ -65,8 +64,6 @@ struct pcie_app_reg {
|
||||
/* CR6 */
|
||||
#define MSI_CTRL_INT (1 << 26)
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
@ -75,7 +72,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
|
||||
u32 val;
|
||||
u32 exp_cap_off = EXP_CAP_ID_OFFSET;
|
||||
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(pci->dev, "link already up\n");
|
||||
@ -89,36 +86,12 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
* default value in capability register is 512 bytes. So force
|
||||
* it to 128 here.
|
||||
*/
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
|
||||
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
|
||||
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
|
||||
|
||||
dw_pcie_write(pci->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
|
||||
dw_pcie_write(pci->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
|
||||
|
||||
/*
|
||||
* if is_gen1 is set then handle it, so that some buggy card
|
||||
* also works
|
||||
*/
|
||||
if (spear13xx_pcie->is_gen1) {
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
|
||||
4, &val);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCAP, 4, val);
|
||||
}
|
||||
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
|
||||
2, &val);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCTL2, 2, val);
|
||||
}
|
||||
}
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
|
||||
|
||||
/* enable ltssm */
|
||||
writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
|
||||
@ -278,7 +251,7 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
|
||||
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
|
||||
|
||||
if (of_property_read_bool(np, "st,pcie-is-gen1"))
|
||||
spear13xx_pcie->is_gen1 = true;
|
||||
pci->link_gen = 1;
|
||||
|
||||
platform_set_drvdata(pdev, spear13xx_pcie);
|
||||
|
||||
|
@ -183,19 +183,7 @@
|
||||
#define EVENT_COUNTER_GROUP_SEL_SHIFT 24
|
||||
#define EVENT_COUNTER_GROUP_5 0x5
|
||||
|
||||
#define PORT_LOGIC_ACK_F_ASPM_CTRL 0x70C
|
||||
#define ENTER_ASPM BIT(30)
|
||||
#define L0S_ENTRANCE_LAT_SHIFT 24
|
||||
#define L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)
|
||||
#define L1_ENTRANCE_LAT_SHIFT 27
|
||||
#define L1_ENTRANCE_LAT_MASK GENMASK(29, 27)
|
||||
#define N_FTS_SHIFT 8
|
||||
#define N_FTS_MASK GENMASK(7, 0)
|
||||
#define N_FTS_VAL 52
|
||||
|
||||
#define PORT_LOGIC_GEN2_CTRL 0x80C
|
||||
#define PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE BIT(17)
|
||||
#define FTS_MASK GENMASK(7, 0)
|
||||
#define FTS_VAL 52
|
||||
|
||||
#define PORT_LOGIC_MSI_CTRL_INT_0_EN 0x828
|
||||
@ -296,7 +284,6 @@ struct tegra_pcie_dw {
|
||||
u8 init_link_width;
|
||||
u32 msi_ctrl_int;
|
||||
u32 num_lanes;
|
||||
u32 max_speed;
|
||||
u32 cid;
|
||||
u32 cfg_link_cap_l1sub;
|
||||
u32 pcie_cap_base;
|
||||
@ -401,9 +388,9 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
|
||||
val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
|
||||
appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val |= PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,42 +555,44 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
static int tegra_pcie_dw_rd_own_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* This is an endpoint mode specific register happen to appear even
|
||||
* when controller is operating in root port mode and system hangs
|
||||
* when it is accessed with link being in ASPM-L1 state.
|
||||
* So skip accessing it altogether
|
||||
*/
|
||||
if (where == PORT_LOGIC_MSIX_DOORBELL) {
|
||||
if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) {
|
||||
*val = 0x00000000;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
return dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
return pci_generic_config_read(bus, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
static int tegra_pcie_dw_wr_own_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* This is an endpoint mode specific register happen to appear even
|
||||
* when controller is operating in root port mode and system hangs
|
||||
* when it is accessed with link being in ASPM-L1 state.
|
||||
* So skip accessing it altogether
|
||||
*/
|
||||
if (where == PORT_LOGIC_MSIX_DOORBELL)
|
||||
if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL)
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
return pci_generic_config_write(bus, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static struct pci_ops tegra_pci_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = tegra_pcie_dw_rd_own_conf,
|
||||
.write = tegra_pcie_dw_wr_own_conf,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PCIEASPM)
|
||||
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
@ -692,30 +681,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
|
||||
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
|
||||
|
||||
/* Program L0s and L1 entrance latencies */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~L0S_ENTRANCE_LAT_MASK;
|
||||
val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT);
|
||||
val |= ENTER_ASPM;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
|
||||
val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT);
|
||||
val |= PORT_AFR_ENTER_ASPM;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
|
||||
}
|
||||
|
||||
static int init_debugfs(struct tegra_pcie_dw *pcie)
|
||||
static void init_debugfs(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
|
||||
pcie->debugfs, aspm_state_cnt);
|
||||
if (IS_ERR_OR_NULL(d))
|
||||
dev_err(pcie->dev,
|
||||
"Failed to create debugfs file \"aspm_state_cnt\"\n");
|
||||
|
||||
return 0;
|
||||
debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs,
|
||||
aspm_state_cnt);
|
||||
}
|
||||
#else
|
||||
static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
|
||||
static inline int init_debugfs(struct tegra_pcie_dw *pcie) { return 0; }
|
||||
static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; }
|
||||
#endif
|
||||
|
||||
static void tegra_pcie_enable_system_interrupts(struct pcie_port *pp)
|
||||
@ -827,26 +809,24 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
|
||||
|
||||
/* Program init preset */
|
||||
for (i = 0; i < pcie->num_lanes; i++) {
|
||||
dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF
|
||||
+ (i * 2), 2, &val);
|
||||
val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2));
|
||||
val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
|
||||
val |= GEN3_GEN4_EQ_PRESET_INIT;
|
||||
val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
|
||||
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
|
||||
CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
|
||||
dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF
|
||||
+ (i * 2), 2, val);
|
||||
dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
|
||||
|
||||
offset = dw_pcie_find_ext_capability(pci,
|
||||
PCI_EXT_CAP_ID_PL_16GT) +
|
||||
PCI_PL_16GT_LE_CTRL;
|
||||
dw_pcie_read(pci->dbi_base + offset + i, 1, &val);
|
||||
val = dw_pcie_readb_dbi(pci, offset + i);
|
||||
val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
|
||||
val |= GEN3_GEN4_EQ_PRESET_INIT;
|
||||
val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
|
||||
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
|
||||
PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
|
||||
dw_pcie_write(pci->dbi_base + offset + i, 1, val);
|
||||
dw_pcie_writeb_dbi(pci, offset + i, val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
@ -892,17 +872,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
|
||||
/* Configure FTS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~(N_FTS_MASK << N_FTS_SHIFT);
|
||||
val |= N_FTS_VAL << N_FTS_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val &= ~FTS_MASK;
|
||||
val |= FTS_VAL;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
|
||||
/* Enable as 0xFFFF0001 response for CRS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
|
||||
val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
@ -910,16 +879,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
|
||||
|
||||
/* Configure Max Speed from DT */
|
||||
if (pcie->max_speed && pcie->max_speed != -EINVAL) {
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_SLS;
|
||||
val |= pcie->max_speed;
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
/* Configure Max lane width from DT */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_MLW;
|
||||
@ -970,6 +929,8 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp)
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val, tmp, offset, speed;
|
||||
|
||||
pp->bridge->ops = &tegra_pci_ops;
|
||||
|
||||
tegra_pcie_prepare_host(pp);
|
||||
|
||||
if (dw_pcie_wait_for_link(pci)) {
|
||||
@ -1057,8 +1018,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
|
||||
};
|
||||
|
||||
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
|
||||
.rd_own_conf = tegra_pcie_dw_rd_own_conf,
|
||||
.wr_own_conf = tegra_pcie_dw_wr_own_conf,
|
||||
.host_init = tegra_pcie_dw_host_init,
|
||||
.set_num_vectors = tegra_pcie_set_msi_vec_num,
|
||||
};
|
||||
@ -1129,8 +1088,6 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcie->max_speed = of_pci_get_max_link_speed(np);
|
||||
|
||||
ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid);
|
||||
if (ret) {
|
||||
dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret);
|
||||
@ -1262,9 +1219,9 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
|
||||
* 5.2 Link State Power Management (Page #428).
|
||||
*/
|
||||
|
||||
list_for_each_entry(child, &pp->root_bus->children, node) {
|
||||
list_for_each_entry(child, &pp->bridge->bus->children, node) {
|
||||
/* Bring downstream devices to D0 if they are not already in */
|
||||
if (child->parent == pp->root_bus) {
|
||||
if (child->parent == pp->bridge->bus) {
|
||||
root_bus = child;
|
||||
break;
|
||||
}
|
||||
@ -1641,10 +1598,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
|
||||
}
|
||||
|
||||
pcie->debugfs = debugfs_create_dir(name, NULL);
|
||||
if (!pcie->debugfs)
|
||||
dev_err(dev, "Failed to create debugfs\n");
|
||||
else
|
||||
init_debugfs(pcie);
|
||||
init_debugfs(pcie);
|
||||
|
||||
return ret;
|
||||
|
||||
@ -1817,27 +1771,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
|
||||
/* Configure N_FTS & FTS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~(N_FTS_MASK << N_FTS_SHIFT);
|
||||
val |= N_FTS_VAL << N_FTS_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val &= ~FTS_MASK;
|
||||
val |= FTS_VAL;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
|
||||
/* Configure Max Speed from DT */
|
||||
if (pcie->max_speed && pcie->max_speed != -EINVAL) {
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_SLS;
|
||||
val |= pcie->max_speed;
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
|
||||
@ -2066,6 +1999,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
pci = &pcie->pci;
|
||||
pci->dev = &pdev->dev;
|
||||
pci->ops = &tegra_dw_pcie_ops;
|
||||
pci->n_fts[0] = N_FTS_VAL;
|
||||
pci->n_fts[1] = FTS_VAL;
|
||||
|
||||
pp = &pci->pp;
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->mode = (enum dw_pcie_device_mode)data->mode;
|
||||
|
@ -322,8 +322,7 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -480,7 +480,6 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct mobiveil_root_port *rp = &pcie->rp;
|
||||
int ret;
|
||||
|
||||
/* setup INTx */
|
||||
rp->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
|
||||
@ -494,11 +493,7 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
|
||||
raw_spin_lock_init(&rp->intx_mask_lock);
|
||||
|
||||
/* setup MSI */
|
||||
ret = mobiveil_allocate_msi_domains(pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return mobiveil_allocate_msi_domains(pcie);
|
||||
}
|
||||
|
||||
static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie)
|
||||
|
@ -9,11 +9,12 @@
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/phy/phy.h>
|
||||
@ -251,6 +252,25 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
|
||||
}
|
||||
}
|
||||
|
||||
static void advk_pcie_issue_perst(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!pcie->reset_gpio)
|
||||
return;
|
||||
|
||||
/* PERST does not work for some cards when link training is enabled */
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
|
||||
reg &= ~LINK_TRAINING_EN;
|
||||
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
|
||||
|
||||
/* 10ms delay is needed for some cards */
|
||||
dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
|
||||
}
|
||||
|
||||
static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen)
|
||||
{
|
||||
int ret, neg_gen;
|
||||
@ -298,6 +318,21 @@ static void advk_pcie_train_link(struct advk_pcie *pcie)
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
int neg_gen = -1, gen;
|
||||
|
||||
/*
|
||||
* Reset PCIe card via PERST# signal. Some cards are not detected
|
||||
* during link training when they are in some non-initial state.
|
||||
*/
|
||||
advk_pcie_issue_perst(pcie);
|
||||
|
||||
/*
|
||||
* PERST# signal could have been asserted by pinctrl subsystem before
|
||||
* probe() callback has been called or issued explicitly by reset gpio
|
||||
* function advk_pcie_issue_perst(), making the endpoint going into
|
||||
* fundamental reset. As required by PCI Express spec a delay for at
|
||||
* least 100ms after such a reset before link training is needed.
|
||||
*/
|
||||
msleep(PCI_PM_D3COLD_WAIT);
|
||||
|
||||
/*
|
||||
* Try link training at link gen specified by device tree property
|
||||
* 'max-link-speed'. If this fails, iteratively train at lower gen.
|
||||
@ -330,31 +365,10 @@ err:
|
||||
dev_err(dev, "link never came up\n");
|
||||
}
|
||||
|
||||
static void advk_pcie_issue_perst(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!pcie->reset_gpio)
|
||||
return;
|
||||
|
||||
/* PERST does not work for some cards when link training is enabled */
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
|
||||
reg &= ~LINK_TRAINING_EN;
|
||||
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
|
||||
|
||||
/* 10ms delay is needed for some cards */
|
||||
dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
|
||||
}
|
||||
|
||||
static void advk_pcie_setup_hw(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
advk_pcie_issue_perst(pcie);
|
||||
|
||||
/* Enable TX */
|
||||
reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG);
|
||||
reg |= PCIE_CORE_REF_CLK_TX_ENABLE;
|
||||
@ -431,15 +445,6 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
|
||||
reg |= PIO_CTRL_ADDR_WIN_DISABLE;
|
||||
advk_writel(pcie, reg, PIO_CTRL);
|
||||
|
||||
/*
|
||||
* PERST# signal could have been asserted by pinctrl subsystem before
|
||||
* probe() callback has been called or issued explicitly by reset gpio
|
||||
* function advk_pcie_issue_perst(), making the endpoint going into
|
||||
* fundamental reset. As required by PCI Express spec a delay for at
|
||||
* least 100ms after such a reset before link training is needed.
|
||||
*/
|
||||
msleep(PCI_PM_D3COLD_WAIT);
|
||||
|
||||
advk_pcie_train_link(pcie);
|
||||
|
||||
/*
|
||||
@ -607,7 +612,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
|
||||
* Initialize the configuration space of the PCI-to-PCI bridge
|
||||
* associated with the given PCIe interface.
|
||||
*/
|
||||
static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
|
||||
static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
|
||||
{
|
||||
struct pci_bridge_emul *bridge = &pcie->bridge;
|
||||
|
||||
@ -633,8 +638,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
|
||||
bridge->data = pcie;
|
||||
bridge->ops = &advk_pci_bridge_emul_ops;
|
||||
|
||||
pci_bridge_emul_init(bridge, 0);
|
||||
|
||||
return pci_bridge_emul_init(bridge, 0);
|
||||
}
|
||||
|
||||
static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
|
||||
@ -1077,7 +1081,9 @@ static int advk_pcie_enable_phy(struct advk_pcie *pcie)
|
||||
}
|
||||
|
||||
ret = phy_power_on(pcie->phy);
|
||||
if (ret) {
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n");
|
||||
} else if (ret) {
|
||||
phy_exit(pcie->phy);
|
||||
return ret;
|
||||
}
|
||||
@ -1122,6 +1128,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pcie = pci_host_bridge_priv(bridge);
|
||||
pcie->pdev = pdev;
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pcie->base))
|
||||
@ -1167,7 +1174,11 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
advk_pcie_setup_hw(pcie);
|
||||
|
||||
advk_sw_pci_bridge_init(pcie);
|
||||
ret = advk_sw_pci_bridge_init(pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register emulated root PCI bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = advk_pcie_init_irq_domain(pcie);
|
||||
if (ret) {
|
||||
@ -1195,18 +1206,37 @@ static int advk_pcie_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int advk_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct advk_pcie *pcie = platform_get_drvdata(pdev);
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_root_bus(bridge->bus);
|
||||
pci_remove_root_bus(bridge->bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id advk_pcie_of_match_table[] = {
|
||||
{ .compatible = "marvell,armada-3700-pcie", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, advk_pcie_of_match_table);
|
||||
|
||||
static struct platform_driver advk_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "advk-pcie",
|
||||
.of_match_table = advk_pcie_of_match_table,
|
||||
/* Driver unloading/unbinding currently not supported */
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = advk_pcie_probe,
|
||||
.remove = advk_pcie_remove,
|
||||
};
|
||||
builtin_platform_driver(advk_pcie_driver);
|
||||
module_platform_driver(advk_pcie_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Aardvark PCIe controller");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1276,11 +1276,25 @@ static void hv_irq_unmask(struct irq_data *data)
|
||||
exit_unlock:
|
||||
spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags);
|
||||
|
||||
if (res) {
|
||||
/*
|
||||
* During hibernation, when a CPU is offlined, the kernel tries
|
||||
* to move the interrupt to the remaining CPUs that haven't
|
||||
* been offlined yet. In this case, the below hv_do_hypercall()
|
||||
* always fails since the vmbus channel has been closed:
|
||||
* refer to cpu_disable_common() -> fixup_irqs() ->
|
||||
* irq_migrate_all_off_this_cpu() -> migrate_one_irq().
|
||||
*
|
||||
* Suppress the error message for hibernation because the failure
|
||||
* during hibernation does not matter (at this time all the devices
|
||||
* have been frozen). Note: the correct affinity info is still updated
|
||||
* into the irqdata data structure in migrate_one_irq() ->
|
||||
* irq_do_set_affinity() -> hv_set_affinity(), so later when the VM
|
||||
* resumes, hv_pci_restore_msi_state() is able to correctly restore
|
||||
* the interrupt with the correct affinity.
|
||||
*/
|
||||
if (res && hbus->state != hv_pcibus_removing)
|
||||
dev_err(&hbus->hdev->device,
|
||||
"%s() failed: %#llx", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_msi_unmask_irq(data);
|
||||
}
|
||||
@ -3367,6 +3381,34 @@ static int hv_pci_suspend(struct hv_device *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg)
|
||||
{
|
||||
struct msi_desc *entry;
|
||||
struct irq_data *irq_data;
|
||||
|
||||
for_each_pci_msi_entry(entry, pdev) {
|
||||
irq_data = irq_get_irq_data(entry->irq);
|
||||
if (WARN_ON_ONCE(!irq_data))
|
||||
return -EINVAL;
|
||||
|
||||
hv_compose_msi_msg(irq_data, &entry->msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upon resume, pci_restore_msi_state() -> ... -> __pci_write_msi_msg()
|
||||
* directly writes the MSI/MSI-X registers via MMIO, but since Hyper-V
|
||||
* doesn't trap and emulate the MMIO accesses, here hv_compose_msi_msg()
|
||||
* must be used to ask Hyper-V to re-create the IOMMU Interrupt Remapping
|
||||
* Table entries.
|
||||
*/
|
||||
static void hv_pci_restore_msi_state(struct hv_pcibus_device *hbus)
|
||||
{
|
||||
pci_walk_bus(hbus->pci_bus, hv_pci_restore_msi_msg, NULL);
|
||||
}
|
||||
|
||||
static int hv_pci_resume(struct hv_device *hdev)
|
||||
{
|
||||
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
|
||||
@ -3400,6 +3442,8 @@ static int hv_pci_resume(struct hv_device *hdev)
|
||||
|
||||
prepopulate_bars(hbus);
|
||||
|
||||
hv_pci_restore_msi_state(hbus);
|
||||
|
||||
hbus->state = hv_pcibus_installed;
|
||||
return 0;
|
||||
out:
|
||||
|
@ -183,7 +183,6 @@ static int loongson_pci_probe(struct platform_device *pdev)
|
||||
struct device_node *node = dev->of_node;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource *regs;
|
||||
int err;
|
||||
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
@ -222,11 +221,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
|
||||
bridge->ops = &loongson_pci_ops;
|
||||
bridge->map_irq = loongson_map_irq;
|
||||
|
||||
err = pci_host_probe(bridge);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return pci_host_probe(bridge);
|
||||
}
|
||||
|
||||
static struct platform_driver loongson_pci_driver = {
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
@ -70,7 +69,6 @@ struct mvebu_pcie_port;
|
||||
struct mvebu_pcie {
|
||||
struct platform_device *pdev;
|
||||
struct mvebu_pcie_port *ports;
|
||||
struct msi_controller *msi;
|
||||
struct resource io;
|
||||
struct resource realio;
|
||||
struct resource mem;
|
||||
@ -1127,7 +1125,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
|
||||
bridge->sysdata = pcie;
|
||||
bridge->ops = &mvebu_pcie_ops;
|
||||
bridge->align_resource = mvebu_pcie_align_resource;
|
||||
bridge->msi = pcie->msi;
|
||||
|
||||
return mvebu_pci_host_probe(bridge);
|
||||
}
|
||||
|
@ -2564,36 +2564,14 @@ static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations tegra_pcie_ports_seq_ops = {
|
||||
static const struct seq_operations tegra_pcie_ports_sops = {
|
||||
.start = tegra_pcie_ports_seq_start,
|
||||
.next = tegra_pcie_ports_seq_next,
|
||||
.stop = tegra_pcie_ports_seq_stop,
|
||||
.show = tegra_pcie_ports_seq_show,
|
||||
};
|
||||
|
||||
static int tegra_pcie_ports_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tegra_pcie *pcie = inode->i_private;
|
||||
struct seq_file *s;
|
||||
int err;
|
||||
|
||||
err = seq_open(file, &tegra_pcie_ports_seq_ops);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
s = file->private_data;
|
||||
s->private = pcie;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations tegra_pcie_ports_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = tegra_pcie_ports_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports);
|
||||
|
||||
static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
|
||||
{
|
||||
@ -2601,24 +2579,12 @@ static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie)
|
||||
pcie->debugfs = NULL;
|
||||
}
|
||||
|
||||
static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
|
||||
static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
|
||||
{
|
||||
struct dentry *file;
|
||||
|
||||
pcie->debugfs = debugfs_create_dir("pcie", NULL);
|
||||
if (!pcie->debugfs)
|
||||
return -ENOMEM;
|
||||
|
||||
file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs,
|
||||
pcie, &tegra_pcie_ports_ops);
|
||||
if (!file)
|
||||
goto remove;
|
||||
|
||||
return 0;
|
||||
|
||||
remove:
|
||||
tegra_pcie_debugfs_exit(pcie);
|
||||
return -ENOMEM;
|
||||
debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie,
|
||||
&tegra_pcie_ports_fops);
|
||||
}
|
||||
|
||||
static int tegra_pcie_probe(struct platform_device *pdev)
|
||||
@ -2672,11 +2638,8 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
||||
goto pm_runtime_put;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
||||
err = tegra_pcie_debugfs_init(pcie);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to setup debugfs: %d\n", err);
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
tegra_pcie_debugfs_init(pcie);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -658,7 +658,6 @@ static int v3_get_dma_range_config(struct v3_pci *v3,
|
||||
default:
|
||||
dev_err(v3->dev, "illegal dma memory chunk size\n");
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
val |= V3_PCI_MAP_M_REG_EN | V3_PCI_MAP_M_ENABLE;
|
||||
*pci_map = val;
|
||||
|
@ -493,8 +493,8 @@ static int xgene_msi_probe(struct platform_device *pdev)
|
||||
*/
|
||||
for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) {
|
||||
for (msi_idx = 0; msi_idx < IDX_PER_GROUP; msi_idx++)
|
||||
msi_val = xgene_msi_ir_read(xgene_msi, irq_index,
|
||||
msi_idx);
|
||||
xgene_msi_ir_read(xgene_msi, irq_index, msi_idx);
|
||||
|
||||
/* Read MSIINTn to confirm */
|
||||
msi_val = xgene_msi_int_read(xgene_msi, irq_index);
|
||||
if (msi_val) {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
@ -52,8 +53,11 @@
|
||||
#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
|
||||
#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
|
||||
#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
|
||||
#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0
|
||||
|
||||
#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
|
||||
#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x07c00000
|
||||
#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x0000001f
|
||||
#define SCB_SIZE_MASK(x) PCIE_MISC_MISC_CTRL_SCB ## x ## _SIZE_MASK
|
||||
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
|
||||
#define PCIE_MEM_WIN0_LO(win) \
|
||||
@ -77,10 +81,12 @@
|
||||
#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
|
||||
|
||||
#define PCIE_MISC_MSI_DATA_CONFIG 0x404c
|
||||
#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540
|
||||
#define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540
|
||||
#define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540
|
||||
|
||||
#define PCIE_MISC_PCIE_CTRL 0x4064
|
||||
#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
|
||||
#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
|
||||
|
||||
#define PCIE_MISC_PCIE_STATUS 0x4068
|
||||
#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
|
||||
@ -88,6 +94,9 @@
|
||||
#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
|
||||
#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
|
||||
|
||||
#define PCIE_MISC_REVISION 0x406c
|
||||
#define BRCM_PCIE_HW_REV_33 0x0303
|
||||
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
|
||||
@ -108,10 +117,14 @@
|
||||
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
|
||||
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
|
||||
|
||||
#define PCIE_MSI_INTR2_STATUS 0x4500
|
||||
#define PCIE_MSI_INTR2_CLR 0x4508
|
||||
#define PCIE_MSI_INTR2_MASK_SET 0x4510
|
||||
#define PCIE_MSI_INTR2_MASK_CLR 0x4514
|
||||
|
||||
#define PCIE_INTR2_CPU_BASE 0x4300
|
||||
#define PCIE_MSI_INTR2_BASE 0x4500
|
||||
/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */
|
||||
#define MSI_INT_STATUS 0x0
|
||||
#define MSI_INT_CLR 0x8
|
||||
#define MSI_INT_MASK_SET 0x10
|
||||
#define MSI_INT_MASK_CLR 0x14
|
||||
|
||||
#define PCIE_EXT_CFG_DATA 0x8000
|
||||
|
||||
@ -120,13 +133,19 @@
|
||||
#define PCIE_EXT_SLOT_SHIFT 15
|
||||
#define PCIE_EXT_FUNC_SHIFT 12
|
||||
|
||||
#define PCIE_RGR1_SW_INIT_1 0x9210
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
|
||||
#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
|
||||
|
||||
#define RGR1_SW_INIT_1_INIT_GENERIC_MASK 0x2
|
||||
#define RGR1_SW_INIT_1_INIT_GENERIC_SHIFT 0x1
|
||||
#define RGR1_SW_INIT_1_INIT_7278_MASK 0x1
|
||||
#define RGR1_SW_INIT_1_INIT_7278_SHIFT 0x0
|
||||
|
||||
/* PCIe parameters */
|
||||
#define BRCM_NUM_PCIE_OUT_WINS 0x4
|
||||
#define BRCM_INT_PCI_MSI_NR 32
|
||||
#define BRCM_INT_PCI_MSI_LEGACY_NR 8
|
||||
#define BRCM_INT_PCI_MSI_SHIFT 0
|
||||
|
||||
/* MSI target adresses */
|
||||
#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
|
||||
@ -151,6 +170,85 @@
|
||||
#define SSC_STATUS_OFFSET 0x1
|
||||
#define SSC_STATUS_SSC_MASK 0x400
|
||||
#define SSC_STATUS_PLL_LOCK_MASK 0x800
|
||||
#define PCIE_BRCM_MAX_MEMC 3
|
||||
|
||||
#define IDX_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_INDEX])
|
||||
#define DATA_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_DATA])
|
||||
#define PCIE_RGR1_SW_INIT_1(pcie) (pcie->reg_offsets[RGR1_SW_INIT_1])
|
||||
|
||||
/* Rescal registers */
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL 0xc700
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS 0x3
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK 0x4
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT 0x2
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK 0x2
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT 0x1
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK 0x1
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT 0x0
|
||||
|
||||
/* Forward declarations */
|
||||
struct brcm_pcie;
|
||||
static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val);
|
||||
static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val);
|
||||
static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val);
|
||||
static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val);
|
||||
|
||||
enum {
|
||||
RGR1_SW_INIT_1,
|
||||
EXT_CFG_INDEX,
|
||||
EXT_CFG_DATA,
|
||||
};
|
||||
|
||||
enum {
|
||||
RGR1_SW_INIT_1_INIT_MASK,
|
||||
RGR1_SW_INIT_1_INIT_SHIFT,
|
||||
};
|
||||
|
||||
enum pcie_type {
|
||||
GENERIC,
|
||||
BCM7278,
|
||||
BCM2711,
|
||||
};
|
||||
|
||||
struct pcie_cfg_data {
|
||||
const int *offsets;
|
||||
const enum pcie_type type;
|
||||
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
||||
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
||||
};
|
||||
|
||||
static const int pcie_offsets[] = {
|
||||
[RGR1_SW_INIT_1] = 0x9210,
|
||||
[EXT_CFG_INDEX] = 0x9000,
|
||||
[EXT_CFG_DATA] = 0x9004,
|
||||
};
|
||||
|
||||
static const struct pcie_cfg_data generic_cfg = {
|
||||
.offsets = pcie_offsets,
|
||||
.type = GENERIC,
|
||||
.perst_set = brcm_pcie_perst_set_generic,
|
||||
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
||||
};
|
||||
|
||||
static const int pcie_offset_bcm7278[] = {
|
||||
[RGR1_SW_INIT_1] = 0xc010,
|
||||
[EXT_CFG_INDEX] = 0x9000,
|
||||
[EXT_CFG_DATA] = 0x9004,
|
||||
};
|
||||
|
||||
static const struct pcie_cfg_data bcm7278_cfg = {
|
||||
.offsets = pcie_offset_bcm7278,
|
||||
.type = BCM7278,
|
||||
.perst_set = brcm_pcie_perst_set_7278,
|
||||
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278,
|
||||
};
|
||||
|
||||
static const struct pcie_cfg_data bcm2711_cfg = {
|
||||
.offsets = pcie_offsets,
|
||||
.type = BCM2711,
|
||||
.perst_set = brcm_pcie_perst_set_generic,
|
||||
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
||||
};
|
||||
|
||||
struct brcm_msi {
|
||||
struct device *dev;
|
||||
@ -163,6 +261,12 @@ struct brcm_msi {
|
||||
int irq;
|
||||
/* used indicates which MSI interrupts have been alloc'd */
|
||||
unsigned long used;
|
||||
bool legacy;
|
||||
/* Some chips have MSIs in bits [31..24] of a shared register. */
|
||||
int legacy_shift;
|
||||
int nr; /* No. of MSI available, depends on chip */
|
||||
/* This is the base pointer for interrupt status/set/clr regs */
|
||||
void __iomem *intr_base;
|
||||
};
|
||||
|
||||
/* Internal PCIe Host Controller Information.*/
|
||||
@ -175,6 +279,14 @@ struct brcm_pcie {
|
||||
int gen;
|
||||
u64 msi_target_addr;
|
||||
struct brcm_msi *msi;
|
||||
const int *reg_offsets;
|
||||
enum pcie_type type;
|
||||
struct reset_control *rescal;
|
||||
int num_memc;
|
||||
u64 memc_size[PCIE_BRCM_MAX_MEMC];
|
||||
u32 hw_rev;
|
||||
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
||||
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -365,8 +477,10 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc)
|
||||
msi = irq_desc_get_handler_data(desc);
|
||||
dev = msi->dev;
|
||||
|
||||
status = readl(msi->base + PCIE_MSI_INTR2_STATUS);
|
||||
for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
|
||||
status = readl(msi->intr_base + MSI_INT_STATUS);
|
||||
status >>= msi->legacy_shift;
|
||||
|
||||
for_each_set_bit(bit, &status, msi->nr) {
|
||||
virq = irq_find_mapping(msi->inner_domain, bit);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
@ -383,7 +497,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
|
||||
msg->address_lo = lower_32_bits(msi->target_addr);
|
||||
msg->address_hi = upper_32_bits(msi->target_addr);
|
||||
msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq;
|
||||
msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq;
|
||||
}
|
||||
|
||||
static int brcm_msi_set_affinity(struct irq_data *irq_data,
|
||||
@ -395,8 +509,9 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data,
|
||||
static void brcm_msi_ack_irq(struct irq_data *data)
|
||||
{
|
||||
struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
|
||||
const int shift_amt = data->hwirq + msi->legacy_shift;
|
||||
|
||||
writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR);
|
||||
writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR);
|
||||
}
|
||||
|
||||
|
||||
@ -412,7 +527,7 @@ static int brcm_msi_alloc(struct brcm_msi *msi)
|
||||
int hwirq;
|
||||
|
||||
mutex_lock(&msi->lock);
|
||||
hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0);
|
||||
hwirq = bitmap_find_free_region(&msi->used, msi->nr, 0);
|
||||
mutex_unlock(&msi->lock);
|
||||
|
||||
return hwirq;
|
||||
@ -461,8 +576,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi)
|
||||
struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);
|
||||
struct device *dev = msi->dev;
|
||||
|
||||
msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
|
||||
&msi_domain_ops, msi);
|
||||
msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi);
|
||||
if (!msi->inner_domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
@ -499,7 +613,10 @@ static void brcm_msi_remove(struct brcm_pcie *pcie)
|
||||
|
||||
static void brcm_msi_set_regs(struct brcm_msi *msi)
|
||||
{
|
||||
writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR);
|
||||
u32 val = __GENMASK(31, msi->legacy_shift);
|
||||
|
||||
writel(val, msi->intr_base + MSI_INT_MASK_CLR);
|
||||
writel(val, msi->intr_base + MSI_INT_CLR);
|
||||
|
||||
/*
|
||||
* The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
|
||||
@ -510,8 +627,8 @@ static void brcm_msi_set_regs(struct brcm_msi *msi)
|
||||
writel(upper_32_bits(msi->target_addr),
|
||||
msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
|
||||
|
||||
writel(PCIE_MISC_MSI_DATA_CONFIG_VAL,
|
||||
msi->base + PCIE_MISC_MSI_DATA_CONFIG);
|
||||
val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32;
|
||||
writel(val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
|
||||
}
|
||||
|
||||
static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
|
||||
@ -536,6 +653,17 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
|
||||
msi->np = pcie->np;
|
||||
msi->target_addr = pcie->msi_target_addr;
|
||||
msi->irq = irq;
|
||||
msi->legacy = pcie->hw_rev < BRCM_PCIE_HW_REV_33;
|
||||
|
||||
if (msi->legacy) {
|
||||
msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
|
||||
msi->nr = BRCM_INT_PCI_MSI_LEGACY_NR;
|
||||
msi->legacy_shift = 24;
|
||||
} else {
|
||||
msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
|
||||
msi->nr = BRCM_INT_PCI_MSI_NR;
|
||||
msi->legacy_shift = 0;
|
||||
}
|
||||
|
||||
ret = brcm_allocate_domains(msi);
|
||||
if (ret)
|
||||
@ -599,22 +727,43 @@ static struct pci_ops brcm_pcie_ops = {
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
|
||||
static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val)
|
||||
{
|
||||
u32 tmp;
|
||||
u32 tmp, mask = RGR1_SW_INIT_1_INIT_GENERIC_MASK;
|
||||
u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT;
|
||||
|
||||
tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
|
||||
u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK);
|
||||
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
|
||||
tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
tmp = (tmp & ~mask) | ((val << shift) & mask);
|
||||
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
}
|
||||
|
||||
static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val)
|
||||
static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val)
|
||||
{
|
||||
u32 tmp, mask = RGR1_SW_INIT_1_INIT_7278_MASK;
|
||||
u32 shift = RGR1_SW_INIT_1_INIT_7278_SHIFT;
|
||||
|
||||
tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
tmp = (tmp & ~mask) | ((val << shift) & mask);
|
||||
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
}
|
||||
|
||||
static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
|
||||
/* Perst bit has moved and assert value is 0 */
|
||||
tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL);
|
||||
u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK);
|
||||
writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL);
|
||||
}
|
||||
|
||||
static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK);
|
||||
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
|
||||
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
||||
}
|
||||
|
||||
static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
|
||||
@ -622,22 +771,44 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
|
||||
u64 *rc_bar2_offset)
|
||||
{
|
||||
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||
struct device *dev = pcie->dev;
|
||||
struct resource_entry *entry;
|
||||
struct device *dev = pcie->dev;
|
||||
u64 lowest_pcie_addr = ~(u64)0;
|
||||
int ret, i = 0;
|
||||
u64 size = 0;
|
||||
|
||||
entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
|
||||
if (!entry)
|
||||
return -ENODEV;
|
||||
resource_list_for_each_entry(entry, &bridge->dma_ranges) {
|
||||
u64 pcie_beg = entry->res->start - entry->offset;
|
||||
|
||||
size += entry->res->end - entry->res->start + 1;
|
||||
if (pcie_beg < lowest_pcie_addr)
|
||||
lowest_pcie_addr = pcie_beg;
|
||||
}
|
||||
|
||||
/*
|
||||
* The controller expects the inbound window offset to be calculated as
|
||||
* the difference between PCIe's address space and CPU's. The offset
|
||||
* provided by the firmware is calculated the opposite way, so we
|
||||
* negate it.
|
||||
*/
|
||||
*rc_bar2_offset = -entry->offset;
|
||||
*rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start);
|
||||
if (lowest_pcie_addr == ~(u64)0) {
|
||||
dev_err(dev, "DT node has no dma-ranges\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1,
|
||||
PCIE_BRCM_MAX_MEMC);
|
||||
|
||||
if (ret <= 0) {
|
||||
/* Make an educated guess */
|
||||
pcie->num_memc = 1;
|
||||
pcie->memc_size[0] = 1ULL << fls64(size - 1);
|
||||
} else {
|
||||
pcie->num_memc = ret;
|
||||
}
|
||||
|
||||
/* Each memc is viewed through a "port" that is a power of 2 */
|
||||
for (i = 0, size = 0; i < pcie->num_memc; i++)
|
||||
size += pcie->memc_size[i];
|
||||
|
||||
/* System memory starts at this address in PCIe-space */
|
||||
*rc_bar2_offset = lowest_pcie_addr;
|
||||
/* The sum of all memc views must also be a power of 2 */
|
||||
*rc_bar2_size = 1ULL << fls64(size - 1);
|
||||
|
||||
/*
|
||||
* We validate the inbound memory view even though we should trust
|
||||
@ -689,22 +860,19 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
void __iomem *base = pcie->base;
|
||||
struct device *dev = pcie->dev;
|
||||
struct resource_entry *entry;
|
||||
unsigned int scb_size_val;
|
||||
bool ssc_good = false;
|
||||
struct resource *res;
|
||||
int num_out_wins = 0;
|
||||
u16 nlw, cls, lnksta;
|
||||
int i, ret;
|
||||
u32 tmp, aspm_support;
|
||||
int i, ret, memc;
|
||||
u32 tmp, burst, aspm_support;
|
||||
|
||||
/* Reset the bridge */
|
||||
brcm_pcie_bridge_sw_init_set(pcie, 1);
|
||||
brcm_pcie_perst_set(pcie, 1);
|
||||
|
||||
pcie->bridge_sw_init_set(pcie, 1);
|
||||
usleep_range(100, 200);
|
||||
|
||||
/* Take the bridge out of reset */
|
||||
brcm_pcie_bridge_sw_init_set(pcie, 0);
|
||||
pcie->bridge_sw_init_set(pcie, 0);
|
||||
|
||||
tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
||||
tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK;
|
||||
@ -712,11 +880,22 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
/* Wait for SerDes to be stable */
|
||||
usleep_range(100, 200);
|
||||
|
||||
/*
|
||||
* SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it
|
||||
* is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it
|
||||
* is encoded as 0=Rsvd, 1=128, 2=256, 3=512.
|
||||
*/
|
||||
if (pcie->type == BCM2711)
|
||||
burst = 0x0; /* 128B */
|
||||
else if (pcie->type == BCM7278)
|
||||
burst = 0x3; /* 512 bytes */
|
||||
else
|
||||
burst = 0x2; /* 512 bytes */
|
||||
|
||||
/* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
|
||||
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
|
||||
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
|
||||
u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128,
|
||||
PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
|
||||
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
|
||||
writel(tmp, base + PCIE_MISC_MISC_CTRL);
|
||||
|
||||
ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
|
||||
@ -731,11 +910,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
writel(upper_32_bits(rc_bar2_offset),
|
||||
base + PCIE_MISC_RC_BAR2_CONFIG_HI);
|
||||
|
||||
scb_size_val = rc_bar2_size ?
|
||||
ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
|
||||
tmp = readl(base + PCIE_MISC_MISC_CTRL);
|
||||
u32p_replace_bits(&tmp, scb_size_val,
|
||||
PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
|
||||
for (memc = 0; memc < pcie->num_memc; memc++) {
|
||||
u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15;
|
||||
|
||||
if (memc == 0)
|
||||
u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0));
|
||||
else if (memc == 1)
|
||||
u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1));
|
||||
else if (memc == 2)
|
||||
u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2));
|
||||
}
|
||||
writel(tmp, base + PCIE_MISC_MISC_CTRL);
|
||||
|
||||
/*
|
||||
@ -760,17 +945,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;
|
||||
writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO);
|
||||
|
||||
/* Mask all interrupts since we are not handling any yet */
|
||||
writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET);
|
||||
|
||||
/* clear any interrupts we find on boot */
|
||||
writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR);
|
||||
|
||||
if (pcie->gen)
|
||||
brcm_pcie_set_gen(pcie, pcie->gen);
|
||||
|
||||
/* Unassert the fundamental reset */
|
||||
brcm_pcie_perst_set(pcie, 0);
|
||||
pcie->perst_set(pcie, 0);
|
||||
|
||||
/*
|
||||
* Give the RC/EP time to wake up, before trying to configure RC.
|
||||
@ -882,6 +1061,52 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie)
|
||||
dev_err(pcie->dev, "failed to enter low-power link state\n");
|
||||
}
|
||||
|
||||
static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start)
|
||||
{
|
||||
static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = {
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT,
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT,
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT,};
|
||||
static const u32 masks[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = {
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK,
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK,
|
||||
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK,};
|
||||
const int beg = start ? 0 : PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS - 1;
|
||||
const int end = start ? PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS : -1;
|
||||
u32 tmp, combined_mask = 0;
|
||||
u32 val;
|
||||
void __iomem *base = pcie->base;
|
||||
int i, ret;
|
||||
|
||||
for (i = beg; i != end; start ? i++ : i--) {
|
||||
val = start ? BIT_MASK(shifts[i]) : 0;
|
||||
tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
|
||||
tmp = (tmp & ~masks[i]) | (val & masks[i]);
|
||||
writel(tmp, base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
|
||||
usleep_range(50, 200);
|
||||
combined_mask |= masks[i];
|
||||
}
|
||||
|
||||
tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL);
|
||||
val = start ? combined_mask : 0;
|
||||
|
||||
ret = (tmp & combined_mask) == val ? 0 : -EIO;
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int brcm_phy_start(struct brcm_pcie *pcie)
|
||||
{
|
||||
return pcie->rescal ? brcm_phy_cntl(pcie, 1) : 0;
|
||||
}
|
||||
|
||||
static inline int brcm_phy_stop(struct brcm_pcie *pcie)
|
||||
{
|
||||
return pcie->rescal ? brcm_phy_cntl(pcie, 0) : 0;
|
||||
}
|
||||
|
||||
static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
{
|
||||
void __iomem *base = pcie->base;
|
||||
@ -890,7 +1115,7 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
if (brcm_pcie_link_up(pcie))
|
||||
brcm_pcie_enter_l23(pcie);
|
||||
/* Assert fundamental reset */
|
||||
brcm_pcie_perst_set(pcie, 1);
|
||||
pcie->perst_set(pcie, 1);
|
||||
|
||||
/* Deassert request for L23 in case it was asserted */
|
||||
tmp = readl(base + PCIE_MISC_PCIE_CTRL);
|
||||
@ -903,13 +1128,66 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
||||
|
||||
/* Shutdown PCIe bridge */
|
||||
brcm_pcie_bridge_sw_init_set(pcie, 1);
|
||||
pcie->bridge_sw_init_set(pcie, 1);
|
||||
}
|
||||
|
||||
static int brcm_pcie_suspend(struct device *dev)
|
||||
{
|
||||
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
brcm_pcie_turn_off(pcie);
|
||||
ret = brcm_phy_stop(pcie);
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcm_pcie_resume(struct device *dev)
|
||||
{
|
||||
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
||||
void __iomem *base;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
base = pcie->base;
|
||||
clk_prepare_enable(pcie->clk);
|
||||
|
||||
ret = brcm_phy_start(pcie);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Take bridge out of reset so we can access the SERDES reg */
|
||||
pcie->bridge_sw_init_set(pcie, 0);
|
||||
|
||||
/* SERDES_IDDQ = 0 */
|
||||
tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
||||
u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
|
||||
writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
||||
|
||||
/* wait for serdes to be stable */
|
||||
udelay(100);
|
||||
|
||||
ret = brcm_pcie_setup(pcie);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (pcie->msi)
|
||||
brcm_msi_set_regs(pcie->msi);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __brcm_pcie_remove(struct brcm_pcie *pcie)
|
||||
{
|
||||
brcm_msi_remove(pcie);
|
||||
brcm_pcie_turn_off(pcie);
|
||||
brcm_phy_stop(pcie);
|
||||
reset_control_assert(pcie->rescal);
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
}
|
||||
|
||||
@ -925,10 +1203,20 @@ static int brcm_pcie_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id brcm_pcie_match[] = {
|
||||
{ .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
|
||||
{ .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg },
|
||||
{ .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
|
||||
{ .compatible = "brcm,bcm7216-pcie", .data = &bcm7278_cfg },
|
||||
{ .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
|
||||
{},
|
||||
};
|
||||
|
||||
static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node, *msi_np;
|
||||
struct pci_host_bridge *bridge;
|
||||
const struct pcie_cfg_data *data;
|
||||
struct brcm_pcie *pcie;
|
||||
int ret;
|
||||
|
||||
@ -936,9 +1224,19 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (!data) {
|
||||
pr_err("failed to look up compatible string\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pcie = pci_host_bridge_priv(bridge);
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->np = np;
|
||||
pcie->reg_offsets = data->offsets;
|
||||
pcie->type = data->type;
|
||||
pcie->perst_set = data->perst_set;
|
||||
pcie->bridge_sw_init_set = data->bridge_sw_init_set;
|
||||
|
||||
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pcie->base))
|
||||
@ -958,11 +1256,29 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "could not enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal");
|
||||
if (IS_ERR(pcie->rescal)) {
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
return PTR_ERR(pcie->rescal);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(pcie->rescal);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to deassert 'rescal'\n");
|
||||
|
||||
ret = brcm_phy_start(pcie);
|
||||
if (ret) {
|
||||
reset_control_assert(pcie->rescal);
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = brcm_pcie_setup(pcie);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION);
|
||||
|
||||
msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
|
||||
if (pci_msi_enabled() && msi_np == pcie->np) {
|
||||
ret = brcm_pcie_enable_msi(pcie);
|
||||
@ -983,18 +1299,20 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id brcm_pcie_match[] = {
|
||||
{ .compatible = "brcm,bcm2711-pcie" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcm_pcie_match);
|
||||
|
||||
static const struct dev_pm_ops brcm_pcie_pm_ops = {
|
||||
.suspend = brcm_pcie_suspend,
|
||||
.resume = brcm_pcie_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver brcm_pcie_driver = {
|
||||
.probe = brcm_pcie_probe,
|
||||
.remove = brcm_pcie_remove,
|
||||
.driver = {
|
||||
.name = "brcm-pcie",
|
||||
.of_match_table = brcm_pcie_match,
|
||||
.pm = &brcm_pcie_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(brcm_pcie_driver);
|
||||
|
327
drivers/pci/controller/pcie-hisi-error.c
Normal file
327
drivers/pci/controller/pcie-hisi-error.c
Normal file
@ -0,0 +1,327 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for handling the PCIe controller errors on
|
||||
* HiSilicon HIP SoCs.
|
||||
*
|
||||
* Copyright (c) 2020 HiSilicon Limited.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/ghes.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* HISI PCIe controller error definitions */
|
||||
#define HISI_PCIE_ERR_MISC_REGS 33
|
||||
|
||||
#define HISI_PCIE_LOCAL_VALID_VERSION BIT(0)
|
||||
#define HISI_PCIE_LOCAL_VALID_SOC_ID BIT(1)
|
||||
#define HISI_PCIE_LOCAL_VALID_SOCKET_ID BIT(2)
|
||||
#define HISI_PCIE_LOCAL_VALID_NIMBUS_ID BIT(3)
|
||||
#define HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID BIT(4)
|
||||
#define HISI_PCIE_LOCAL_VALID_CORE_ID BIT(5)
|
||||
#define HISI_PCIE_LOCAL_VALID_PORT_ID BIT(6)
|
||||
#define HISI_PCIE_LOCAL_VALID_ERR_TYPE BIT(7)
|
||||
#define HISI_PCIE_LOCAL_VALID_ERR_SEVERITY BIT(8)
|
||||
#define HISI_PCIE_LOCAL_VALID_ERR_MISC 9
|
||||
|
||||
static guid_t hisi_pcie_sec_guid =
|
||||
GUID_INIT(0xB2889FC9, 0xE7D7, 0x4F9D,
|
||||
0xA8, 0x67, 0xAF, 0x42, 0xE9, 0x8B, 0xE7, 0x72);
|
||||
|
||||
/*
|
||||
* Firmware reports the socket port ID where the error occurred. These
|
||||
* macros convert that to the core ID and core port ID required by the
|
||||
* ACPI reset method.
|
||||
*/
|
||||
#define HISI_PCIE_PORT_ID(core, v) (((v) >> 1) + ((core) << 3))
|
||||
#define HISI_PCIE_CORE_ID(v) ((v) >> 3)
|
||||
#define HISI_PCIE_CORE_PORT_ID(v) (((v) & 7) << 1)
|
||||
|
||||
struct hisi_pcie_error_data {
|
||||
u64 val_bits;
|
||||
u8 version;
|
||||
u8 soc_id;
|
||||
u8 socket_id;
|
||||
u8 nimbus_id;
|
||||
u8 sub_module_id;
|
||||
u8 core_id;
|
||||
u8 port_id;
|
||||
u8 err_severity;
|
||||
u16 err_type;
|
||||
u8 reserv[2];
|
||||
u32 err_misc[HISI_PCIE_ERR_MISC_REGS];
|
||||
};
|
||||
|
||||
struct hisi_pcie_error_private {
|
||||
struct notifier_block nb;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
enum hisi_pcie_submodule_id {
|
||||
HISI_PCIE_SUB_MODULE_ID_AP,
|
||||
HISI_PCIE_SUB_MODULE_ID_TL,
|
||||
HISI_PCIE_SUB_MODULE_ID_MAC,
|
||||
HISI_PCIE_SUB_MODULE_ID_DL,
|
||||
HISI_PCIE_SUB_MODULE_ID_SDI,
|
||||
};
|
||||
|
||||
static const char * const hisi_pcie_sub_module[] = {
|
||||
[HISI_PCIE_SUB_MODULE_ID_AP] = "AP Layer",
|
||||
[HISI_PCIE_SUB_MODULE_ID_TL] = "TL Layer",
|
||||
[HISI_PCIE_SUB_MODULE_ID_MAC] = "MAC Layer",
|
||||
[HISI_PCIE_SUB_MODULE_ID_DL] = "DL Layer",
|
||||
[HISI_PCIE_SUB_MODULE_ID_SDI] = "SDI Layer",
|
||||
};
|
||||
|
||||
enum hisi_pcie_err_severity {
|
||||
HISI_PCIE_ERR_SEV_RECOVERABLE,
|
||||
HISI_PCIE_ERR_SEV_FATAL,
|
||||
HISI_PCIE_ERR_SEV_CORRECTED,
|
||||
HISI_PCIE_ERR_SEV_NONE,
|
||||
};
|
||||
|
||||
static const char * const hisi_pcie_error_sev[] = {
|
||||
[HISI_PCIE_ERR_SEV_RECOVERABLE] = "recoverable",
|
||||
[HISI_PCIE_ERR_SEV_FATAL] = "fatal",
|
||||
[HISI_PCIE_ERR_SEV_CORRECTED] = "corrected",
|
||||
[HISI_PCIE_ERR_SEV_NONE] = "none",
|
||||
};
|
||||
|
||||
static const char *hisi_pcie_get_string(const char * const *array,
|
||||
size_t n, u32 id)
|
||||
{
|
||||
u32 index;
|
||||
|
||||
for (index = 0; index < n; index++) {
|
||||
if (index == id && array[index])
|
||||
return array[index];
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static int hisi_pcie_port_reset(struct platform_device *pdev,
|
||||
u32 chip_id, u32 port_id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
union acpi_object arg[3];
|
||||
struct acpi_object_list arg_list;
|
||||
acpi_status s;
|
||||
unsigned long long data = 0;
|
||||
|
||||
arg[0].type = ACPI_TYPE_INTEGER;
|
||||
arg[0].integer.value = chip_id;
|
||||
arg[1].type = ACPI_TYPE_INTEGER;
|
||||
arg[1].integer.value = HISI_PCIE_CORE_ID(port_id);
|
||||
arg[2].type = ACPI_TYPE_INTEGER;
|
||||
arg[2].integer.value = HISI_PCIE_CORE_PORT_ID(port_id);
|
||||
|
||||
arg_list.count = 3;
|
||||
arg_list.pointer = arg;
|
||||
|
||||
s = acpi_evaluate_integer(handle, "RST", &arg_list, &data);
|
||||
if (ACPI_FAILURE(s)) {
|
||||
dev_err(dev, "No RST method\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
dev_err(dev, "Failed to Reset\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_pcie_port_do_recovery(struct platform_device *dev,
|
||||
u32 chip_id, u32 port_id)
|
||||
{
|
||||
acpi_status s;
|
||||
struct device *device = &dev->dev;
|
||||
acpi_handle root_handle = ACPI_HANDLE(device);
|
||||
struct acpi_pci_root *pci_root;
|
||||
struct pci_bus *root_bus;
|
||||
struct pci_dev *pdev;
|
||||
u32 domain, busnr, devfn;
|
||||
|
||||
s = acpi_get_parent(root_handle, &root_handle);
|
||||
if (ACPI_FAILURE(s))
|
||||
return -ENODEV;
|
||||
pci_root = acpi_pci_find_root(root_handle);
|
||||
if (!pci_root)
|
||||
return -ENODEV;
|
||||
root_bus = pci_root->bus;
|
||||
domain = pci_root->segment;
|
||||
|
||||
busnr = root_bus->number;
|
||||
devfn = PCI_DEVFN(port_id, 0);
|
||||
pdev = pci_get_domain_bus_and_slot(domain, busnr, devfn);
|
||||
if (!pdev) {
|
||||
dev_info(device, "Fail to get root port %04x:%02x:%02x.%d device\n",
|
||||
domain, busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pci_stop_and_remove_bus_device_locked(pdev);
|
||||
pci_dev_put(pdev);
|
||||
|
||||
if (hisi_pcie_port_reset(dev, chip_id, port_id))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* The initialization time of subordinate devices after
|
||||
* hot reset is no more than 1s, which is required by
|
||||
* the PCI spec v5.0 sec 6.6.1. The time will shorten
|
||||
* if Readiness Notifications mechanisms are used. But
|
||||
* wait 1s here to adapt any conditions.
|
||||
*/
|
||||
ssleep(1UL);
|
||||
|
||||
/* add root port and downstream devices */
|
||||
pci_lock_rescan_remove();
|
||||
pci_rescan_bus(root_bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hisi_pcie_handle_error(struct platform_device *pdev,
|
||||
const struct hisi_pcie_error_data *edata)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int idx, rc;
|
||||
const unsigned long valid_bits[] = {BITMAP_FROM_U64(edata->val_bits)};
|
||||
|
||||
if (edata->val_bits == 0) {
|
||||
dev_warn(dev, "%s: no valid error information\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_info(dev, "\nHISI : HIP : PCIe controller error\n");
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOC_ID)
|
||||
dev_info(dev, "Table version = %d\n", edata->version);
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOCKET_ID)
|
||||
dev_info(dev, "Socket ID = %d\n", edata->socket_id);
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_NIMBUS_ID)
|
||||
dev_info(dev, "Nimbus ID = %d\n", edata->nimbus_id);
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID)
|
||||
dev_info(dev, "Sub Module = %s\n",
|
||||
hisi_pcie_get_string(hisi_pcie_sub_module,
|
||||
ARRAY_SIZE(hisi_pcie_sub_module),
|
||||
edata->sub_module_id));
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_CORE_ID)
|
||||
dev_info(dev, "Core ID = core%d\n", edata->core_id);
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_PORT_ID)
|
||||
dev_info(dev, "Port ID = port%d\n", edata->port_id);
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_SEVERITY)
|
||||
dev_info(dev, "Error severity = %s\n",
|
||||
hisi_pcie_get_string(hisi_pcie_error_sev,
|
||||
ARRAY_SIZE(hisi_pcie_error_sev),
|
||||
edata->err_severity));
|
||||
if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_TYPE)
|
||||
dev_info(dev, "Error type = 0x%x\n", edata->err_type);
|
||||
|
||||
dev_info(dev, "Reg Dump:\n");
|
||||
idx = HISI_PCIE_LOCAL_VALID_ERR_MISC;
|
||||
for_each_set_bit_from(idx, valid_bits,
|
||||
HISI_PCIE_LOCAL_VALID_ERR_MISC + HISI_PCIE_ERR_MISC_REGS)
|
||||
dev_info(dev, "ERR_MISC_%d = 0x%x\n", idx - HISI_PCIE_LOCAL_VALID_ERR_MISC,
|
||||
edata->err_misc[idx - HISI_PCIE_LOCAL_VALID_ERR_MISC]);
|
||||
|
||||
if (edata->err_severity != HISI_PCIE_ERR_SEV_RECOVERABLE)
|
||||
return;
|
||||
|
||||
/* Recovery for the PCIe controller errors, try reset
|
||||
* PCI port for the error recovery
|
||||
*/
|
||||
rc = hisi_pcie_port_do_recovery(pdev, edata->socket_id,
|
||||
HISI_PCIE_PORT_ID(edata->core_id, edata->port_id));
|
||||
if (rc)
|
||||
dev_info(dev, "fail to do hisi pcie port reset\n");
|
||||
}
|
||||
|
||||
static int hisi_pcie_notify_error(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct acpi_hest_generic_data *gdata = data;
|
||||
const struct hisi_pcie_error_data *error_data = acpi_hest_get_payload(gdata);
|
||||
struct hisi_pcie_error_private *priv;
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
guid_t err_sec_guid;
|
||||
u8 socket;
|
||||
|
||||
import_guid(&err_sec_guid, gdata->section_type);
|
||||
if (!guid_equal(&err_sec_guid, &hisi_pcie_sec_guid))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
priv = container_of(nb, struct hisi_pcie_error_private, nb);
|
||||
dev = priv->dev;
|
||||
|
||||
if (device_property_read_u8(dev, "socket", &socket))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (error_data->socket_id != socket)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
pdev = container_of(dev, struct platform_device, dev);
|
||||
hisi_pcie_handle_error(pdev, error_data);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int hisi_pcie_error_handler_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hisi_pcie_error_private *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->nb.notifier_call = hisi_pcie_notify_error;
|
||||
priv->dev = &pdev->dev;
|
||||
ret = ghes_register_vendor_record_notifier(&priv->nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register hisi pcie controller error handler with apei\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_pcie_error_handler_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hisi_pcie_error_private *priv = platform_get_drvdata(pdev);
|
||||
|
||||
ghes_unregister_vendor_record_notifier(&priv->nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id hisi_pcie_acpi_match[] = {
|
||||
{ "HISI0361", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver hisi_pcie_error_handler_driver = {
|
||||
.driver = {
|
||||
.name = "hisi-pcie-error-handler",
|
||||
.acpi_match_table = hisi_pcie_acpi_match,
|
||||
},
|
||||
.probe = hisi_pcie_error_handler_probe,
|
||||
.remove = hisi_pcie_error_handler_remove,
|
||||
};
|
||||
module_platform_driver(hisi_pcie_error_handler_driver);
|
||||
|
||||
MODULE_DESCRIPTION("HiSilicon HIP PCIe controller error handling driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -94,18 +94,7 @@ static struct bcma_driver iproc_pcie_bcma_driver = {
|
||||
.probe = iproc_pcie_bcma_probe,
|
||||
.remove = iproc_pcie_bcma_remove,
|
||||
};
|
||||
|
||||
static int __init iproc_pcie_bcma_init(void)
|
||||
{
|
||||
return bcma_driver_register(&iproc_pcie_bcma_driver);
|
||||
}
|
||||
module_init(iproc_pcie_bcma_init);
|
||||
|
||||
static void __exit iproc_pcie_bcma_exit(void)
|
||||
{
|
||||
bcma_driver_unregister(&iproc_pcie_bcma_driver);
|
||||
}
|
||||
module_exit(iproc_pcie_bcma_exit);
|
||||
module_bcma_driver(iproc_pcie_bcma_driver);
|
||||
|
||||
MODULE_AUTHOR("Hauke Mehrtens");
|
||||
MODULE_DESCRIPTION("Broadcom iProc PCIe BCMA driver");
|
||||
|
@ -209,15 +209,20 @@ static int iproc_msi_irq_set_affinity(struct irq_data *data,
|
||||
struct iproc_msi *msi = irq_data_get_irq_chip_data(data);
|
||||
int target_cpu = cpumask_first(mask);
|
||||
int curr_cpu;
|
||||
int ret;
|
||||
|
||||
curr_cpu = hwirq_to_cpu(msi, data->hwirq);
|
||||
if (curr_cpu == target_cpu)
|
||||
return IRQ_SET_MASK_OK_DONE;
|
||||
ret = IRQ_SET_MASK_OK_DONE;
|
||||
else {
|
||||
/* steer MSI to the target CPU */
|
||||
data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu;
|
||||
ret = IRQ_SET_MASK_OK;
|
||||
}
|
||||
|
||||
/* steer MSI to the target CPU */
|
||||
data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu;
|
||||
irq_data_update_effective_affinity(data, cpumask_of(target_cpu));
|
||||
|
||||
return IRQ_SET_MASK_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iproc_msi_irq_compose_msi_msg(struct irq_data *data,
|
||||
|
@ -99,7 +99,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
||||
switch (pcie->type) {
|
||||
case IPROC_PCIE_PAXC:
|
||||
case IPROC_PCIE_PAXC_V2:
|
||||
pcie->map_irq = 0;
|
||||
pcie->map_irq = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -572,12 +572,8 @@ static int xilinx_cpm_pcie_probe(struct platform_device *pdev)
|
||||
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)
|
||||
|
@ -298,6 +298,33 @@ static struct msi_domain_info vmd_msi_domain_info = {
|
||||
.chip = &vmd_msi_controller,
|
||||
};
|
||||
|
||||
static int vmd_create_irq_domain(struct vmd_dev *vmd)
|
||||
{
|
||||
struct fwnode_handle *fn;
|
||||
|
||||
fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
|
||||
if (!fn)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);
|
||||
if (!vmd->irq_domain) {
|
||||
irq_domain_free_fwnode(fn);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmd_remove_irq_domain(struct vmd_dev *vmd)
|
||||
{
|
||||
if (vmd->irq_domain) {
|
||||
struct fwnode_handle *fn = vmd->irq_domain->fwnode;
|
||||
|
||||
irq_domain_remove(vmd->irq_domain);
|
||||
irq_domain_free_fwnode(fn);
|
||||
}
|
||||
}
|
||||
|
||||
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
|
||||
unsigned int devfn, int reg, int len)
|
||||
{
|
||||
@ -417,10 +444,141 @@ static int vmd_find_free_domain(void)
|
||||
return domain + 1;
|
||||
}
|
||||
|
||||
static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint,
|
||||
resource_size_t *offset1,
|
||||
resource_size_t *offset2)
|
||||
{
|
||||
struct pci_dev *dev = vmd->dev;
|
||||
u64 phys1, phys2;
|
||||
|
||||
if (native_hint) {
|
||||
u32 vmlock;
|
||||
int ret;
|
||||
|
||||
ret = pci_read_config_dword(dev, PCI_REG_VMLOCK, &vmlock);
|
||||
if (ret || vmlock == ~0)
|
||||
return -ENODEV;
|
||||
|
||||
if (MB2_SHADOW_EN(vmlock)) {
|
||||
void __iomem *membar2;
|
||||
|
||||
membar2 = pci_iomap(dev, VMD_MEMBAR2, 0);
|
||||
if (!membar2)
|
||||
return -ENOMEM;
|
||||
phys1 = readq(membar2 + MB2_SHADOW_OFFSET);
|
||||
phys2 = readq(membar2 + MB2_SHADOW_OFFSET + 8);
|
||||
pci_iounmap(dev, membar2);
|
||||
} else
|
||||
return 0;
|
||||
} else {
|
||||
/* Hypervisor-Emulated Vendor-Specific Capability */
|
||||
int pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
|
||||
u32 reg, regu;
|
||||
|
||||
pci_read_config_dword(dev, pos + 4, ®);
|
||||
|
||||
/* "SHDW" */
|
||||
if (pos && reg == 0x53484457) {
|
||||
pci_read_config_dword(dev, pos + 8, ®);
|
||||
pci_read_config_dword(dev, pos + 12, ®u);
|
||||
phys1 = (u64) regu << 32 | reg;
|
||||
|
||||
pci_read_config_dword(dev, pos + 16, ®);
|
||||
pci_read_config_dword(dev, pos + 20, ®u);
|
||||
phys2 = (u64) regu << 32 | reg;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
*offset1 = dev->resource[VMD_MEMBAR1].start -
|
||||
(phys1 & PCI_BASE_ADDRESS_MEM_MASK);
|
||||
*offset2 = dev->resource[VMD_MEMBAR2].start -
|
||||
(phys2 & PCI_BASE_ADDRESS_MEM_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmd_get_bus_number_start(struct vmd_dev *vmd)
|
||||
{
|
||||
struct pci_dev *dev = vmd->dev;
|
||||
u16 reg;
|
||||
|
||||
pci_read_config_word(dev, PCI_REG_VMCAP, ®);
|
||||
if (BUS_RESTRICT_CAP(reg)) {
|
||||
pci_read_config_word(dev, PCI_REG_VMCONFIG, ®);
|
||||
|
||||
switch (BUS_RESTRICT_CFG(reg)) {
|
||||
case 0:
|
||||
vmd->busn_start = 0;
|
||||
break;
|
||||
case 1:
|
||||
vmd->busn_start = 128;
|
||||
break;
|
||||
case 2:
|
||||
vmd->busn_start = 224;
|
||||
break;
|
||||
default:
|
||||
pci_err(dev, "Unknown Bus Offset Setting (%d)\n",
|
||||
BUS_RESTRICT_CFG(reg));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t vmd_irq(int irq, void *data)
|
||||
{
|
||||
struct vmd_irq_list *irqs = data;
|
||||
struct vmd_irq *vmdirq;
|
||||
int idx;
|
||||
|
||||
idx = srcu_read_lock(&irqs->srcu);
|
||||
list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
|
||||
generic_handle_irq(vmdirq->virq);
|
||||
srcu_read_unlock(&irqs->srcu, idx);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int vmd_alloc_irqs(struct vmd_dev *vmd)
|
||||
{
|
||||
struct pci_dev *dev = vmd->dev;
|
||||
int i, err;
|
||||
|
||||
vmd->msix_count = pci_msix_vec_count(dev);
|
||||
if (vmd->msix_count < 0)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
|
||||
PCI_IRQ_MSIX);
|
||||
if (vmd->msix_count < 0)
|
||||
return vmd->msix_count;
|
||||
|
||||
vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),
|
||||
GFP_KERNEL);
|
||||
if (!vmd->irqs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < vmd->msix_count; i++) {
|
||||
err = init_srcu_struct(&vmd->irqs[i].srcu);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
|
||||
err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
|
||||
vmd_irq, IRQF_NO_THREAD,
|
||||
"vmd", &vmd->irqs[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
{
|
||||
struct pci_sysdata *sd = &vmd->sysdata;
|
||||
struct fwnode_handle *fn;
|
||||
struct resource *res;
|
||||
u32 upper_bits;
|
||||
unsigned long flags;
|
||||
@ -428,6 +586,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
resource_size_t offset[2] = {0};
|
||||
resource_size_t membar2_offset = 0x2000;
|
||||
struct pci_bus *child;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Shadow registers may exist in certain VMD device ids which allow
|
||||
@ -436,50 +595,14 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
* or 0, depending on an enable bit in the VMD device.
|
||||
*/
|
||||
if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) {
|
||||
u32 vmlock;
|
||||
int ret;
|
||||
|
||||
membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE;
|
||||
ret = pci_read_config_dword(vmd->dev, PCI_REG_VMLOCK, &vmlock);
|
||||
if (ret || vmlock == ~0)
|
||||
return -ENODEV;
|
||||
|
||||
if (MB2_SHADOW_EN(vmlock)) {
|
||||
void __iomem *membar2;
|
||||
|
||||
membar2 = pci_iomap(vmd->dev, VMD_MEMBAR2, 0);
|
||||
if (!membar2)
|
||||
return -ENOMEM;
|
||||
offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
|
||||
(readq(membar2 + MB2_SHADOW_OFFSET) &
|
||||
PCI_BASE_ADDRESS_MEM_MASK);
|
||||
offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
|
||||
(readq(membar2 + MB2_SHADOW_OFFSET + 8) &
|
||||
PCI_BASE_ADDRESS_MEM_MASK);
|
||||
pci_iounmap(vmd->dev, membar2);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
|
||||
ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -487,27 +610,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
* limits the bus range to between 0-127, 128-255, or 224-255
|
||||
*/
|
||||
if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) {
|
||||
u16 reg16;
|
||||
|
||||
pci_read_config_word(vmd->dev, PCI_REG_VMCAP, ®16);
|
||||
if (BUS_RESTRICT_CAP(reg16)) {
|
||||
pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG,
|
||||
®16);
|
||||
|
||||
switch (BUS_RESTRICT_CFG(reg16)) {
|
||||
case 1:
|
||||
vmd->busn_start = 128;
|
||||
break;
|
||||
case 2:
|
||||
vmd->busn_start = 224;
|
||||
break;
|
||||
case 3:
|
||||
pci_err(vmd->dev, "Unknown Bus Offset Setting\n");
|
||||
return -ENODEV;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = vmd_get_bus_number_start(vmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = &vmd->dev->resource[VMD_CFGBAR];
|
||||
@ -568,17 +673,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
|
||||
sd->node = pcibus_to_node(vmd->dev->bus);
|
||||
|
||||
fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
|
||||
if (!fn)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,
|
||||
NULL);
|
||||
|
||||
if (!vmd->irq_domain) {
|
||||
irq_domain_free_fwnode(fn);
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = vmd_create_irq_domain(vmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Override the irq domain bus token so the domain can be distinguished
|
||||
@ -594,13 +691,13 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
&vmd_ops, sd, &resources);
|
||||
if (!vmd->bus) {
|
||||
pci_free_resource_list(&resources);
|
||||
irq_domain_remove(vmd->irq_domain);
|
||||
irq_domain_free_fwnode(fn);
|
||||
vmd_remove_irq_domain(vmd);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vmd_attach_resources(vmd);
|
||||
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
|
||||
if (vmd->irq_domain)
|
||||
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
|
||||
|
||||
pci_scan_child_bus(vmd->bus);
|
||||
pci_assign_unassigned_bus_resources(vmd->bus);
|
||||
@ -620,24 +717,10 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t vmd_irq(int irq, void *data)
|
||||
{
|
||||
struct vmd_irq_list *irqs = data;
|
||||
struct vmd_irq *vmdirq;
|
||||
int idx;
|
||||
|
||||
idx = srcu_read_lock(&irqs->srcu);
|
||||
list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
|
||||
generic_handle_irq(vmdirq->virq);
|
||||
srcu_read_unlock(&irqs->srcu, idx);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct vmd_dev *vmd;
|
||||
int i, err;
|
||||
int err;
|
||||
|
||||
if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20))
|
||||
return -ENOMEM;
|
||||
@ -660,32 +743,9 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)))
|
||||
return -ENODEV;
|
||||
|
||||
vmd->msix_count = pci_msix_vec_count(dev);
|
||||
if (vmd->msix_count < 0)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
|
||||
PCI_IRQ_MSIX);
|
||||
if (vmd->msix_count < 0)
|
||||
return vmd->msix_count;
|
||||
|
||||
vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),
|
||||
GFP_KERNEL);
|
||||
if (!vmd->irqs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < vmd->msix_count; i++) {
|
||||
err = init_srcu_struct(&vmd->irqs[i].srcu);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
|
||||
err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
|
||||
vmd_irq, IRQF_NO_THREAD,
|
||||
"vmd", &vmd->irqs[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = vmd_alloc_irqs(vmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
spin_lock_init(&vmd->cfg_lock);
|
||||
pci_set_drvdata(dev, vmd);
|
||||
@ -709,15 +769,13 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd)
|
||||
static void vmd_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct vmd_dev *vmd = pci_get_drvdata(dev);
|
||||
struct fwnode_handle *fn = vmd->irq_domain->fwnode;
|
||||
|
||||
sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
|
||||
pci_stop_root_bus(vmd->bus);
|
||||
pci_remove_root_bus(vmd->bus);
|
||||
vmd_cleanup_srcu(vmd);
|
||||
vmd_detach_resources(vmd);
|
||||
irq_domain_remove(vmd->irq_domain);
|
||||
irq_domain_free_fwnode(fn);
|
||||
vmd_remove_irq_domain(vmd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -730,7 +788,6 @@ static int vmd_suspend(struct device *dev)
|
||||
for (i = 0; i < vmd->msix_count; i++)
|
||||
devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
|
||||
|
||||
pci_save_state(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -748,7 +805,6 @@ static int vmd_resume(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
pci_restore_state(pdev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -168,4 +168,14 @@ const struct pci_ecam_ops pci_32b_ops = {
|
||||
.write = pci_generic_config_write32,
|
||||
}
|
||||
};
|
||||
|
||||
/* ECAM ops for 32-bit read only (non-compliant) */
|
||||
const struct pci_ecam_ops pci_32b_read_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = pci_generic_config_read32,
|
||||
.write = pci_generic_config_write,
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
@ -73,10 +73,8 @@ static int board_added(struct controller *ctrl)
|
||||
|
||||
/* Check link training status */
|
||||
retval = pciehp_check_link_status(ctrl);
|
||||
if (retval) {
|
||||
ctrl_err(ctrl, "Failed to check link status\n");
|
||||
if (retval)
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
/* Check for a power fault */
|
||||
if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
|
||||
|
@ -283,8 +283,6 @@ static void pcie_wait_for_presence(struct pci_dev *pdev)
|
||||
msleep(10);
|
||||
timeout -= 10;
|
||||
} while (timeout > 0);
|
||||
|
||||
pci_info(pdev, "Timeout waiting for Presence Detect\n");
|
||||
}
|
||||
|
||||
int pciehp_check_link_status(struct controller *ctrl)
|
||||
@ -293,8 +291,10 @@ int pciehp_check_link_status(struct controller *ctrl)
|
||||
bool found;
|
||||
u16 lnk_status;
|
||||
|
||||
if (!pcie_wait_for_link(pdev, true))
|
||||
if (!pcie_wait_for_link(pdev, true)) {
|
||||
ctrl_info(ctrl, "Slot(%s): No link\n", slot_name(ctrl));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctrl->inband_presence_disabled)
|
||||
pcie_wait_for_presence(pdev);
|
||||
@ -311,15 +311,18 @@ int pciehp_check_link_status(struct controller *ctrl)
|
||||
ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
|
||||
if ((lnk_status & PCI_EXP_LNKSTA_LT) ||
|
||||
!(lnk_status & PCI_EXP_LNKSTA_NLW)) {
|
||||
ctrl_err(ctrl, "link training error: status %#06x\n",
|
||||
lnk_status);
|
||||
ctrl_info(ctrl, "Slot(%s): Cannot train link: status %#06x\n",
|
||||
slot_name(ctrl), lnk_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
|
||||
|
||||
if (!found)
|
||||
if (!found) {
|
||||
ctrl_info(ctrl, "Slot(%s): No device found\n",
|
||||
slot_name(ctrl));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -40,13 +40,13 @@ static DEFINE_MUTEX(rpadlpar_mutex);
|
||||
static struct device_node *find_vio_slot_node(char *drc_name)
|
||||
{
|
||||
struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
|
||||
struct device_node *dn = NULL;
|
||||
struct device_node *dn;
|
||||
int rc;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
while ((dn = of_get_next_child(parent, dn))) {
|
||||
for_each_child_of_node(parent, dn) {
|
||||
rc = rpaphp_check_drc_props(dn, drc_name, NULL);
|
||||
if (rc == 0)
|
||||
break;
|
||||
@ -60,10 +60,10 @@ static struct device_node *find_vio_slot_node(char *drc_name)
|
||||
static struct device_node *find_php_slot_pci_node(char *drc_name,
|
||||
char *drc_type)
|
||||
{
|
||||
struct device_node *np = NULL;
|
||||
struct device_node *np;
|
||||
int rc;
|
||||
|
||||
while ((np = of_find_node_by_name(np, "pci"))) {
|
||||
for_each_node_by_name(np, "pci") {
|
||||
rc = rpaphp_check_drc_props(np, drc_name, drc_type);
|
||||
if (rc == 0)
|
||||
break;
|
||||
|
@ -299,7 +299,6 @@ static int board_added(struct slot *p_slot)
|
||||
if (p_slot->status == 0xFF) {
|
||||
/* power fault occurred, but it was benign */
|
||||
ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
|
||||
rc = POWER_FAILURE;
|
||||
p_slot->status = 0;
|
||||
goto err_exit;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr,
|
||||
if (pdev->p2pdma->pool)
|
||||
size = gen_pool_size(pdev->p2pdma->pool);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%zd\n", size);
|
||||
return scnprintf(buf, PAGE_SIZE, "%zd\n", size);
|
||||
}
|
||||
static DEVICE_ATTR_RO(size);
|
||||
|
||||
@ -66,7 +66,7 @@ static ssize_t available_show(struct device *dev, struct device_attribute *attr,
|
||||
if (pdev->p2pdma->pool)
|
||||
avail = gen_pool_avail(pdev->p2pdma->pool);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%zd\n", avail);
|
||||
return scnprintf(buf, PAGE_SIZE, "%zd\n", avail);
|
||||
}
|
||||
static DEVICE_ATTR_RO(available);
|
||||
|
||||
@ -75,8 +75,8 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
pdev->p2pdma->p2pmem_published);
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n",
|
||||
pdev->p2pdma->p2pmem_published);
|
||||
}
|
||||
static DEVICE_ATTR_RO(published);
|
||||
|
||||
@ -762,7 +762,7 @@ struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
|
||||
struct scatterlist *sg;
|
||||
void *addr;
|
||||
|
||||
sg = kzalloc(sizeof(*sg), GFP_KERNEL);
|
||||
sg = kmalloc(sizeof(*sg), GFP_KERNEL);
|
||||
if (!sg)
|
||||
return NULL;
|
||||
|
||||
|
@ -1177,7 +1177,7 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
|
||||
* @pdev: the PCI device whose delay is to be updated
|
||||
* @handle: ACPI handle of this device
|
||||
*
|
||||
* Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM
|
||||
* Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM
|
||||
* control method of either the device itself or the PCI host bridge.
|
||||
*
|
||||
* Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
|
||||
@ -1216,8 +1216,8 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
|
||||
}
|
||||
if (elements[3].type == ACPI_TYPE_INTEGER) {
|
||||
value = (int)elements[3].integer.value / 1000;
|
||||
if (value < PCI_PM_D3_WAIT)
|
||||
pdev->d3_delay = value;
|
||||
if (value < PCI_PM_D3HOT_WAIT)
|
||||
pdev->d3hot_delay = value;
|
||||
}
|
||||
}
|
||||
ACPI_FREE(obj);
|
||||
|
@ -294,6 +294,7 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_bridge_emul_init);
|
||||
|
||||
/*
|
||||
* Cleanup a pci_bridge_emul structure that was previously initialized
|
||||
@ -305,6 +306,7 @@ void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge)
|
||||
kfree(bridge->pcie_cap_regs_behavior);
|
||||
kfree(bridge->pci_regs_behavior);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_bridge_emul_cleanup);
|
||||
|
||||
/*
|
||||
* Should be called by the PCI controller driver when reading the PCI
|
||||
@ -366,6 +368,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_bridge_emul_conf_read);
|
||||
|
||||
/*
|
||||
* Should be called by the PCI controller driver when writing the PCI
|
||||
@ -430,3 +433,4 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_bridge_emul_conf_write);
|
||||
|
@ -970,12 +970,6 @@ static int pci_pm_resume(struct device *dev)
|
||||
|
||||
#ifdef CONFIG_HIBERNATE_CALLBACKS
|
||||
|
||||
/*
|
||||
* pcibios_pm_ops - provide arch-specific hooks when a PCI device is doing
|
||||
* a hibernate transition
|
||||
*/
|
||||
struct dev_pm_ops __weak pcibios_pm_ops;
|
||||
|
||||
static int pci_pm_freeze(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
@ -1034,9 +1028,6 @@ static int pci_pm_freeze_noirq(struct device *dev)
|
||||
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
if (pcibios_pm_ops.freeze_noirq)
|
||||
return pcibios_pm_ops.freeze_noirq(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1044,13 +1035,6 @@ static int pci_pm_thaw_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
int error;
|
||||
|
||||
if (pcibios_pm_ops.thaw_noirq) {
|
||||
error = pcibios_pm_ops.thaw_noirq(dev);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pm->thaw_noirq() callback assumes the device has been
|
||||
@ -1175,9 +1159,6 @@ static int pci_pm_poweroff_noirq(struct device *dev)
|
||||
|
||||
pci_fixup_device(pci_fixup_suspend_late, pci_dev);
|
||||
|
||||
if (pcibios_pm_ops.poweroff_noirq)
|
||||
return pcibios_pm_ops.poweroff_noirq(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1185,13 +1166,6 @@ static int pci_pm_restore_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
int error;
|
||||
|
||||
if (pcibios_pm_ops.restore_noirq) {
|
||||
error = pcibios_pm_ops.restore_noirq(dev);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
pci_pm_default_resume_early(pci_dev);
|
||||
pci_fixup_device(pci_fixup_resume_early, pci_dev);
|
||||
|
@ -37,18 +37,6 @@ static struct pci_driver pf_stub_driver = {
|
||||
.probe = pci_pf_stub_probe,
|
||||
.sriov_configure = pci_sriov_configure_simple,
|
||||
};
|
||||
|
||||
static int __init pci_pf_stub_init(void)
|
||||
{
|
||||
return pci_register_driver(&pf_stub_driver);
|
||||
}
|
||||
|
||||
static void __exit pci_pf_stub_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&pf_stub_driver);
|
||||
}
|
||||
|
||||
module_init(pci_pf_stub_init);
|
||||
module_exit(pci_pf_stub_exit);
|
||||
module_pci_driver(pf_stub_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -574,7 +574,7 @@ static ssize_t driver_override_show(struct device *dev,
|
||||
ssize_t len;
|
||||
|
||||
device_lock(dev);
|
||||
len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
|
||||
len = scnprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override);
|
||||
device_unlock(dev);
|
||||
return len;
|
||||
}
|
||||
@ -708,6 +708,7 @@ static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
|
||||
data[off - init_off + 3] = (val >> 24) & 0xff;
|
||||
off += 4;
|
||||
size -= 4;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (size >= 2) {
|
||||
@ -1196,10 +1197,10 @@ static int pci_create_resource_files(struct pci_dev *pdev)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else /* !HAVE_PCI_MMAP */
|
||||
#else /* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */
|
||||
int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
|
||||
void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
|
||||
#endif /* HAVE_PCI_MMAP */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* pci_write_rom - used to enable access to the PCI ROM display
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
@ -30,8 +29,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pci-ats.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/dma.h>
|
||||
#include <linux/aer.h>
|
||||
#include "pci.h"
|
||||
@ -49,7 +46,7 @@ EXPORT_SYMBOL(isa_dma_bridge_buggy);
|
||||
int pci_pci_problems;
|
||||
EXPORT_SYMBOL(pci_pci_problems);
|
||||
|
||||
unsigned int pci_pm_d3_delay;
|
||||
unsigned int pci_pm_d3hot_delay;
|
||||
|
||||
static void pci_pme_list_scan(struct work_struct *work);
|
||||
|
||||
@ -66,10 +63,10 @@ struct pci_pme_device {
|
||||
|
||||
static void pci_dev_d3_sleep(struct pci_dev *dev)
|
||||
{
|
||||
unsigned int delay = dev->d3_delay;
|
||||
unsigned int delay = dev->d3hot_delay;
|
||||
|
||||
if (delay < pci_pm_d3_delay)
|
||||
delay = pci_pm_d3_delay;
|
||||
if (delay < pci_pm_d3hot_delay)
|
||||
delay = pci_pm_d3hot_delay;
|
||||
|
||||
if (delay)
|
||||
msleep(delay);
|
||||
@ -101,7 +98,19 @@ unsigned long pci_hotplug_mmio_pref_size = DEFAULT_HOTPLUG_MMIO_PREF_SIZE;
|
||||
#define DEFAULT_HOTPLUG_BUS_SIZE 1
|
||||
unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
|
||||
|
||||
|
||||
/* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param */
|
||||
#ifdef CONFIG_PCIE_BUS_TUNE_OFF
|
||||
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
|
||||
#elif defined CONFIG_PCIE_BUS_SAFE
|
||||
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
|
||||
#elif defined CONFIG_PCIE_BUS_PERFORMANCE
|
||||
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
|
||||
#elif defined CONFIG_PCIE_BUS_PEER2PEER
|
||||
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PEER2PEER;
|
||||
#else
|
||||
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The default CLS is used if arch didn't set CLS explicitly and not
|
||||
@ -876,6 +885,10 @@ static void pci_std_enable_acs(struct pci_dev *dev)
|
||||
/* Upstream Forwarding */
|
||||
ctrl |= (cap & PCI_ACS_UF);
|
||||
|
||||
/* Enable Translation Blocking for external devices */
|
||||
if (dev->external_facing || dev->untrusted)
|
||||
ctrl |= (cap & PCI_ACS_TB);
|
||||
|
||||
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
|
||||
}
|
||||
|
||||
@ -1065,7 +1078,7 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
|
||||
pci_dev_d3_sleep(dev);
|
||||
else if (state == PCI_D2 || dev->current_state == PCI_D2)
|
||||
msleep(PCI_PM_D2_DELAY);
|
||||
udelay(PCI_PM_D2_DELAY);
|
||||
|
||||
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
|
||||
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
|
||||
@ -3013,7 +3026,7 @@ void pci_pm_init(struct pci_dev *dev)
|
||||
}
|
||||
|
||||
dev->pm_cap = pm;
|
||||
dev->d3_delay = PCI_PM_D3_WAIT;
|
||||
dev->d3hot_delay = PCI_PM_D3HOT_WAIT;
|
||||
dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
|
||||
dev->bridge_d3 = pci_bridge_d3_possible(dev);
|
||||
dev->d3cold_allowed = true;
|
||||
@ -3038,7 +3051,7 @@ void pci_pm_init(struct pci_dev *dev)
|
||||
(pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D3hot) ? " D3hot" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
|
||||
dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
|
||||
dev->pme_poll = true;
|
||||
@ -4621,7 +4634,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
|
||||
*
|
||||
* NOTE: This causes the caller to sleep for twice the device power transition
|
||||
* cooldown period, which for the D0->D3hot and D3hot->D0 transitions is 10 ms
|
||||
* by default (i.e. unless the @dev's d3_delay field has a different value).
|
||||
* by default (i.e. unless the @dev's d3hot_delay field has a different value).
|
||||
* Moreover, only devices in D0 can be reset by this function.
|
||||
*/
|
||||
static int pci_pm_reset(struct pci_dev *dev, int probe)
|
||||
@ -4701,9 +4714,7 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
|
||||
}
|
||||
if (active && ret)
|
||||
msleep(delay);
|
||||
else if (ret != active)
|
||||
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
|
||||
active ? "set" : "cleared");
|
||||
|
||||
return ret == active;
|
||||
}
|
||||
|
||||
@ -4828,6 +4839,7 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
|
||||
delay);
|
||||
if (!pcie_wait_for_link_delay(dev, true, delay)) {
|
||||
/* Did not train, no need to wait any further */
|
||||
pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -4920,16 +4932,10 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
|
||||
|
||||
static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if (dev->subordinate || !dev->slot ||
|
||||
if (dev->multifunction || dev->subordinate || !dev->slot ||
|
||||
dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
|
||||
return -ENOTTY;
|
||||
|
||||
list_for_each_entry(pdev, &dev->bus->devices, bus_list)
|
||||
if (pdev != dev && pdev->slot == dev->slot)
|
||||
return -ENOTTY;
|
||||
|
||||
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
|
||||
}
|
||||
|
||||
@ -6005,7 +6011,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
|
||||
|
||||
if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
if (decode == true)
|
||||
if (decode)
|
||||
cmd |= command_bits;
|
||||
else
|
||||
cmd &= ~command_bits;
|
||||
@ -6021,7 +6027,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
|
||||
if (bridge) {
|
||||
pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
|
||||
&cmd);
|
||||
if (decode == true)
|
||||
if (decode)
|
||||
cmd |= PCI_BRIDGE_CTL_VGA;
|
||||
else
|
||||
cmd &= ~PCI_BRIDGE_CTL_VGA;
|
||||
@ -6350,7 +6356,7 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
|
||||
|
||||
spin_lock(&resource_alignment_lock);
|
||||
if (resource_alignment_param)
|
||||
count = snprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
|
||||
count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
|
||||
spin_unlock(&resource_alignment_lock);
|
||||
|
||||
/*
|
||||
|
@ -43,10 +43,9 @@ int pci_probe_reset_function(struct pci_dev *dev);
|
||||
int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
|
||||
int pci_bus_error_reset(struct pci_dev *dev);
|
||||
|
||||
#define PCI_PM_D2_DELAY 200
|
||||
#define PCI_PM_D3_WAIT 10
|
||||
#define PCI_PM_D3COLD_WAIT 100
|
||||
#define PCI_PM_BUS_WAIT 50
|
||||
#define PCI_PM_D2_DELAY 200 /* usec; see PCIe r4.0, sec 5.9.1 */
|
||||
#define PCI_PM_D3HOT_WAIT 10 /* msec */
|
||||
#define PCI_PM_D3COLD_WAIT 100 /* msec */
|
||||
|
||||
/**
|
||||
* struct pci_platform_pm_ops - Firmware PM callbacks
|
||||
@ -178,7 +177,7 @@ extern struct mutex pci_slot_mutex;
|
||||
|
||||
extern raw_spinlock_t pci_lock;
|
||||
|
||||
extern unsigned int pci_pm_d3_delay;
|
||||
extern unsigned int pci_pm_d3hot_delay;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
void pci_no_msi(void);
|
||||
|
@ -74,14 +74,6 @@ struct pcie_link_state {
|
||||
* has one slot under it, so at most there are 8 functions.
|
||||
*/
|
||||
struct aspm_latency acceptable[8];
|
||||
|
||||
/* L1 PM Substate info */
|
||||
struct {
|
||||
u32 up_cap_ptr; /* L1SS cap ptr in upstream dev */
|
||||
u32 dw_cap_ptr; /* L1SS cap ptr in downstream dev */
|
||||
u32 ctl1; /* value to be programmed in ctl1 */
|
||||
u32 ctl2; /* value to be programmed in ctl2 */
|
||||
} l1ss;
|
||||
};
|
||||
|
||||
static int aspm_disabled, aspm_force;
|
||||
@ -308,8 +300,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
||||
}
|
||||
|
||||
/* Convert L0s latency encoding to ns */
|
||||
static u32 calc_l0s_latency(u32 encoding)
|
||||
static u32 calc_l0s_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (5 * 1000); /* > 4us */
|
||||
return (64 << encoding);
|
||||
@ -324,8 +318,10 @@ static u32 calc_l0s_acceptable(u32 encoding)
|
||||
}
|
||||
|
||||
/* Convert L1 latency encoding to ns */
|
||||
static u32 calc_l1_latency(u32 encoding)
|
||||
static u32 calc_l1_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (65 * 1000); /* > 64us */
|
||||
return (1000 << encoding);
|
||||
@ -380,58 +376,6 @@ static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||
}
|
||||
}
|
||||
|
||||
struct aspm_register_info {
|
||||
u32 support:2;
|
||||
u32 enabled:2;
|
||||
u32 latency_encoding_l0s;
|
||||
u32 latency_encoding_l1;
|
||||
|
||||
/* L1 substates */
|
||||
u32 l1ss_cap_ptr;
|
||||
u32 l1ss_cap;
|
||||
u32 l1ss_ctl1;
|
||||
u32 l1ss_ctl2;
|
||||
};
|
||||
|
||||
static void pcie_get_aspm_reg(struct pci_dev *pdev,
|
||||
struct aspm_register_info *info)
|
||||
{
|
||||
u16 reg16;
|
||||
u32 reg32;
|
||||
|
||||
pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, ®32);
|
||||
info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
|
||||
info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
|
||||
info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, ®16);
|
||||
info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
|
||||
|
||||
/* Read L1 PM substate capabilities */
|
||||
info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
|
||||
info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!info->l1ss_cap_ptr)
|
||||
return;
|
||||
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
|
||||
&info->l1ss_cap);
|
||||
if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
|
||||
info->l1ss_cap = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we don't have LTR for the entire path from the Root Complex
|
||||
* to this device, we can't use ASPM L1.2 because it relies on the
|
||||
* LTR_L1.2_THRESHOLD. See PCIe r4.0, secs 5.5.4, 6.18.
|
||||
*/
|
||||
if (!pdev->ltr_path)
|
||||
info->l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
|
||||
|
||||
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
|
||||
&info->l1ss_ctl1);
|
||||
pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
|
||||
&info->l1ss_ctl2);
|
||||
}
|
||||
|
||||
static void pcie_aspm_check_latency(struct pci_dev *endpoint)
|
||||
{
|
||||
u32 latency, l1_switch_latency = 0;
|
||||
@ -493,39 +437,49 @@ static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
|
||||
u32 clear, u32 set)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
pci_read_config_dword(pdev, pos, &val);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
pci_write_config_dword(pdev, pos, val);
|
||||
}
|
||||
|
||||
/* Calculate L1.2 PM substate timing parameters */
|
||||
static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
||||
struct aspm_register_info *upreg,
|
||||
struct aspm_register_info *dwreg)
|
||||
u32 parent_l1ss_cap, u32 child_l1ss_cap)
|
||||
{
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
u32 val1, val2, scale1, scale2;
|
||||
u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
|
||||
|
||||
link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
|
||||
link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
|
||||
link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
|
||||
u32 ctl1 = 0, ctl2 = 0;
|
||||
u32 pctl1, pctl2, cctl1, cctl2;
|
||||
u32 pl1_2_enables, cl1_2_enables;
|
||||
|
||||
if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
|
||||
return;
|
||||
|
||||
/* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
t_common_mode = max(val1, val2);
|
||||
|
||||
/* Choose the greater of the two Port T_POWER_ON times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
|
||||
if (calc_l1ss_pwron(link->pdev, scale1, val1) >
|
||||
calc_l1ss_pwron(link->downstream, scale2, val2)) {
|
||||
link->l1ss.ctl2 |= scale1 | (val1 << 3);
|
||||
t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
|
||||
if (calc_l1ss_pwron(parent, scale1, val1) >
|
||||
calc_l1ss_pwron(child, scale2, val2)) {
|
||||
ctl2 |= scale1 | (val1 << 3);
|
||||
t_power_on = calc_l1ss_pwron(parent, scale1, val1);
|
||||
} else {
|
||||
link->l1ss.ctl2 |= scale2 | (val2 << 3);
|
||||
t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
|
||||
ctl2 |= scale2 | (val2 << 3);
|
||||
t_power_on = calc_l1ss_pwron(child, scale2, val2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -540,14 +494,60 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
||||
*/
|
||||
l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||
encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||
link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
|
||||
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
|
||||
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
|
||||
|
||||
if (ctl1 == pctl1 && ctl1 == cctl1 &&
|
||||
ctl2 == pctl2 && ctl2 == cctl2)
|
||||
return;
|
||||
|
||||
/* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
|
||||
pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||
cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||
|
||||
if (pl1_2_enables || cl1_2_enables) {
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||
}
|
||||
|
||||
/* Program T_POWER_ON times in both ports */
|
||||
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||
pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||
|
||||
/* Program Common_Mode_Restore_Time in upstream device */
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
|
||||
|
||||
/* Program LTR_L1.2_THRESHOLD time in both ports */
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||
|
||||
if (pl1_2_enables || cl1_2_enables) {
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
|
||||
pl1_2_enables);
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
|
||||
cl1_2_enables);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
{
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
u32 parent_lnkcap, child_lnkcap;
|
||||
u16 parent_lnkctl, child_lnkctl;
|
||||
u32 parent_l1ss_cap, child_l1ss_cap;
|
||||
u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0;
|
||||
struct pci_bus *linkbus = parent->subordinate;
|
||||
struct aspm_register_info upreg, dwreg;
|
||||
|
||||
if (blacklist) {
|
||||
/* Set enabled/disable so that we will disable ASPM later */
|
||||
@ -556,26 +556,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get upstream/downstream components' register state */
|
||||
pcie_get_aspm_reg(parent, &upreg);
|
||||
pcie_get_aspm_reg(child, &dwreg);
|
||||
|
||||
/*
|
||||
* If ASPM not supported, don't mess with the clocks and link,
|
||||
* bail out now.
|
||||
*/
|
||||
if (!(upreg.support & dwreg.support))
|
||||
pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
|
||||
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
|
||||
if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS))
|
||||
return;
|
||||
|
||||
/* Configure common clock before checking latencies */
|
||||
pcie_aspm_configure_common_clock(link);
|
||||
|
||||
/*
|
||||
* Re-read upstream/downstream components' register state
|
||||
* after clock configuration
|
||||
* Re-read upstream/downstream components' register state after
|
||||
* clock configuration. L0s & L1 exit latencies in the otherwise
|
||||
* read-only Link Capabilities may change depending on common clock
|
||||
* configuration (PCIe r5.0, sec 7.5.3.6).
|
||||
*/
|
||||
pcie_get_aspm_reg(parent, &upreg);
|
||||
pcie_get_aspm_reg(child, &dwreg);
|
||||
pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
|
||||
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
|
||||
pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
|
||||
|
||||
/*
|
||||
* Setup L0s state
|
||||
@ -584,44 +586,71 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
* given link unless components on both sides of the link each
|
||||
* support L0s.
|
||||
*/
|
||||
if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
|
||||
if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
|
||||
link->aspm_support |= ASPM_STATE_L0S;
|
||||
if (dwreg.enabled & PCIE_LINK_STATE_L0S)
|
||||
|
||||
if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
|
||||
link->aspm_enabled |= ASPM_STATE_L0S_UP;
|
||||
if (upreg.enabled & PCIE_LINK_STATE_L0S)
|
||||
if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
|
||||
link->aspm_enabled |= ASPM_STATE_L0S_DW;
|
||||
link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
|
||||
link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
|
||||
link->latency_up.l0s = calc_l0s_latency(parent_lnkcap);
|
||||
link->latency_dw.l0s = calc_l0s_latency(child_lnkcap);
|
||||
|
||||
/* Setup L1 state */
|
||||
if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
|
||||
if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
|
||||
link->aspm_support |= ASPM_STATE_L1;
|
||||
if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
|
||||
|
||||
if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
|
||||
link->aspm_enabled |= ASPM_STATE_L1;
|
||||
link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
|
||||
link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
|
||||
link->latency_up.l1 = calc_l1_latency(parent_lnkcap);
|
||||
link->latency_dw.l1 = calc_l1_latency(child_lnkcap);
|
||||
|
||||
/* Setup L1 substate */
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||
&parent_l1ss_cap);
|
||||
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||
&child_l1ss_cap);
|
||||
|
||||
if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||
parent_l1ss_cap = 0;
|
||||
if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||
child_l1ss_cap = 0;
|
||||
|
||||
/*
|
||||
* If we don't have LTR for the entire path from the Root Complex
|
||||
* to this device, we can't use ASPM L1.2 because it relies on the
|
||||
* LTR_L1.2_THRESHOLD. See PCIe r4.0, secs 5.5.4, 6.18.
|
||||
*/
|
||||
if (!child->ltr_path)
|
||||
child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
|
||||
|
||||
if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
|
||||
link->aspm_support |= ASPM_STATE_L1_1;
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
|
||||
if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
|
||||
link->aspm_support |= ASPM_STATE_L1_2;
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
|
||||
if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
|
||||
link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
|
||||
if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
|
||||
if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
|
||||
link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
|
||||
|
||||
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
if (parent_l1ss_cap)
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
&parent_l1ss_ctl1);
|
||||
if (child_l1ss_cap)
|
||||
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
&child_l1ss_ctl1);
|
||||
|
||||
if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
link->aspm_enabled |= ASPM_STATE_L1_1;
|
||||
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
link->aspm_enabled |= ASPM_STATE_L1_2;
|
||||
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
|
||||
if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
|
||||
|
||||
if (link->aspm_support & ASPM_STATE_L1SS)
|
||||
aspm_calc_l1ss_info(link, &upreg, &dwreg);
|
||||
aspm_calc_l1ss_info(link, parent_l1ss_cap, child_l1ss_cap);
|
||||
|
||||
/* Save default state */
|
||||
link->aspm_default = link->aspm_enabled;
|
||||
@ -651,24 +680,11 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
|
||||
u32 clear, u32 set)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
pci_read_config_dword(pdev, pos, &val);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
pci_write_config_dword(pdev, pos, val);
|
||||
}
|
||||
|
||||
/* Configure the ASPM L1 substates */
|
||||
static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
{
|
||||
u32 val, enable_req;
|
||||
struct pci_dev *child = link->downstream, *parent = link->pdev;
|
||||
u32 up_cap_ptr = link->l1ss.up_cap_ptr;
|
||||
u32 dw_cap_ptr = link->l1ss.dw_cap_ptr;
|
||||
|
||||
enable_req = (link->aspm_enabled ^ state) & state;
|
||||
|
||||
@ -686,9 +702,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
*/
|
||||
|
||||
/* Disable all L1 substates */
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, 0);
|
||||
/*
|
||||
* If needed, disable L1, and it gets enabled later
|
||||
@ -701,30 +717,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
PCI_EXP_LNKCTL_ASPM_L1, 0);
|
||||
}
|
||||
|
||||
if (enable_req & ASPM_STATE_L1_2_MASK) {
|
||||
|
||||
/* Program T_POWER_ON times in both ports */
|
||||
pci_write_config_dword(parent, up_cap_ptr + PCI_L1SS_CTL2,
|
||||
link->l1ss.ctl2);
|
||||
pci_write_config_dword(child, dw_cap_ptr + PCI_L1SS_CTL2,
|
||||
link->l1ss.ctl2);
|
||||
|
||||
/* Program Common_Mode_Restore_Time in upstream device */
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_CM_RESTORE_TIME,
|
||||
link->l1ss.ctl1);
|
||||
|
||||
/* Program LTR_L1.2_THRESHOLD time in both ports */
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
|
||||
link->l1ss.ctl1);
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||
PCI_L1SS_CTL1_LTR_L12_TH_SCALE,
|
||||
link->l1ss.ctl1);
|
||||
}
|
||||
|
||||
val = 0;
|
||||
if (state & ASPM_STATE_L1_1)
|
||||
val |= PCI_L1SS_CTL1_ASPM_L1_1;
|
||||
@ -736,9 +728,9 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
val |= PCI_L1SS_CTL1_PCIPM_L1_2;
|
||||
|
||||
/* Enable what we need to enable */
|
||||
pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
|
||||
pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
* and warns when links become degraded in operation.
|
||||
*/
|
||||
|
||||
#define dev_fmt(fmt) "bw_notification: " fmt
|
||||
|
||||
#include "../pci.h"
|
||||
#include "portdrv.h"
|
||||
|
||||
@ -97,6 +99,7 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
|
||||
return ret;
|
||||
|
||||
pcie_enable_link_bandwidth_notification(srv->port);
|
||||
pci_info(srv->port, "enabled with IRQ %d\n", srv->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -103,7 +103,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
|
||||
* Wait until the Link is inactive, then clear DPC Trigger Status
|
||||
* to allow the Port to leave DPC.
|
||||
*/
|
||||
pcie_wait_for_link(pdev, false);
|
||||
if (!pcie_wait_for_link(pdev, false))
|
||||
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
|
||||
|
||||
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
@ -111,8 +112,10 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
|
||||
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
|
||||
PCI_EXP_DPC_STATUS_TRIGGER);
|
||||
|
||||
if (!pcie_wait_for_link(pdev, true))
|
||||
if (!pcie_wait_for_link(pdev, true)) {
|
||||
pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
@ -941,6 +941,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
|
||||
|
||||
pcibios_add_bus(bus);
|
||||
|
||||
if (bus->ops->add_bus) {
|
||||
err = bus->ops->add_bus(bus);
|
||||
if (WARN_ON(err < 0))
|
||||
dev_err(&bus->dev, "failed to add bus: %d\n", err);
|
||||
}
|
||||
|
||||
/* Create legacy_io and legacy_mem files for this bus */
|
||||
pci_create_legacy_files(bus);
|
||||
|
||||
@ -1036,6 +1042,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
struct pci_dev *bridge, int busnr)
|
||||
{
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *host;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
@ -1045,11 +1052,16 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
return NULL;
|
||||
|
||||
child->parent = parent;
|
||||
child->ops = parent->ops;
|
||||
child->msi = parent->msi;
|
||||
child->sysdata = parent->sysdata;
|
||||
child->bus_flags = parent->bus_flags;
|
||||
|
||||
host = pci_find_host_bridge(parent);
|
||||
if (host->child_ops)
|
||||
child->ops = host->child_ops;
|
||||
else
|
||||
child->ops = parent->ops;
|
||||
|
||||
/*
|
||||
* Initialize some portions of the bus device, but don't register
|
||||
* it now as the parent is not properly set up yet.
|
||||
@ -2106,6 +2118,9 @@ static void pci_configure_ltr(struct pci_dev *dev)
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
/* Read L1 PM substate capabilities */
|
||||
dev->l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
|
||||
if (!(cap & PCI_EXP_DEVCAP2_LTR))
|
||||
return;
|
||||
|
@ -1846,7 +1846,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_pci
|
||||
*/
|
||||
static void quirk_intel_pcie_pm(struct pci_dev *dev)
|
||||
{
|
||||
pci_pm_d3_delay = 120;
|
||||
pci_pm_d3hot_delay = 120;
|
||||
dev->no_d1d2 = 1;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e2, quirk_intel_pcie_pm);
|
||||
@ -1873,12 +1873,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
|
||||
|
||||
static void quirk_d3hot_delay(struct pci_dev *dev, unsigned int delay)
|
||||
{
|
||||
if (dev->d3_delay >= delay)
|
||||
if (dev->d3hot_delay >= delay)
|
||||
return;
|
||||
|
||||
dev->d3_delay = delay;
|
||||
dev->d3hot_delay = delay;
|
||||
pci_info(dev, "extending delay after power-on from D3hot to %d msec\n",
|
||||
dev->d3_delay);
|
||||
dev->d3hot_delay);
|
||||
}
|
||||
|
||||
static void quirk_radeon_pm(struct pci_dev *dev)
|
||||
@ -3387,36 +3387,36 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
|
||||
* PCI devices which are on Intel chips can skip the 10ms delay
|
||||
* before entering D3 mode.
|
||||
*/
|
||||
static void quirk_remove_d3_delay(struct pci_dev *dev)
|
||||
static void quirk_remove_d3hot_delay(struct pci_dev *dev)
|
||||
{
|
||||
dev->d3_delay = 0;
|
||||
dev->d3hot_delay = 0;
|
||||
}
|
||||
/* C600 Series devices do not need 10ms d3_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c00, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c0c, quirk_remove_d3_delay);
|
||||
/* Lynxpoint-H PCH devices do not need 10ms d3_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c18, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c1c, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c20, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c2d, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c31, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3a, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3d, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3_delay);
|
||||
/* Intel Cherrytrail devices do not need 10ms d3_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2280, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b0, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b8, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22d8, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22dc, quirk_remove_d3_delay);
|
||||
/* C600 Series devices do not need 10ms d3hot_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c00, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c0c, quirk_remove_d3hot_delay);
|
||||
/* Lynxpoint-H PCH devices do not need 10ms d3hot_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c18, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c1c, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c20, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c2d, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c31, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3a, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3d, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3hot_delay);
|
||||
/* Intel Cherrytrail devices do not need 10ms d3hot_delay */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2280, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b0, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b8, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22d8, quirk_remove_d3hot_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22dc, quirk_remove_d3hot_delay);
|
||||
|
||||
/*
|
||||
* Some devices may pass our check in pci_intx_mask_supported() if
|
||||
@ -4892,6 +4892,13 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently this quirk does the equivalent of
|
||||
* PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
|
||||
*
|
||||
* TODO: This quirk also needs to do equivalent of PCI_ACS_TB,
|
||||
* if dev->external_facing || dev->untrusted
|
||||
*/
|
||||
static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_quirk_intel_pch_acs_match(dev))
|
||||
@ -4931,6 +4938,9 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)
|
||||
ctrl |= (cap & PCI_ACS_CR);
|
||||
ctrl |= (cap & PCI_ACS_UF);
|
||||
|
||||
if (dev->external_facing || dev->untrusted)
|
||||
ctrl |= (cap & PCI_ACS_TB);
|
||||
|
||||
pci_write_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, ctrl);
|
||||
|
||||
pci_info(dev, "Intel SPT PCH root port ACS workaround enabled\n");
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define COMPHY_SIP_POWER_ON 0x82000001
|
||||
#define COMPHY_SIP_POWER_OFF 0x82000002
|
||||
#define COMPHY_SIP_PLL_LOCK 0x82000003
|
||||
#define COMPHY_FW_NOT_SUPPORTED (-1)
|
||||
|
||||
#define COMPHY_FW_MODE_SATA 0x1
|
||||
#define COMPHY_FW_MODE_SGMII 0x2
|
||||
@ -112,10 +111,19 @@ static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
|
||||
unsigned long mode)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
s32 ret;
|
||||
|
||||
arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
|
||||
ret = res.a0;
|
||||
|
||||
return res.a0;
|
||||
switch (ret) {
|
||||
case SMCCC_RET_SUCCESS:
|
||||
return 0;
|
||||
case SMCCC_RET_NOT_SUPPORTED:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
|
||||
@ -220,7 +228,7 @@ static int mvebu_a3700_comphy_power_on(struct phy *phy)
|
||||
}
|
||||
|
||||
ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
|
||||
if (ret == COMPHY_FW_NOT_SUPPORTED)
|
||||
if (ret == -EOPNOTSUPP)
|
||||
dev_err(lane->dev,
|
||||
"unsupported SMC call, try updating your firmware\n");
|
||||
|
||||
|
@ -123,7 +123,6 @@
|
||||
|
||||
#define COMPHY_SIP_POWER_ON 0x82000001
|
||||
#define COMPHY_SIP_POWER_OFF 0x82000002
|
||||
#define COMPHY_FW_NOT_SUPPORTED (-1)
|
||||
|
||||
/*
|
||||
* A lane is described by the following bitfields:
|
||||
@ -273,10 +272,19 @@ static int mvebu_comphy_smc(unsigned long function, unsigned long phys,
|
||||
unsigned long lane, unsigned long mode)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
s32 ret;
|
||||
|
||||
arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res);
|
||||
ret = res.a0;
|
||||
|
||||
return res.a0;
|
||||
switch (ret) {
|
||||
case SMCCC_RET_SUCCESS:
|
||||
return 0;
|
||||
case SMCCC_RET_NOT_SUPPORTED:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mvebu_comphy_get_mode(bool fw_mode, int lane, int port,
|
||||
@ -819,7 +827,7 @@ static int mvebu_comphy_power_on(struct phy *phy)
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
if (ret == COMPHY_FW_NOT_SUPPORTED)
|
||||
if (ret == -EOPNOTSUPP)
|
||||
dev_err(priv->dev,
|
||||
"unsupported SMC call, try updating your firmware\n");
|
||||
|
||||
|
@ -1570,7 +1570,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
|
||||
spin_lock_init(&isp->lock);
|
||||
|
||||
/* This is not a true PCI device on SoC, so the delay is not needed. */
|
||||
pdev->d3_delay = 0;
|
||||
pdev->d3hot_delay = 0;
|
||||
|
||||
pci_set_drvdata(pdev, isp);
|
||||
|
||||
|
@ -53,6 +53,24 @@ enum {
|
||||
GHES_SEV_PANIC = 0x3,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_GHES
|
||||
/**
|
||||
* ghes_register_vendor_record_notifier - register a notifier for vendor
|
||||
* records that the kernel would otherwise ignore.
|
||||
* @nb: pointer to the notifier_block structure of the event handler.
|
||||
*
|
||||
* return 0 : SUCCESS, non-zero : FAIL
|
||||
*/
|
||||
int ghes_register_vendor_record_notifier(struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* ghes_unregister_vendor_record_notifier - unregister the previously
|
||||
* registered vendor record notifier.
|
||||
* @nb: pointer to the notifier_block structure of the vendor record handler.
|
||||
*/
|
||||
void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
|
||||
#endif
|
||||
|
||||
int ghes_estatus_pool_init(int num_ghes);
|
||||
|
||||
/* From drivers/edac/ghes_edac.c */
|
||||
|
@ -911,18 +911,6 @@ static inline void iowrite64_rep(volatile void __iomem *addr,
|
||||
#include <linux/vmalloc.h>
|
||||
#define __io_virt(x) ((void __force *)(x))
|
||||
|
||||
#ifndef CONFIG_GENERIC_IOMAP
|
||||
struct pci_dev;
|
||||
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
|
||||
|
||||
#ifndef pci_iounmap
|
||||
#define pci_iounmap pci_iounmap
|
||||
static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_GENERIC_IOMAP */
|
||||
|
||||
/*
|
||||
* Change virtual addresses to physical addresses and vv.
|
||||
* These are pretty trivial
|
||||
@ -1016,6 +1004,16 @@ static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
|
||||
port &= IO_SPACE_LIMIT;
|
||||
return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
|
||||
}
|
||||
#define __pci_ioport_unmap __pci_ioport_unmap
|
||||
static inline void __pci_ioport_unmap(void __iomem *p)
|
||||
{
|
||||
uintptr_t start = (uintptr_t) PCI_IOBASE;
|
||||
uintptr_t addr = (uintptr_t) p;
|
||||
|
||||
if (addr >= start && addr < start + IO_SPACE_LIMIT)
|
||||
return;
|
||||
iounmap(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ioport_unmap
|
||||
@ -1030,6 +1028,23 @@ extern void ioport_unmap(void __iomem *p);
|
||||
#endif /* CONFIG_GENERIC_IOMAP */
|
||||
#endif /* CONFIG_HAS_IOPORT_MAP */
|
||||
|
||||
#ifndef CONFIG_GENERIC_IOMAP
|
||||
struct pci_dev;
|
||||
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
|
||||
|
||||
#ifndef __pci_ioport_unmap
|
||||
static inline void __pci_ioport_unmap(void __iomem *p) {}
|
||||
#endif
|
||||
|
||||
#ifndef pci_iounmap
|
||||
#define pci_iounmap pci_iounmap
|
||||
static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
|
||||
{
|
||||
__pci_ioport_unmap(p);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_GENERIC_IOMAP */
|
||||
|
||||
/*
|
||||
* Convert a virtual cached pointer to an uncached pointer
|
||||
*/
|
||||
|
@ -51,6 +51,7 @@ extern const struct pci_ecam_ops pci_generic_ecam_ops;
|
||||
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
|
||||
extern const struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */
|
||||
extern const struct pci_ecam_ops pci_32b_read_ops; /* 32-bit read only */
|
||||
extern const struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */
|
||||
extern const struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
|
||||
extern const struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
|
||||
|
@ -19,7 +19,7 @@ void pci_ep_cfs_remove_epf_group(struct config_group *group);
|
||||
#else
|
||||
static inline struct config_group *pci_ep_cfs_add_epc_group(const char *name)
|
||||
{
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void pci_ep_cfs_remove_epc_group(struct config_group *group)
|
||||
@ -28,7 +28,7 @@ static inline void pci_ep_cfs_remove_epc_group(struct config_group *group)
|
||||
|
||||
static inline struct config_group *pci_ep_cfs_add_epf_group(const char *name)
|
||||
{
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void pci_ep_cfs_remove_epf_group(struct config_group *group)
|
||||
|
@ -373,13 +373,14 @@ struct pci_dev {
|
||||
user sysfs */
|
||||
unsigned int clear_retrain_link:1; /* Need to clear Retrain Link
|
||||
bit manually */
|
||||
unsigned int d3_delay; /* D3->D0 transition time in ms */
|
||||
unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */
|
||||
unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
struct pcie_link_state *link_state; /* ASPM link state */
|
||||
unsigned int ltr_path:1; /* Latency Tolerance Reporting
|
||||
supported from root to here */
|
||||
int l1ss; /* L1SS Capability pointer */
|
||||
#endif
|
||||
unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */
|
||||
|
||||
@ -523,6 +524,7 @@ struct pci_host_bridge {
|
||||
struct device dev;
|
||||
struct pci_bus *bus; /* Root bus */
|
||||
struct pci_ops *ops;
|
||||
struct pci_ops *child_ops;
|
||||
void *sysdata;
|
||||
int busnr;
|
||||
struct list_head windows; /* resource_entry */
|
||||
@ -2034,10 +2036,6 @@ int pcibios_alloc_irq(struct pci_dev *dev);
|
||||
void pcibios_free_irq(struct pci_dev *dev);
|
||||
resource_size_t pcibios_default_alignment(void);
|
||||
|
||||
#ifdef CONFIG_HIBERNATE_CALLBACKS
|
||||
extern struct dev_pm_ops pcibios_pm_ops;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
|
||||
void __init pci_mmcfg_early_init(void);
|
||||
void __init pci_mmcfg_late_init(void);
|
||||
|
@ -76,6 +76,7 @@
|
||||
#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
|
||||
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
|
||||
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
|
||||
#define PCI_HEADER_TYPE_MASK 0x7f
|
||||
#define PCI_HEADER_TYPE_NORMAL 0
|
||||
#define PCI_HEADER_TYPE_BRIDGE 1
|
||||
#define PCI_HEADER_TYPE_CARDBUS 2
|
||||
@ -246,7 +247,7 @@
|
||||
#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
|
||||
#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
|
||||
#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
|
||||
#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
|
||||
#define PCI_PM_CAP_PME_D3hot 0x4000 /* PME# from D3 (hot) */
|
||||
#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
|
||||
#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
|
||||
#define PCI_PM_CTRL 4 /* PM control and status register */
|
||||
@ -532,6 +533,8 @@
|
||||
#define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
|
||||
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
|
||||
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
|
||||
#define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */
|
||||
#define PCI_EXP_LNKCAP_ASPM_L1 0x00000800 /* ASPM L1 Support */
|
||||
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
|
||||
#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */
|
||||
#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* Clock Power Management */
|
||||
@ -1056,6 +1059,7 @@
|
||||
#define PCI_L1SS_CTL1_PCIPM_L1_1 0x00000002 /* PCI-PM L1.1 Enable */
|
||||
#define PCI_L1SS_CTL1_ASPM_L1_2 0x00000004 /* ASPM L1.2 Enable */
|
||||
#define PCI_L1SS_CTL1_ASPM_L1_1 0x00000008 /* ASPM L1.1 Enable */
|
||||
#define PCI_L1SS_CTL1_L1_2_MASK 0x00000005
|
||||
#define PCI_L1SS_CTL1_L1SS_MASK 0x0000000f
|
||||
#define PCI_L1SS_CTL1_CM_RESTORE_TIME 0x0000ff00 /* Common_Mode_Restore_Time */
|
||||
#define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */
|
||||
|
Loading…
Reference in New Issue
Block a user