From 2ab51ddeca2fc32a7040d8560415be3366fa9ba7 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 15:36:26 -0500 Subject: ARM64: PCI: Add acpi_pci_bus_find_domain_nr() Extend pci_bus_find_domain_nr() so it can find the domain from either: - ACPI, via the new acpi_pci_bus_find_domain_nr() interface, or - DT, via of_pci_bus_find_domain_nr() Note that this is only used for CONFIG_PCI_DOMAINS_GENERIC=y, so it does not affect x86 or ia64. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/arm64/kernel') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 3c4e308b40a0..d5d3d26834cf 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -85,6 +86,12 @@ EXPORT_SYMBOL(pcibus_to_node); #endif #ifdef CONFIG_ACPI + +int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) +{ + return 0; +} + /* Root bridge scanning */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { -- cgit v1.2.3 From d8ed75d593321c80ccd92f9dba218e90286bde16 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 21:55:17 +0200 Subject: ARM64: PCI: ACPI support for legacy IRQs parsing and consolidation with DT code To enable PCI legacy IRQs on platforms booting with ACPI, arch code should include ACPI-specific callbacks that parse and set-up the device IRQ number, equivalent to the DT boot path. Owing to the current ACPI core scan handlers implementation, ACPI PCI legacy IRQs bindings cannot be parsed at device add time, since that would trigger ACPI scan handlers ordering issues depending on how the ACPI tables are defined. To solve this problem and consolidate FW PCI legacy IRQs parsing in one single pcibios callback (pending final removal), this patch moves DT PCI IRQ parsing to the pcibios_alloc_irq() callback (called by PCI core code at driver probe time) and adds ACPI PCI legacy IRQs parsing to the same callback too, so that FW PCI legacy IRQs parsing is confined in one single arch callback that can be easily removed when code parsing PCI legacy IRQs is consolidated and moved to core PCI code. Suggested-by: Lorenzo Pieralisi Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'arch/arm64/kernel') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index d5d3d26834cf..b3b8a2c68510 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -51,11 +51,16 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) } /* - * Try to assign the IRQ number from DT when adding a new device + * Try to assign the IRQ number when probing a new device */ -int pcibios_add_device(struct pci_dev *dev) +int pcibios_alloc_irq(struct pci_dev *dev) { - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); + if (acpi_disabled) + dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); +#ifdef CONFIG_ACPI + else + return acpi_pci_irq_enable(dev); +#endif return 0; } -- cgit v1.2.3 From f058f4fbd64028c9e9d433472cf6bcff8efdce7c Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 21:55:18 +0200 Subject: ARM64: PCI: Implement AML accessors for PCI_Config region On ACPI systems, the PCI_Config OperationRegion allows AML to access PCI configuration space. The ACPI CA AML interpreter uses performs config space accesses with acpi_os_read_pci_configuration() and acpi_os_write_pci_configuration(), which are OS-dependent functions supplied by acpi/osl.c. Implement the arch-specific raw_pci_read() and raw_pci_write() interfaces used by acpi/osl.c for PCI_Config accesses. N.B. PCI_Config accesses are not supported before PCI bus enumeration. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Jayachandran C Signed-off-by: Bjorn Helgaas Reviewed-by: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'arch/arm64/kernel') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index b3b8a2c68510..328f85727d35 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -71,13 +71,21 @@ int pcibios_alloc_irq(struct pci_dev *dev) int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val) { - return -ENXIO; + struct pci_bus *b = pci_find_bus(domain, bus); + + if (!b) + return PCIBIOS_DEVICE_NOT_FOUND; + return b->ops->read(b, devfn, reg, len, val); } int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 val) { - return -ENXIO; + struct pci_bus *b = pci_find_bus(domain, bus); + + if (!b) + return PCIBIOS_DEVICE_NOT_FOUND; + return b->ops->write(b, devfn, reg, len, val); } #ifdef CONFIG_NUMA -- cgit v1.2.3 From 0cb0786bac159ee4c983abab51093ef623849afa Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 21:55:19 +0200 Subject: ARM64: PCI: Support ACPI-based PCI host controller Implement pci_acpi_scan_root() and other arch-specific calls so ARM64 can use ACPI to setup and enumerate PCI buses. Use memory-mapped configuration space information from either the ACPI _CBA method or the MCFG table and the ECAM library and generic ECAM config accessor ops. Implement acpi_pci_bus_find_domain_nr() to retrieve the domain number from the acpi_pci_root structure. Implement pcibios_add_bus() and pcibios_remove_bus() to call acpi_pci_add_bus() and acpi_pci_remove_bus() for ACPI slot management and other configuration. Signed-off-by: Tomasz Nowicki Signed-off-by: Jayachandran C Signed-off-by: Bjorn Helgaas Reviewed-by: Lorenzo Pieralisi --- arch/arm64/Kconfig | 2 + arch/arm64/kernel/pci.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 3 deletions(-) (limited to 'arch/arm64/kernel') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5a0a691d4220..4806cde37b5f 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -3,6 +3,7 @@ config ARM64 select ACPI_CCA_REQUIRED if ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI + select ACPI_MCFG if ACPI select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ELF_RANDOMIZE @@ -96,6 +97,7 @@ config ARM64 select OF_EARLY_FLATTREE select OF_NUMA if NUMA && OF select OF_RESERVED_MEM + select PCI_ECAM if ACPI select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 328f85727d35..94cd43c20130 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include /* @@ -100,15 +102,123 @@ EXPORT_SYMBOL(pcibus_to_node); #ifdef CONFIG_ACPI +struct acpi_pci_generic_root_info { + struct acpi_pci_root_info common; + struct pci_config_window *cfg; /* config space mapping */ +}; + int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) { + struct pci_config_window *cfg = bus->sysdata; + struct acpi_device *adev = to_acpi_device(cfg->parent); + struct acpi_pci_root *root = acpi_driver_data(adev); + + return root->segment; +} + +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) +{ + if (!acpi_disabled) { + struct pci_config_window *cfg = bridge->bus->sysdata; + struct acpi_device *adev = to_acpi_device(cfg->parent); + ACPI_COMPANION_SET(&bridge->dev, adev); + } + return 0; } -/* Root bridge scanning */ +/* + * Lookup the bus range for the domain in MCFG, and set up config space + * mapping. + */ +static struct pci_config_window * +pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) +{ + struct resource *bus_res = &root->secondary; + u16 seg = root->segment; + struct pci_config_window *cfg; + struct resource cfgres; + unsigned int bsz; + + /* Use address from _CBA if present, otherwise lookup MCFG */ + if (!root->mcfg_addr) + root->mcfg_addr = pci_mcfg_lookup(seg, bus_res); + + if (!root->mcfg_addr) { + dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n", + seg, bus_res); + return NULL; + } + + bsz = 1 << pci_generic_ecam_ops.bus_shift; + cfgres.start = root->mcfg_addr + bus_res->start * bsz; + cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; + cfgres.flags = IORESOURCE_MEM; + cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, + &pci_generic_ecam_ops); + if (IS_ERR(cfg)) { + dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n", + seg, bus_res, PTR_ERR(cfg)); + return NULL; + } + + return cfg; +} + +/* release_info: free resources allocated by init_info */ +static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci) +{ + struct acpi_pci_generic_root_info *ri; + + ri = container_of(ci, struct acpi_pci_generic_root_info, common); + pci_ecam_free(ri->cfg); + kfree(ri); +} + +static struct acpi_pci_root_ops acpi_pci_root_ops = { + .release_info = pci_acpi_generic_release_info, +}; + +/* Interface called from ACPI code to setup PCI host controller */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { - /* TODO: Should be revisited when implementing PCI on ACPI */ - return NULL; + int node = acpi_get_node(root->device->handle); + struct acpi_pci_generic_root_info *ri; + struct pci_bus *bus, *child; + + ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); + if (!ri) + return NULL; + + ri->cfg = pci_acpi_setup_ecam_mapping(root); + if (!ri->cfg) { + kfree(ri); + return NULL; + } + + acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops; + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common, + ri->cfg); + if (!bus) + return NULL; + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + + return bus; +} + +void pcibios_add_bus(struct pci_bus *bus) +{ + acpi_pci_add_bus(bus); } + +void pcibios_remove_bus(struct pci_bus *bus) +{ + acpi_pci_remove_bus(bus); +} + #endif -- cgit v1.2.3 From f615bca4ccb9a91b33f0d378503b070fad97e181 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 8 Jun 2016 12:04:49 +0100 Subject: ARM64/PCI: Remove arch-specific pcibios_enable_device() On systems with PCI_PROBE_ONLY set, we rely on BAR assignments from firmware. Previously we did not insert those resources into the resource tree, so we had to skip pci_enable_resources() because it fails if resources are not in the resource tree. Now that we *do* insert resources even when PCI_PROBE_ONLY is set, we no longer need the ARM64-specific pcibios_enable_device(). Remove it so we use the generic version. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Will Deacon CC: Arnd Bergmann CC: Catalin Marinas --- arch/arm64/kernel/pci.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'arch/arm64/kernel') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 3c4e308b40a0..39cfa032ffa7 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -36,19 +36,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return res->start; } -/** - * pcibios_enable_device - Enable I/O and memory. - * @dev: PCI device to be enabled - * @mask: bitmask of BARs to enable - */ -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - if (pci_has_flag(PCI_PROBE_ONLY)) - return 0; - - return pci_enable_resources(dev, mask); -} - /* * Try to assign the IRQ number from DT when adding a new device */ -- cgit v1.2.3