diff options
Diffstat (limited to 'drivers/pci/controller/pci-xgene.c')
| -rw-r--r-- | drivers/pci/controller/pci-xgene.c | 171 |
1 files changed, 87 insertions, 84 deletions
diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index d1efa8ffbae1..b95afa35201d 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ -/** +/* * APM X-Gene PCIe Driver * * Copyright (c) 2014 Applied Micro Circuits Corporation. @@ -12,9 +12,9 @@ #include <linux/jiffies.h> #include <linux/memblock.h> #include <linux/init.h> +#include <linux/irqdomain.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_pci.h> #include <linux/pci.h> #include <linux/pci-acpi.h> @@ -48,20 +48,16 @@ #define EN_COHERENCY 0xF0000000 #define EN_REG 0x00000001 #define OB_LO_IO 0x00000002 -#define XGENE_PCIE_VENDORID 0x10E8 #define XGENE_PCIE_DEVICEID 0xE004 -#define SZ_1T (SZ_1G*1024ULL) #define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe) #define XGENE_V1_PCI_EXP_CAP 0x40 /* PCIe IP version */ -#define XGENE_PCIE_IP_VER_UNKN 0 #define XGENE_PCIE_IP_VER_1 1 #define XGENE_PCIE_IP_VER_2 2 -#if defined(CONFIG_PCI_XGENE) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) -struct xgene_pcie_port { +struct xgene_pcie { struct device_node *node; struct device *dev; struct clk *clk; @@ -72,12 +68,12 @@ struct xgene_pcie_port { u32 version; }; -static u32 xgene_pcie_readl(struct xgene_pcie_port *port, u32 reg) +static u32 xgene_pcie_readl(struct xgene_pcie *port, u32 reg) { return readl(port->csr_base + reg); } -static void xgene_pcie_writel(struct xgene_pcie_port *port, u32 reg, u32 val) +static void xgene_pcie_writel(struct xgene_pcie *port, u32 reg, u32 val) { writel(val, port->csr_base + reg); } @@ -87,15 +83,15 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags) return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; } -static inline struct xgene_pcie_port *pcie_bus_to_port(struct pci_bus *bus) +static inline struct xgene_pcie *pcie_bus_to_port(struct pci_bus *bus) { struct pci_config_window *cfg; if (acpi_disabled) - return (struct xgene_pcie_port *)(bus->sysdata); + return (struct xgene_pcie *)(bus->sysdata); cfg = bus->sysdata; - return (struct xgene_pcie_port *)(cfg->priv); + return (struct xgene_pcie *)(cfg->priv); } /* @@ -104,7 +100,7 @@ static inline struct xgene_pcie_port *pcie_bus_to_port(struct pci_bus *bus) */ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) { - struct xgene_pcie_port *port = pcie_bus_to_port(bus); + struct xgene_pcie *port = pcie_bus_to_port(bus); if (bus->number >= (bus->primary + 1)) return port->cfg_base + AXI_EP_CFG_ACCESS; @@ -118,7 +114,7 @@ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) */ static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) { - struct xgene_pcie_port *port = pcie_bus_to_port(bus); + struct xgene_pcie *port = pcie_bus_to_port(bus); unsigned int b, d, f; u32 rtdid_val = 0; @@ -165,31 +161,32 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct xgene_pcie_port *port = pcie_bus_to_port(bus); + struct xgene_pcie *port = pcie_bus_to_port(bus); + int ret; - if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) != - PCIBIOS_SUCCESSFUL) - return PCIBIOS_DEVICE_NOT_FOUND; + ret = pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; /* - * The v1 controller has a bug in its Configuration Request - * Retry Status (CRS) logic: when CRS is enabled and we read the - * Vendor and Device ID of a non-existent device, the controller - * fabricates return data of 0xFFFF0001 ("device exists but is not - * ready") instead of 0xFFFFFFFF ("device does not exist"). This - * causes the PCI core to retry the read until it times out. - * Avoid this by not claiming to support CRS. + * The v1 controller has a bug in its Configuration Request Retry + * Status (RRS) logic: when RRS Software Visibility is enabled and + * we read the Vendor and Device ID of a non-existent device, the + * controller fabricates return data of 0xFFFF0001 ("device exists + * but is not ready") instead of 0xFFFFFFFF (PCI_ERROR_RESPONSE) + * ("device does not exist"). This causes the PCI core to retry + * the read until it times out. Avoid this by not claiming to + * support RRS SV. */ if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) && ((where & ~0x3) == XGENE_V1_PCI_EXP_CAP + PCI_EXP_RTCTL)) - *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); + *val &= ~(PCI_EXP_RTCAP_RRS_SV << 16); if (size <= 2) *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); return PCIBIOS_SUCCESSFUL; } -#endif #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) static int xgene_get_csr_resource(struct acpi_device *adev, @@ -227,7 +224,7 @@ static int xgene_pcie_ecam_init(struct pci_config_window *cfg, u32 ipversion) { struct device *dev = cfg->parent; struct acpi_device *adev = to_acpi_device(dev); - struct xgene_pcie_port *port; + struct xgene_pcie *port; struct resource csr; int ret; @@ -257,7 +254,6 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) } const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { - .bus_shift = 16, .init = xgene_v1_pcie_ecam_init, .pci_ops = { .map_bus = xgene_pcie_map_bus, @@ -272,7 +268,6 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg) } const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = { - .bus_shift = 16, .init = xgene_v2_pcie_ecam_init, .pci_ops = { .map_bus = xgene_pcie_map_bus, @@ -282,8 +277,7 @@ const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = { }; #endif -#if defined(CONFIG_PCI_XGENE) -static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr, +static u64 xgene_pcie_set_ib_mask(struct xgene_pcie *port, u32 addr, u32 flags, u64 size) { u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags; @@ -309,7 +303,7 @@ static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr, return mask; } -static void xgene_pcie_linkup(struct xgene_pcie_port *port, +static void xgene_pcie_linkup(struct xgene_pcie *port, u32 *lanes, u32 *speed) { u32 val32; @@ -324,7 +318,7 @@ static void xgene_pcie_linkup(struct xgene_pcie_port *port, } } -static int xgene_pcie_init_port(struct xgene_pcie_port *port) +static int xgene_pcie_init_port(struct xgene_pcie *port) { struct device *dev = port->dev; int rc; @@ -344,7 +338,7 @@ static int xgene_pcie_init_port(struct xgene_pcie_port *port) return 0; } -static int xgene_pcie_map_reg(struct xgene_pcie_port *port, +static int xgene_pcie_map_reg(struct xgene_pcie *port, struct platform_device *pdev) { struct device *dev = port->dev; @@ -364,7 +358,7 @@ static int xgene_pcie_map_reg(struct xgene_pcie_port *port, return 0; } -static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, +static void xgene_pcie_setup_ob_reg(struct xgene_pcie *port, struct resource *res, u32 offset, u64 cpu_addr, u64 pci_addr) { @@ -396,7 +390,7 @@ static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, xgene_pcie_writel(port, offset + 0x14, upper_32_bits(pci_addr)); } -static void xgene_pcie_setup_cfg_reg(struct xgene_pcie_port *port) +static void xgene_pcie_setup_cfg_reg(struct xgene_pcie *port) { u64 addr = port->cfg_addr; @@ -405,7 +399,7 @@ static void xgene_pcie_setup_cfg_reg(struct xgene_pcie_port *port) xgene_pcie_writel(port, CFGCTL, EN_REG); } -static int xgene_pcie_map_ranges(struct xgene_pcie_port *port) +static int xgene_pcie_map_ranges(struct xgene_pcie *port) { struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port); struct resource_entry *window; @@ -446,7 +440,7 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port) return 0; } -static void xgene_pcie_setup_pims(struct xgene_pcie_port *port, u32 pim_reg, +static void xgene_pcie_setup_pims(struct xgene_pcie *port, u32 pim_reg, u64 pim, u64 size) { xgene_pcie_writel(port, pim_reg, lower_32_bits(pim)); @@ -480,29 +474,28 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) return -EINVAL; } -static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, - struct resource_entry *entry, - u8 *ib_reg_mask) +static void xgene_pcie_setup_ib_reg(struct xgene_pcie *port, + struct of_pci_range *range, u8 *ib_reg_mask) { void __iomem *cfg_base = port->cfg_base; struct device *dev = port->dev; - void *bar_addr; + void __iomem *bar_addr; u32 pim_reg; - u64 cpu_addr = entry->res->start; - u64 pci_addr = cpu_addr - entry->offset; - u64 size = resource_size(entry->res); + u64 cpu_addr = range->cpu_addr; + u64 pci_addr = range->pci_addr; + u64 size = range->size; u64 mask = ~(size - 1) | EN_REG; u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64; u32 bar_low; int region; - region = xgene_pcie_select_ib_reg(ib_reg_mask, size); + region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); if (region < 0) { dev_warn(dev, "invalid pcie dma-range config\n"); return; } - if (entry->res->flags & IORESOURCE_PREFETCH) + if (range->flags & IORESOURCE_PREFETCH) flags |= PCI_BASE_ADDRESS_MEM_PREFETCH; bar_low = pcie_bar_low_val((u32)cpu_addr, flags); @@ -531,20 +524,32 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, xgene_pcie_setup_pims(port, pim_reg, pci_addr, ~(size - 1)); } -static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) +static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie *port) { - struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port); - struct resource_entry *entry; + struct device_node *np = port->node; + struct of_pci_range range; + struct of_pci_range_parser parser; + struct device *dev = port->dev; u8 ib_reg_mask = 0; - resource_list_for_each_entry(entry, &bridge->dma_ranges) - xgene_pcie_setup_ib_reg(port, entry, &ib_reg_mask); + if (of_pci_dma_range_parser_init(&parser, np)) { + dev_err(dev, "missing dma-ranges property\n"); + return -EINVAL; + } + + /* Get the dma-ranges from DT */ + for_each_of_pci_range(&parser, &range) { + u64 end = range.cpu_addr + range.size - 1; + dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + range.flags, range.cpu_addr, end, range.pci_addr); + xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); + } return 0; } /* clear BAR configuration which was done by firmware */ -static void xgene_pcie_clear_config(struct xgene_pcie_port *port) +static void xgene_pcie_clear_config(struct xgene_pcie *port) { int i; @@ -552,7 +557,7 @@ static void xgene_pcie_clear_config(struct xgene_pcie_port *port) xgene_pcie_writel(port, i, 0); } -static int xgene_pcie_setup(struct xgene_pcie_port *port) +static int xgene_pcie_setup(struct xgene_pcie *port) { struct device *dev = port->dev; u32 val, lanes = 0, speed = 0; @@ -561,7 +566,7 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port) xgene_pcie_clear_config(port); /* setup the vendor and device IDs correctly */ - val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID; + val = (XGENE_PCIE_DEVICEID << 16) | PCI_VENDOR_ID_AMCC; xgene_pcie_writel(port, BRIDGE_CFG_0, val); ret = xgene_pcie_map_ranges(port); @@ -586,15 +591,36 @@ static struct pci_ops xgene_pcie_ops = { .write = pci_generic_config_write32, }; +static bool xgene_check_pcie_msi_ready(void) +{ + struct device_node *np; + struct irq_domain *d; + + if (!IS_ENABLED(CONFIG_PCI_XGENE_MSI)) + return true; + + np = of_find_compatible_node(NULL, NULL, "apm,xgene1-msi"); + if (!np) + return true; + + d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); + of_node_put(np); + + return d && irq_domain_is_msi_parent(d); +} + static int xgene_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; - struct xgene_pcie_port *port; - struct pci_bus *bus, *child; + struct xgene_pcie *port; struct pci_host_bridge *bridge; int ret; + if (!xgene_check_pcie_msi_ready()) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, + "MSI driver not ready\n"); + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); if (!bridge) return -ENOMEM; @@ -603,10 +629,7 @@ static int xgene_pcie_probe(struct platform_device *pdev) port->node = of_node_get(dn); port->dev = dev; - - port->version = XGENE_PCIE_IP_VER_UNKN; - if (of_device_is_compatible(port->node, "apm,xgene-pcie")) - port->version = XGENE_PCIE_IP_VER_1; + port->version = XGENE_PCIE_IP_VER_1; ret = xgene_pcie_map_reg(port, pdev); if (ret) @@ -616,33 +639,14 @@ static int xgene_pcie_probe(struct platform_device *pdev) if (ret) return ret; - ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, - &bridge->dma_ranges, NULL); - if (ret) - return ret; - ret = xgene_pcie_setup(port); if (ret) return ret; - bridge->dev.parent = dev; bridge->sysdata = port; - bridge->busnr = 0; bridge->ops = &xgene_pcie_ops; - bridge->map_irq = of_irq_parse_and_map_pci; - bridge->swizzle_irq = pci_common_swizzle; - - ret = pci_scan_root_bus_bridge(bridge); - if (ret < 0) - return ret; - bus = bridge->bus; - - pci_assign_unassigned_bus_resources(bus); - list_for_each_entry(child, &bus->children, node) - pcie_bus_configure_settings(child); - pci_bus_add_devices(bus); - return 0; + return pci_host_probe(bridge); } static const struct of_device_id xgene_pcie_match_table[] = { @@ -653,10 +657,9 @@ static const struct of_device_id xgene_pcie_match_table[] = { static struct platform_driver xgene_pcie_driver = { .driver = { .name = "xgene-pcie", - .of_match_table = of_match_ptr(xgene_pcie_match_table), + .of_match_table = xgene_pcie_match_table, .suppress_bind_attrs = true, }, .probe = xgene_pcie_probe, }; builtin_platform_driver(xgene_pcie_driver); -#endif |
