diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index ee6c04036492..b3bc50f650ee 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/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c index 219ba8090a37..f279060cf6e2 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/iov.c b/drivers/pci/iov.c index 4d109c07294a..4b3a4eaad996 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-acpi.c b/drivers/pci/pci-acpi.c index 6ebf8edc5f3c..3542150fc8a3 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/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 92b6d9ab00e4..91e760f9655b 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, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 625a4ace10b4..a7ac72639c52 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); @@ -3144,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; } @@ -3174,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; } @@ -4180,7 +4170,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 0601890db22d..a0905a0985ce 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; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5ed99309c758..a9e34ca119e1 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); @@ -175,7 +174,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 +199,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,23 +213,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; - 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; - 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; - 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); @@ -239,18 +236,30 @@ 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) { + 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) && 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; } @@ -259,22 +268,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); @@ -293,7 +295,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; @@ -302,19 +305,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); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a81f413083e4..a20ce7d5e2a7 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 116ca3746adb..b1ffebec9b9e 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; @@ -866,6 +865,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 +951,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) diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 2706ee9a4327..8c7895061121 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) {