From 70b3e89aaf421ad642c4ab0fb196e1c19ea838c5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 22 Oct 2014 13:58:49 +0900 Subject: PCI: exynos: Add exynos prefix to add_pcie_port()/pcie_init() The add_pcie_port() and pcie_init() functions are Exynos-specific. Add exynos prefix to avoid collision in global name space. Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index c5d0ca3..902d7cd 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -509,8 +509,8 @@ static struct pcie_host_ops exynos_pcie_host_ops = { .host_init = exynos_pcie_host_init, }; -static int __init add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int __init exynos_add_pcie_port(struct pcie_port *pp, + struct platform_device *pdev) { int ret; @@ -615,7 +615,7 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) goto fail_bus_clk; } - ret = add_pcie_port(pp, pdev); + ret = exynos_add_pcie_port(pp, pdev); if (ret < 0) goto fail_bus_clk; @@ -656,11 +656,11 @@ static struct platform_driver exynos_pcie_driver = { /* Exynos PCIe driver does not allow module unload */ -static int __init pcie_init(void) +static int __init exynos_pcie_init(void) { return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe); } -subsys_initcall(pcie_init); +subsys_initcall(exynos_pcie_init); MODULE_AUTHOR("Jingoo Han "); MODULE_DESCRIPTION("Samsung PCIe host controller driver"); -- cgit v0.10.2 From 5ba8368b7a78514d823cd7caaba7f6c2fdef8f97 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 23 Oct 2014 11:10:16 +0900 Subject: PCI: keystone: Make ks_dw_pcie_msi_domain_ops static Make ks_dw_pcie_msi_domain_ops static because it is used only in this file. Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Murali Karicheri Acked-by: Santosh Shilimkar diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index 34086ce..4a97cd1 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -201,7 +201,7 @@ static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq, return 0; } -const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = { +static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = { .map = ks_dw_pcie_msi_map, }; -- cgit v0.10.2 From 3c70637f7569de3ebf05e2961c05e05ed80e22df Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 23 Oct 2014 11:11:47 +0900 Subject: PCI: rcar: Make rcar_pci static Make rcar_pci static because it is used only in this file. Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Simon Horman diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 61158e0..0df9b29 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -389,7 +389,7 @@ static void rcar_pcie_add_bus(struct pci_bus *bus) } } -struct hw_pci rcar_pci = { +static struct hw_pci rcar_pci = { .setup = rcar_pcie_setup, .map_irq = of_irq_parse_and_map_pci, .ops = &rcar_pcie_ops, -- cgit v0.10.2 From a5525b240368cf496e669703a5fe169febbc72ef Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 23 Oct 2014 16:23:06 +0100 Subject: PCI: generic: Allocate config space windows after limiting bus number range The number of config space windows allocated for the host bridge depends on how many bus numbers are below the bridge. Instead of first allocating the windows and then limiting the bus resource, this patch reshuffles the code so that if any limitation is applied to the bus resource, it is taken into account in the windows allocation. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Will Deacon diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 3d2076f..1e1a80f 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -276,17 +276,17 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) return err; } - pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), - sizeof(*pci->cfg.win), GFP_KERNEL); - if (!pci->cfg.win) - return -ENOMEM; - /* Limit the bus-range to fit within reg */ bus_max = pci->cfg.bus_range.start + (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end, bus_max); + pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), + sizeof(*pci->cfg.win), GFP_KERNEL); + if (!pci->cfg.win) + return -ENOMEM; + /* Map our Configuration Space windows */ if (!devm_request_mem_region(dev, pci->cfg.res.start, resource_size(&pci->cfg.res), -- cgit v0.10.2 From dbf9826d57974c2b4e68928528a4a6c354ceddb3 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 23 Oct 2014 16:23:07 +0100 Subject: PCI: generic: Convert to DT resource parsing API In order to consolidate DT configuration for PCI host controllers in the kernel, a new API, of_pci_get_host_bridge_resources(), was developed to allow parsing and assigning IO/BUS/MEM resources from DT, removing duplicated code present in the majority of PCI host driver implementations. Convert the existing PCI generic host controller driver to the new API. Most of the code parsing ranges and creating resources is now delegated to the of_pci_get_host_bridge_resources() API. The PCI host controller code filters the resulting resource list and maps IO space by using the newly introduced pci_ioremap_iospace() API. New code supports only one IO resource per generic host controller, which should cater for all existing host controller configurations. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Will Deacon diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 1e1a80f..1895907 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -32,7 +32,7 @@ struct gen_pci_cfg_bus_ops { struct gen_pci_cfg_windows { struct resource res; - struct resource bus_range; + struct resource *bus_range; void __iomem **win; const struct gen_pci_cfg_bus_ops *ops; @@ -50,7 +50,7 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, { struct pci_sys_data *sys = bus->sysdata; struct gen_pci *pci = sys->private_data; - resource_size_t idx = bus->number - pci->cfg.bus_range.start; + resource_size_t idx = bus->number - pci->cfg.bus_range->start; return pci->cfg.win[idx] + ((devfn << 8) | where); } @@ -66,7 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, { struct pci_sys_data *sys = bus->sysdata; struct gen_pci *pci = sys->private_data; - resource_size_t idx = bus->number - pci->cfg.bus_range.start; + resource_size_t idx = bus->number - pci->cfg.bus_range->start; return pci->cfg.win[idx] + ((devfn << 12) | where); } @@ -138,106 +138,50 @@ static const struct of_device_id gen_pci_of_match[] = { }; MODULE_DEVICE_TABLE(of, gen_pci_of_match); -static int gen_pci_calc_io_offset(struct device *dev, - struct of_pci_range *range, - struct resource *res, - resource_size_t *offset) -{ - static atomic_t wins = ATOMIC_INIT(0); - int err, idx, max_win; - unsigned int window; - - if (!PAGE_ALIGNED(range->cpu_addr)) - return -EINVAL; - - max_win = (IO_SPACE_LIMIT + 1) / SZ_64K; - idx = atomic_inc_return(&wins); - if (idx > max_win) - return -ENOSPC; - - window = (idx - 1) * SZ_64K; - err = pci_ioremap_io(window, range->cpu_addr); - if (err) - return err; - - of_pci_range_to_resource(range, dev->of_node, res); - res->start = window; - res->end = res->start + range->size - 1; - *offset = window - range->pci_addr; - return 0; -} - -static int gen_pci_calc_mem_offset(struct device *dev, - struct of_pci_range *range, - struct resource *res, - resource_size_t *offset) -{ - of_pci_range_to_resource(range, dev->of_node, res); - *offset = range->cpu_addr - range->pci_addr; - return 0; -} - static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) { - struct pci_host_bridge_window *win; - - list_for_each_entry(win, &pci->resources, list) - release_resource(win->res); - pci_free_resource_list(&pci->resources); } static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) { - struct of_pci_range range; - struct of_pci_range_parser parser; int err, res_valid = 0; struct device *dev = pci->host.dev.parent; struct device_node *np = dev->of_node; + resource_size_t iobase; + struct pci_host_bridge_window *win; - if (of_pci_range_parser_init(&parser, np)) { - dev_err(dev, "missing \"ranges\" property\n"); - return -EINVAL; - } + err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, + &iobase); + if (err) + return err; - for_each_of_pci_range(&parser, &range) { - struct resource *parent, *res; - resource_size_t offset; - u32 restype = range.flags & IORESOURCE_TYPE_BITS; + list_for_each_entry(win, &pci->resources, list) { + struct resource *parent, *res = win->res; - res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL); - if (!res) { - err = -ENOMEM; - goto out_release_res; - } - - switch (restype) { + switch (resource_type(res)) { case IORESOURCE_IO: parent = &ioport_resource; - err = gen_pci_calc_io_offset(dev, &range, res, &offset); + err = pci_remap_iospace(res, iobase); + if (err) { + dev_warn(dev, "error %d: failed to map resource %pR\n", + err, res); + continue; + } break; case IORESOURCE_MEM: parent = &iomem_resource; - err = gen_pci_calc_mem_offset(dev, &range, res, &offset); - res_valid |= !(res->flags & IORESOURCE_PREFETCH || err); + res_valid |= !(res->flags & IORESOURCE_PREFETCH); break; + case IORESOURCE_BUS: + pci->cfg.bus_range = res; default: - err = -EINVAL; continue; } - if (err) { - dev_warn(dev, - "error %d: failed to add resource [type 0x%x, %lld bytes]\n", - err, restype, range.size); - continue; - } - - err = request_resource(parent, res); + err = devm_request_resource(dev, parent, res); if (err) goto out_release_res; - - pci_add_resource_offset(&pci->resources, res, offset); } if (!res_valid) { @@ -262,14 +206,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) struct device *dev = pci->host.dev.parent; struct device_node *np = dev->of_node; - if (of_pci_parse_bus_range(np, &pci->cfg.bus_range)) - pci->cfg.bus_range = (struct resource) { - .name = np->name, - .start = 0, - .end = 0xff, - .flags = IORESOURCE_BUS, - }; - err = of_address_to_resource(np, 0, &pci->cfg.res); if (err) { dev_err(dev, "missing \"reg\" property\n"); @@ -277,12 +213,12 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) } /* Limit the bus-range to fit within reg */ - bus_max = pci->cfg.bus_range.start + + bus_max = pci->cfg.bus_range->start + (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; - pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end, - bus_max); + pci->cfg.bus_range->end = min_t(resource_size_t, + pci->cfg.bus_range->end, bus_max); - pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), + pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), sizeof(*pci->cfg.win), GFP_KERNEL); if (!pci->cfg.win) return -ENOMEM; @@ -293,7 +229,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) "Configuration Space")) return -ENOMEM; - bus_range = &pci->cfg.bus_range; + bus_range = pci->cfg.bus_range; for (busn = bus_range->start; busn <= bus_range->end; ++busn) { u32 idx = busn - bus_range->start; u32 sz = 1 << pci->cfg.ops->bus_shift; @@ -305,8 +241,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) return -ENOMEM; } - /* Register bus resource */ - pci_add_resource(&pci->resources, bus_range); return 0; } -- cgit v0.10.2 From 23cf1d006f1a32cebf7ac6910ac6bcf41adfd702 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 6 Oct 2014 11:04:45 +0800 Subject: xen/pcifront: Process failure for pcifront_(re)scan_root() When pcifront_try_connect() finds no PCI roots, it falls back to calling pcifront_scan_root() for 0000:00. If that fails, it used to switch to XenbusStateConnected and return success (because xenbus_switch_state() currently always succeeds). If pcifront_scan_root() fails, leave the XenbusState unchanged and return an error code. Similarly, pcifront_attach_devices() falls back to calling pcifront_rescan_root() for 0000:00. If that fails, it used to switch to XenbusStateConnected and return an error code. If pcifront_rescan_root() fails, leave the XenbusState unchanged and return the error code. [bhelgaas: changelog] Signed-off-by: Chen Gang Signed-off-by: Bjorn Helgaas Reviewed-by: Konrad Rzeszutek Wilk diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 116ca37..9331650 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -866,6 +866,11 @@ static int pcifront_try_connect(struct pcifront_device *pdev) xenbus_dev_error(pdev->xdev, err, "No PCI Roots found, trying 0000:00"); err = pcifront_scan_root(pdev, 0, 0); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error scanning PCI root 0000:00"); + goto out; + } num_roots = 0; } else if (err != 1) { if (err == 0) @@ -947,6 +952,11 @@ static int pcifront_attach_devices(struct pcifront_device *pdev) xenbus_dev_error(pdev->xdev, err, "No PCI Roots found, trying 0000:00"); err = pcifront_rescan_root(pdev, 0, 0); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error scanning PCI root 0000:00"); + goto out; + } num_roots = 0; } else if (err != 1) { if (err == 0) -- cgit v0.10.2 From 63692df103e9c76b26c382ce8079283b7df9a99a Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 23 Oct 2014 14:22:12 -0400 Subject: PCI: Allow numa_node override via sysfs NUMA systems with ACPI normally describe the physical topology via _PXM methods. But many BIOSes don't implement _PXM, which leaves the kernel with no way to discover the device topology, which reduces performance because we can't put memory and processes close to the device. The NUMA node of a PCI device is already exported in the sysfs "numa_node" file. Make that file writable so users can workaround the lack of _PXM methods in the BIOS. For example: echo 3 > /sys/devices/pci0000:ff/0000:03:1f.3/numa_node sets the node for PCI device 0000:03:1f.3. Writing the file emits a FW_BUG warning to encourage users to request firmware updates. It also taints the kernel with TAINT_FIRMWARE_WORKAROUND because overriding the node incorrectly can cause performance issues. [bhelgaas: changelog, documentation text] Signed-off-by: Prarit Bhargava Signed-off-by: Bjorn Helgaas CC: Myron Stowe CC: Alexander Ducyk CC: Jiang Liu diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index ee6c040..b3bc50f 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -281,3 +281,16 @@ Description: opt-out of driver binding using a driver_override name such as "none". Only a single driver may be specified in the override, there is no support for parsing delimiters. + +What: /sys/bus/pci/devices/.../numa_node +Date: Oct 2014 +Contact: Prarit Bhargava +Description: + This file contains the NUMA node to which the PCI device is + attached, or -1 if the node is unknown. The initial value + comes from an ACPI _PXM method or a similar firmware + source. If that is missing or incorrect, this file can be + written to override the node. In that case, please report + a firmware bug to the system vendor. Writing to this file + taints the kernel with TAINT_FIRMWARE_WORKAROUND, which + reduces the supportability of your system. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 92b6d9a..91e760f 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -221,12 +221,37 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(enabled); #ifdef CONFIG_NUMA +static ssize_t numa_node_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int node, ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = kstrtoint(buf, 0, &node); + if (ret) + return ret; + + if (!node_online(node)) + return -EINVAL; + + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); + dev_alert(&pdev->dev, FW_BUG "Overriding NUMA node to %d. Contact your vendor for updates.", + node); + + dev->numa_node = node; + return count; +} + static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", dev->numa_node); } -static DEVICE_ATTR_RO(numa_node); +static DEVICE_ATTR_RW(numa_node); #endif static ssize_t dma_mask_bits_show(struct device *dev, -- cgit v0.10.2 From 36e8164882ca6d3c41cb91e6f09a3ed236841f80 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Thu, 30 Oct 2014 11:54:37 -0600 Subject: PCI: Restore detection of read-only BARs Commit 6ac665c63dca ("PCI: rewrite PCI BAR reading code") masked off low-order bits from 'l', but not from 'sz'. Both are passed to pci_size(), which compares 'base == maxbase' to check for read-only BARs. The masking of 'l' means that comparison will never be 'true', so the check for read-only BARs no longer works. Resolve this by also masking off the low-order bits of 'sz' before passing it into pci_size() as 'maxbase'. With this change, pci_size() will once again catch the problems that have been encountered to date: - AGP aperture BAR of AMD-7xx host bridges: if the AGP window is disabled, this BAR is read-only and read as 0x00000008 [1] - BARs 0-4 of ALi IDE controllers can be non-zero and read-only [1] - Intel Sandy Bridge - Thermal Management Controller [8086:0103]; BAR 0 returning 0xfed98004 [2] - Intel Xeon E5 v3/Core i7 Power Control Unit [8086:2fc0]; Bar 0 returning 0x00001a [3] Link: [1] https://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/drivers/pci/probe.c?id=1307ef6621991f1c4bc3cec1b5a4ebd6fd3d66b9 ("PCI: probing read-only BARs" (pre-git)) Link: [2] https://bugzilla.kernel.org/show_bug.cgi?id=43331 Link: [3] https://bugzilla.kernel.org/show_bug.cgi?id=85991 Reported-by: William Unruh Reported-by: Martin Lucina Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox CC: stable@vger.kernel.org # v2.6.27+ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5ed9930..19dc247 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -216,14 +216,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= IORESOURCE_SIZEALIGN; if (res->flags & IORESOURCE_IO) { l &= PCI_BASE_ADDRESS_IO_MASK; + sz &= PCI_BASE_ADDRESS_IO_MASK; mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; } else { l &= PCI_BASE_ADDRESS_MEM_MASK; + sz &= PCI_BASE_ADDRESS_MEM_MASK; mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; } } else { res->flags |= (l & IORESOURCE_ROM_ENABLE); l &= PCI_ROM_ADDRESS_MASK; + sz &= PCI_ROM_ADDRESS_MASK; mask = (u32)PCI_ROM_ADDRESS_MASK; } -- cgit v0.10.2 From f795d86aaa578501551a2d1b463eac4bbea84db2 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Thu, 30 Oct 2014 11:54:43 -0600 Subject: PCI: Shrink decoding-disabled window while sizing BARs __pci_read_base() disables decoding while sizing device BARs. We can't print while decoding is disabled, which leads to some rather messy exit logic. Coalesce the sizing logic to minimize the time decoding is disabled. This lets us print errors where they're detected. The refactoring also takes advantage of the symmetry of obtaining the BAR's extent (pci_size) and storing the result as the 'region' for both the 32-bit and 64-bit BARs, consolidating both cases. No functional change intended. [bhelgaas: move pci_size() up, per Thomas Petazzoni, Thierry Reding, Kevin Hilman] Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 19dc247..529fcd7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -175,7 +175,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, u64 l64, sz64, mask64; u16 orig_cmd; struct pci_bus_region region, inverted_region; - bool bar_too_big = false, bar_too_high = false, bar_invalid = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -201,8 +200,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit * 1 must be clear. */ - if (!sz || sz == 0xffffffff) - goto fail; + if (sz == 0xffffffff) + sz = 0; /* * I don't know how l can have all bits set. Copied from old code. @@ -215,26 +214,22 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags = decode_bar(dev, l); res->flags |= IORESOURCE_SIZEALIGN; if (res->flags & IORESOURCE_IO) { - l &= PCI_BASE_ADDRESS_IO_MASK; - sz &= PCI_BASE_ADDRESS_IO_MASK; - mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; + l64 = l & PCI_BASE_ADDRESS_IO_MASK; + sz64 = sz & PCI_BASE_ADDRESS_IO_MASK; + mask64 = PCI_BASE_ADDRESS_IO_MASK & (u32)IO_SPACE_LIMIT; } else { - l &= PCI_BASE_ADDRESS_MEM_MASK; - sz &= PCI_BASE_ADDRESS_MEM_MASK; - mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + l64 = l & PCI_BASE_ADDRESS_MEM_MASK; + sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; + mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; } } else { res->flags |= (l & IORESOURCE_ROM_ENABLE); - l &= PCI_ROM_ADDRESS_MASK; - sz &= PCI_ROM_ADDRESS_MASK; - mask = (u32)PCI_ROM_ADDRESS_MASK; + l64 = l & PCI_ROM_ADDRESS_MASK; + sz64 = sz & PCI_ROM_ADDRESS_MASK; + mask64 = (u32)PCI_ROM_ADDRESS_MASK; } if (res->flags & IORESOURCE_MEM_64) { - l64 = l; - sz64 = sz; - mask64 = mask | (u64)~0 << 32; - pci_read_config_dword(dev, pos + 4, &l); pci_write_config_dword(dev, pos + 4, ~0); pci_read_config_dword(dev, pos + 4, &sz); @@ -242,18 +237,27 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, l64 |= ((u64)l << 32); sz64 |= ((u64)sz << 32); + mask64 |= ((u64)~0 << 32); + } - sz64 = pci_size(l64, sz64, mask64); + if (!dev->mmio_always_on && (orig_cmd & PCI_COMMAND_DECODE_ENABLE)) + pci_write_config_word(dev, PCI_COMMAND, orig_cmd); - if (!sz64) - goto fail; + if (!sz64) + goto fail; + + sz64 = pci_size(l64, sz64, mask64); + if (!sz64) + goto fail; + if (res->flags & IORESOURCE_MEM_64) { if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && sz64 > 0x100000000ULL) { res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; res->start = 0; res->end = 0; - bar_too_big = true; + dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", + pos, (unsigned long long)sz64); goto out; } @@ -262,22 +266,15 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= IORESOURCE_UNSET; res->start = 0; res->end = sz64; - bar_too_high = true; + dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n", + pos, (unsigned long long)l64); goto out; - } else { - region.start = l64; - region.end = l64 + sz64; } - } else { - sz = pci_size(l, sz, mask); - - if (!sz) - goto fail; - - region.start = l; - region.end = l + sz; } + region.start = l64; + region.end = l64 + sz64; + pcibios_bus_to_resource(dev->bus, res, ®ion); pcibios_resource_to_bus(dev->bus, &inverted_region, res); @@ -296,7 +293,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= IORESOURCE_UNSET; res->start = 0; res->end = region.end - region.start; - bar_invalid = true; + dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", + pos, (unsigned long long)region.start); } goto out; @@ -305,19 +303,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, fail: res->flags = 0; out: - if (!dev->mmio_always_on && - (orig_cmd & PCI_COMMAND_DECODE_ENABLE)) - pci_write_config_word(dev, PCI_COMMAND, orig_cmd); - - if (bar_too_big) - dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", - pos, (unsigned long long) sz64); - if (bar_too_high) - dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4G (bus address %#010llx)\n", - pos, (unsigned long long) l64); - if (bar_invalid) - dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", - pos, (unsigned long long) region.start); if (res->flags) dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); -- cgit v0.10.2 From ff0387c3777f2438bad2088abe442c9f231b0be4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 10 Nov 2014 21:02:17 -0700 Subject: PCI: Delete unnecessary NULL pointer checks The functions pci_dev_put(), pci_pme_wakeup_bus(), and put_device() return immediately if their argument is NULL. Thus the test before the call is not needed. Remove these unnecessary tests. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6ebf8ed..3542150 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -322,8 +322,7 @@ static void pci_acpi_wake_dev(struct work_struct *work) pci_wakeup_event(pci_dev); pm_runtime_resume(&pci_dev->dev); - if (pci_dev->subordinate) - pci_pme_wakeup_bus(pci_dev->subordinate); + pci_pme_wakeup_bus(pci_dev->subordinate); } /** diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5ed9930..eb927c0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -87,8 +87,7 @@ static void release_pcibus_dev(struct device *dev) { struct pci_bus *pci_bus = to_pci_bus(dev); - if (pci_bus->bridge) - put_device(pci_bus->bridge); + put_device(pci_bus->bridge); pci_bus_remove_resources(pci_bus); pci_release_bus_of_node(pci_bus); kfree(pci_bus); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a81f413..a20ce7d 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -271,8 +271,7 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id, match_pci_dev_by_id); if (dev) pdev = to_pci_dev(dev); - if (from) - pci_dev_put(from); + pci_dev_put(from); return pdev; } diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 116ca37..f01b26d 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -596,8 +596,7 @@ static pci_ers_result_t pcifront_common_process(int cmd, pcidev = pci_get_bus_and_slot(bus, devfn); if (!pcidev || !pcidev->driver) { dev_err(&pdev->xdev->dev, "device or AER driver is NULL\n"); - if (pcidev) - pci_dev_put(pcidev); + pci_dev_put(pcidev); return result; } pdrv = pcidev->driver; -- cgit v0.10.2 From 754834b9caae8d1380f66a5f0337547e9361094d Mon Sep 17 00:00:00 2001 From: Quentin Lambert Date: Thu, 6 Nov 2014 17:45:55 +0100 Subject: PCI: Simplify if-return sequences Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci Signed-off-by: Quentin Lambert Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c index 219ba80..f279060 100644 --- a/drivers/pci/hotplug/ibmphp_res.c +++ b/drivers/pci/hotplug/ibmphp_res.c @@ -376,10 +376,7 @@ int __init ibmphp_rsrc_init (void) if (rc) return rc; } - rc = once_over (); /* This is to align ranges (so no -1) */ - if (rc) - return rc; - return 0; + return once_over (); /* This is to align ranges (so no -1) */ } /******************************************************************************** diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 625a4ac..9a5871f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1012,11 +1012,7 @@ int pci_save_state(struct pci_dev *dev) if (i != 0) return i; - i = pci_save_vc_state(dev); - if (i != 0) - return i; - - return 0; + return pci_save_vc_state(dev); } EXPORT_SYMBOL(pci_save_state); -- cgit v0.10.2 From 62d0ff83c6e2221662fa0dccf2de096bdc7a2fc4 Mon Sep 17 00:00:00 2001 From: Minghuan Lian Date: Wed, 5 Nov 2014 16:45:11 +0800 Subject: PCI: layerscape: Add Freescale Layerscape PCIe driver Add support for Freescale Layerscape PCIe controller. This driver re-uses the Synopsis DesignWare core code. [bhelgaas: add Kconfig dependency on CONFIG_ARM] Signed-off-by: Minghuan Lian Signed-off-by: Bjorn Helgaas Acked-by: Arnd Bergmann diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt new file mode 100644 index 0000000..6286f04 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -0,0 +1,42 @@ +Freescale Layerscape PCIe controller + +This PCIe host controller is based on the Synopsis Designware PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: should contain the platform identifier such as "fsl,ls1021a-pcie" +- reg: base addresses and lengths of the PCIe controller +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The interrupt that is asserted for controller interrupts +- fsl,pcie-scfg: Must include two entries. + The first entry must be a link to the SCFG device node + The second entry must be '0' or '1' based on physical PCIe controller index. + This is used to get SCFG PEXN registers + +Example: + + pcie@3400000 { + compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = ; /* controller interrupt */ + interrupt-names = "intr"; + fsl,pcie-scfg = <&scfg 0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0xc2000000 0x0 0x20000000 0x40 0x20000000 0x0 0x20000000 /* prefetchable memory */ + 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a20df9b..016e1ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6983,6 +6983,16 @@ S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci.txt F: drivers/pci/host/pci-xgene.c +PCI DRIVER FOR FREESCALE LAYERSCAPE +M: Minghuan Lian +M: Mingkai Hu +M: Roy Zang +L: linuxppc-dev@lists.ozlabs.org +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: drivers/pci/host/*layerscape* + PCI DRIVER FOR IMX6 M: Richard Zhu M: Lucas Stach diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 3dc25fa..67e2cc5 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -91,4 +91,12 @@ config PCI_XGENE There are 5 internal PCIe ports available. Each port is GEN3 capable and have varied lanes from x1 to x8. +config PCI_LAYERSCAPE + bool "Freescale Layerscape PCIe controller" + depends on OF && ARM + select PCIE_DW + select MFD_SYSCON + help + Say Y here if you want PCIe controller support on Layerscape SoCs. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 26b3461..44c2699 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCI_XGENE) += pci-xgene.o +obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c new file mode 100644 index 0000000..6697b1a --- /dev/null +++ b/drivers/pci/host/pci-layerscape.c @@ -0,0 +1,179 @@ +/* + * PCIe host controller driver for Freescale Layerscape SoCs + * + * Copyright (C) 2014 Freescale Semiconductor. + * + * Author: Minghuan Lian + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-designware.h" + +/* PEX1/2 Misc Ports Status Register */ +#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) +#define LTSSM_STATE_SHIFT 20 +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +/* Symbol Timer Register and Filter Mask Register 1 */ +#define PCIE_STRFMR1 0x71c + +struct ls_pcie { + struct list_head node; + struct device *dev; + struct pci_bus *bus; + void __iomem *dbi; + struct regmap *scfg; + struct pcie_port pp; + int index; + int msi_irq; +}; + +#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) + +static int ls_pcie_link_up(struct pcie_port *pp) +{ + u32 state; + struct ls_pcie *pcie = to_ls_pcie(pp); + + regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state); + state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; + + if (state < LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static void ls_pcie_host_init(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int count = 0; + u32 val; + + dw_pcie_setup_rc(pp); + + while (!ls_pcie_link_up(pp)) { + usleep_range(100, 1000); + count++; + if (count >= 200) { + dev_err(pp->dev, "phy link never came up\n"); + return; + } + } + + /* + * LS1021A Workaround for internal TKT228622 + * to fix the INTx hang issue + */ + val = ioread32(pcie->dbi + PCIE_STRFMR1); + val &= 0xffff; + iowrite32(val, pcie->dbi + PCIE_STRFMR1); +} + +static struct pcie_host_ops ls_pcie_host_ops = { + .link_up = ls_pcie_link_up, + .host_init = ls_pcie_host_init, +}; + +static int ls_add_pcie_port(struct ls_pcie *pcie) +{ + struct pcie_port *pp; + int ret; + + pp = &pcie->pp; + pp->dev = pcie->dev; + pp->dbi_base = pcie->dbi; + pp->root_bus_nr = -1; + pp->ops = &ls_pcie_host_ops; + + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(pp->dev, "failed to initialize host\n"); + return ret; + } + + return 0; +} + +static int __init ls_pcie_probe(struct platform_device *pdev) +{ + struct ls_pcie *pcie; + struct resource *dbi_base; + u32 index[2]; + int ret; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; + + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!dbi_base) { + dev_err(&pdev->dev, "missing *regs* space\n"); + return -ENODEV; + } + + pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); + if (IS_ERR(pcie->dbi)) + return PTR_ERR(pcie->dbi); + + pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "fsl,pcie-scfg"); + if (IS_ERR(pcie->scfg)) { + dev_err(&pdev->dev, "No syscfg phandle specified\n"); + return PTR_ERR(pcie->scfg); + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "fsl,pcie-scfg", index, 2); + if (ret) + return ret; + pcie->index = index[1]; + + ret = ls_add_pcie_port(pcie); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, pcie); + + return 0; +} + +static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls1021a-pcie" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ls_pcie_of_match); + +static struct platform_driver ls_pcie_driver = { + .driver = { + .name = "layerscape-pcie", + .owner = THIS_MODULE, + .of_match_table = ls_pcie_of_match, + }, +}; + +module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe); + +MODULE_AUTHOR("Minghuan Lian "); +MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 23926c8dbd6fdca3da884fa6c2daa0d6a3cbddec Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Nov 2014 14:30:49 +0900 Subject: PCI: dra7xx: Rename add_pcie_port() to dra7xx_add_pcie_port() The add_pcie_port() function is dra7xx-specific. Add dra7xx prefix to avoid collision in global name space. Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Kishon Vijay Abraham I diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 52b34fe..5b4a644 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -270,8 +270,8 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static int add_pcie_port(struct dra7xx_pcie *dra7xx, - struct platform_device *pdev) +static int dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, + struct platform_device *pdev) { int ret; struct pcie_port *pp; @@ -398,7 +398,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dra7xx); - ret = add_pcie_port(dra7xx, pdev); + ret = dra7xx_add_pcie_port(dra7xx, pdev); if (ret < 0) goto err_add_port; -- cgit v0.10.2 From a9875d83a0ae57a18f9c9f70c2ac524b81cc2cbe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Nov 2014 10:29:41 +0900 Subject: PCI: spear: Rename add_pcie_port(), pcie_init() to spear13xx_add_pcie_port(), etc. The add_pcie_port() and pcie_init() functions are SPEAr13xx-specific. Add spear13xx prefix to avoid collision in global name space. Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Viresh Kumar diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 85f594e..63f869f 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -269,7 +269,8 @@ static struct pcie_host_ops spear13xx_pcie_host_ops = { .host_init = spear13xx_pcie_host_init, }; -static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) +static int spear13xx_add_pcie_port(struct pcie_port *pp, + struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret; @@ -352,7 +353,7 @@ static int __init spear13xx_pcie_probe(struct platform_device *pdev) if (of_property_read_bool(np, "st,pcie-is-gen1")) spear13xx_pcie->is_gen1 = true; - ret = add_pcie_port(pp, pdev); + ret = spear13xx_add_pcie_port(pp, pdev); if (ret < 0) goto fail_clk; @@ -382,11 +383,11 @@ static struct platform_driver spear13xx_pcie_driver __initdata = { /* SPEAr13xx PCIe driver does not allow module unload */ -static int __init pcie_init(void) +static int __init spear13xx_pcie_init(void) { return platform_driver_register(&spear13xx_pcie_driver); } -module_init(pcie_init); +module_init(spear13xx_pcie_init); MODULE_DESCRIPTION("ST Microelectronics SPEAr13xx PCIe host controller driver"); MODULE_AUTHOR("Pratyush Anand "); -- cgit v0.10.2 From 992e7bd2be1817d6327febebcfff7ab836a3306c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Nov 2014 14:38:18 +0900 Subject: PCI: spear: Add __init annotation to spear13xx_add_pcie_port() Add __init annotation to spear13xx_add_pcie_port(), because spear13xx_add_pcie_port() is called only by spear13xx_pcie_probe(), which is marked __init. This fixes a section mismatch warning: WARNING: drivers/pci/host/built-in.o(.text.unlikely+0x94): Section mismatch in reference from the function spear13xx_add_pcie_port() to the function .init.text:dw_pcie_host_init() Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Viresh Kumar diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 63f869f..60f43cd 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -269,8 +269,8 @@ static struct pcie_host_ops spear13xx_pcie_host_ops = { .host_init = spear13xx_pcie_host_init, }; -static int spear13xx_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int __init spear13xx_add_pcie_port(struct pcie_port *pp, + struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret; -- cgit v0.10.2 From e73044a069c40b8c49c75f1869a07bd912801494 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 6 Nov 2014 14:37:39 +0900 Subject: PCI: dra7xx: Add __init annotation to dra7xx_add_pcie_port() Add __init annotation to dra7xx_add_pcie_port(), because dra7xx_add_pcie_port() is called only by dra7xx_pcie_probe() which is marked __init. This patch fixes a section mismatch warning: WARNING: drivers/pci/host/built-in.o(.text.unlikely+0xcc): Section mismatch in reference from the function dra7xx_add_pcie_port() to the function .init.text:dw_pcie_host_init() Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 5b4a644..8c69697 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -270,8 +270,8 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static int dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, - struct platform_device *pdev) +static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, + struct platform_device *pdev) { int ret; struct pcie_port *pp; -- cgit v0.10.2 From bb383e283b2c2dca8eb5152a1a2477efcc469431 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 12 Nov 2014 13:41:51 +1100 Subject: PCI: Make FLR and AF FLR reset warning messages different We have same warning message for FLR and AF FLR and users can't know which type of resets the PCI device is taking when there are pending transactions. Print different messages for FLR and AF FLR cases. [bhelgaas: make code structure parallel, add "anyway" to suggest risk] Signed-off-by: Gavin Shan Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9a5871f..e8b3627 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3140,12 +3140,10 @@ static int pcie_flr(struct pci_dev *dev, int probe) return 0; if (!pci_wait_for_pending_transaction(dev)) - dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n"); + dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n"); pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); - msleep(100); - return 0; } @@ -3170,16 +3168,12 @@ static int pci_af_flr(struct pci_dev *dev, int probe) * is used, so we use the conrol offset rather than status and shift * the test bit to match. */ - if (pci_wait_for_pending(dev, pos + PCI_AF_CTRL, + if (!pci_wait_for_pending(dev, pos + PCI_AF_CTRL, PCI_AF_STATUS_TP << 8)) - goto clear; + dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n"); - dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n"); - -clear: pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); msleep(100); - return 0; } -- cgit v0.10.2 From a4acded086c4320bc58bd59ea746fd19de6dabb0 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 12 Nov 2014 13:43:52 +1100 Subject: PCI: Remove unused and broken to_hotplug_slot() to_hotplug_slot() is unused and wouldn't work anyway, because struct hotplug_slot no longer contains a struct kobject (it was removed by f46753c5e354 ("PCI: introduce pci_slot")). Remove to_hotplug_slot(). [bhelgaas: changelog] Signed-off-by: Gavin Shan Signed-off-by: Bjorn Helgaas diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 2706ee9..8c78950 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -109,7 +109,6 @@ struct hotplug_slot { struct list_head slot_list; struct pci_slot *pci_slot; }; -#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) { -- cgit v0.10.2 From 6670070742991c69e02dde38c611a6c31ce8f30b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:22:56 +0900 Subject: PCI: keystone: Remove unnecessary OOM message The site-specific OOM messages are unnecessary because they duplicate the MM subsystem generic OOM message. This patch fixes the following checkpatch warning: WARNING: Possible unnecessary 'out of memory' message Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 1b893bc..62b9454 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -353,10 +353,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie), GFP_KERNEL); - if (!ks_pcie) { - dev_err(dev, "no memory for keystone pcie\n"); + if (!ks_pcie) return -ENOMEM; - } + pp = &ks_pcie->pp; /* initialize SerDes Phy if present */ -- cgit v0.10.2 From d88a7ef99e4c15985e0d726d4a4e4c1f0e4f0ad5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:25:09 +0900 Subject: PCI: imx6: Use tabs for indentation This patch fixes the following checkpatch error: ERROR: code indent should use tabs where possible Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 233fe8a..8a7530b 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -526,8 +526,8 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, } ret = devm_request_irq(&pdev->dev, pp->msi_irq, - imx6_pcie_msi_handler, - IRQF_SHARED, "mx6-pcie-msi", pp); + imx6_pcie_msi_handler, + IRQF_SHARED, "mx6-pcie-msi", pp); if (ret) { dev_err(&pdev->dev, "failed to request MSI irq\n"); return -ENODEV; -- cgit v0.10.2 From bc512c5a8c78db6904de7275bce54ce5b1433893 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:25:38 +0900 Subject: PCI: exynos: Remove unnecessary return statement This patch fixes the following checkpatch warning: WARNING: void function return statements are not generally useful Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 902d7cd..850c9f9 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -312,7 +312,6 @@ static void exynos_pcie_assert_reset(struct pcie_port *pp) if (exynos_pcie->reset_gpio >= 0) devm_gpio_request_one(pp->dev, exynos_pcie->reset_gpio, GPIOF_OUT_INIT_HIGH, "RESET"); - return; } static int exynos_pcie_establish_link(struct pcie_port *pp) @@ -388,7 +387,6 @@ static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_PULSE); exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_PULSE); - return; } static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) @@ -400,7 +398,6 @@ static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | IRQ_INTC_ASSERT | IRQ_INTD_ASSERT, exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_PULSE); - return; } static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) @@ -429,7 +426,6 @@ static void exynos_pcie_msi_init(struct pcie_port *pp) val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL); val |= IRQ_MSI_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL); - return; } static void exynos_pcie_enable_interrupts(struct pcie_port *pp) @@ -438,8 +434,6 @@ static void exynos_pcie_enable_interrupts(struct pcie_port *pp) if (IS_ENABLED(CONFIG_PCI_MSI)) exynos_pcie_msi_init(pp); - - return; } static inline void exynos_pcie_readl_rc(struct pcie_port *pp, @@ -448,7 +442,6 @@ static inline void exynos_pcie_readl_rc(struct pcie_port *pp, exynos_pcie_sideband_dbi_r_mode(pp, true); *val = readl(dbi_base); exynos_pcie_sideband_dbi_r_mode(pp, false); - return; } static inline void exynos_pcie_writel_rc(struct pcie_port *pp, @@ -457,7 +450,6 @@ static inline void exynos_pcie_writel_rc(struct pcie_port *pp, exynos_pcie_sideband_dbi_w_mode(pp, true); writel(val, dbi_base); exynos_pcie_sideband_dbi_w_mode(pp, false); - return; } static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, -- cgit v0.10.2 From 2c992f3779e699a0f03dbfa39fcd96efee422bbe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:27:04 +0900 Subject: PCI: designware: Add a blank line after declarations This patch fixes the following checkpatch warning: WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index dfed00a..f9be371 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -380,6 +380,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp) /* Get the I/O and memory ranges from DT */ for_each_of_pci_range(&parser, &range) { unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; + if (restype == IORESOURCE_IO) { of_pci_range_to_resource(&range, np, &pp->io); pp->io.name = "I/O"; -- cgit v0.10.2 From cf3a9d6bae51e3ff14196a4684c47c234fc34c27 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:27:54 +0900 Subject: PCI: mvebu: Add a blank line after declarations This patch fixes the following checkpatch warning: WARNING: Missing a blank line after declarations [bhelgaas: drop mvebu_pcie_add_bus() change because it's going away anyway] Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index b1315e1..e45f88e 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -622,6 +622,7 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, for (i = 0; i < pcie->nports; i++) { struct mvebu_pcie_port *port = &pcie->ports[i]; + if (bus->number == 0 && port->devfn == devfn) return port; if (bus->number != 0 && @@ -751,6 +752,7 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) for (i = 0; i < pcie->nports; i++) { struct mvebu_pcie_port *port = &pcie->ports[i]; + if (!port->base) continue; mvebu_pcie_setup_hw(port); -- cgit v0.10.2 From 20f9ece101d8793331f61a234cef3ee000891085 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Nov 2014 12:29:02 +0900 Subject: PCI: spear: Remove unnecessary OOM message The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. This patch fixes the following checkpatch warning: WARNING: Possible unnecessary 'out of memory' message Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas Acked-by: Viresh Kumar diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 60f43cd..2ca10cc 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -309,10 +309,8 @@ static int __init spear13xx_pcie_probe(struct platform_device *pdev) int ret; spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL); - if (!spear13xx_pcie) { - dev_err(dev, "no memory for SPEAr13xx pcie\n"); + if (!spear13xx_pcie) return -ENOMEM; - } spear13xx_pcie->phy = devm_phy_get(dev, "pcie-phy"); if (IS_ERR(spear13xx_pcie->phy)) { -- cgit v0.10.2 From 4407308b73a33dadfc72e5754f5bba5d5dec206f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 12 Nov 2014 14:53:37 +0100 Subject: PCI: tegra: Do not build on 64-bit ARM 32-bit and 64-bit ARM use very different infrastructure to register a PCI host bridge. The Tegra PCIe host controller driver currently only supports the 32-bit ARM infrastructure, so prevent it from being built on 64-bit ARM where it will break. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 3dc25fa..9c56137 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -32,7 +32,7 @@ config PCI_IMX6 config PCI_TEGRA bool "NVIDIA Tegra PCIe controller" - depends on ARCH_TEGRA + depends on ARCH_TEGRA && !ARM64 config PCI_RCAR_GEN2 bool "Renesas R-Car Gen2 Internal PCI controller" -- cgit v0.10.2 From 6b1c4d7674edd213295befb9e007edd6aea857ff Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 12 Nov 2014 14:53:38 +0100 Subject: PCI: tegra: Add Kconfig help text Add a standard help text to the Kconfig entry for the Tegra PCIe host controller driver. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 9c56137..9dbb1fc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -33,6 +33,9 @@ config PCI_IMX6 config PCI_TEGRA bool "NVIDIA Tegra PCIe controller" depends on ARCH_TEGRA && !ARM64 + help + Say Y here if you want support for the PCIe host controller found + on NVIDIA Tegra SoCs. config PCI_RCAR_GEN2 bool "Renesas R-Car Gen2 Internal PCI controller" -- cgit v0.10.2 From 7e79c5f8cad2ac1dc26c03e1aa16216391a04dad Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Thu, 30 Oct 2014 11:54:50 -0600 Subject: PCI: Add informational printk for invalid BARs As a consequence of restoring the detection of invalid BARs, add a new informational printk like the following when such occurrences are encountered. pci ssss:bb:dd.f: [Firmware Bug]: reg 0xXX: invalid BAR (can't size) Reported-by: William Unruh Reported-by: Martin Lucina Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 529fcd7..6029ad7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -247,8 +247,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto fail; sz64 = pci_size(l64, sz64, mask64); - if (!sz64) + if (!sz64) { + dev_info(&dev->dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n", + pos); goto fail; + } if (res->flags & IORESOURCE_MEM_64) { if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && -- cgit v0.10.2 From 26ff46c6f23bb1497aaa1364a5c73a109493b653 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Tue, 11 Nov 2014 08:04:50 -0700 Subject: PCI: Remove fixed parameter in pci_iov_resource_bar() pci_iov_resource_bar() always sets its 'pci_bar_type' parameter to 'pci_bar_unknown'. Drop the parameter and just use 'pci_bar_unknown' directly in the callers. No functional change intended. Signed-off-by: Myron Stowe Signed-off-by: Bjorn Helgaas CC: Chris Wright CC: Yu Zhao diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 4d109c0..4b3a4ea 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -479,20 +479,16 @@ void pci_iov_release(struct pci_dev *dev) * pci_iov_resource_bar - get position of the SR-IOV BAR * @dev: the PCI device * @resno: the resource number - * @type: the BAR type to be filled in * * Returns position of the BAR encapsulated in the SR-IOV capability. */ -int pci_iov_resource_bar(struct pci_dev *dev, int resno, - enum pci_bar_type *type) +int pci_iov_resource_bar(struct pci_dev *dev, int resno) { if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END) return 0; BUG_ON(!dev->is_physfn); - *type = pci_bar_unknown; - return dev->sriov->pos + PCI_SRIOV_BAR + 4 * (resno - PCI_IOV_RESOURCES); } @@ -510,13 +506,12 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno, resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) { struct resource tmp; - enum pci_bar_type type; - int reg = pci_iov_resource_bar(dev, resno, &type); + int reg = pci_iov_resource_bar(dev, resno); if (!reg) return 0; - __pci_read_base(dev, type, &tmp, reg); + __pci_read_base(dev, pci_bar_unknown, &tmp, reg); return resource_alignment(&tmp); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 625a4ac..7bf2465 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4180,7 +4180,8 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) return dev->rom_base_reg; } else if (resno < PCI_BRIDGE_RESOURCES) { /* device specific resource */ - reg = pci_iov_resource_bar(dev, resno, type); + *type = pci_bar_unknown; + reg = pci_iov_resource_bar(dev, resno); if (reg) return reg; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 0601890..a0905a0 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -251,8 +251,7 @@ static inline void pci_restore_ats_state(struct pci_dev *dev) #ifdef CONFIG_PCI_IOV int pci_iov_init(struct pci_dev *dev); void pci_iov_release(struct pci_dev *dev); -int pci_iov_resource_bar(struct pci_dev *dev, int resno, - enum pci_bar_type *type); +int pci_iov_resource_bar(struct pci_dev *dev, int resno); resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno); void pci_restore_iov_state(struct pci_dev *dev); int pci_iov_bus_range(struct pci_bus *bus); @@ -266,8 +265,7 @@ static inline void pci_iov_release(struct pci_dev *dev) { } -static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno, - enum pci_bar_type *type) +static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno) { return 0; } -- cgit v0.10.2