diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/ioapic.c | 13 | ||||
-rw-r--r-- | drivers/pci/iov.c | 5 | ||||
-rw-r--r-- | drivers/pci/msi.c | 10 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 4 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 48 | ||||
-rw-r--r-- | drivers/pci/pci.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 29 | ||||
-rw-r--r-- | drivers/pci/probe.c | 31 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 27 |
9 files changed, 125 insertions, 44 deletions
diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 3c6bbdd059a4..1b90579b233a 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -113,17 +113,6 @@ static struct pci_driver ioapic_driver = { .remove = ioapic_remove, }; -static int __init ioapic_init(void) -{ - return pci_register_driver(&ioapic_driver); -} - -static void __exit ioapic_exit(void) -{ - pci_unregister_driver(&ioapic_driver); -} - -module_init(ioapic_init); -module_exit(ioapic_exit); +module_pci_driver(ioapic_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c93071d428f5..a971a6f6268d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -92,6 +92,8 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); pci_setup_device(virtfn); virtfn->dev.parent = dev->dev.parent; + virtfn->physfn = pci_dev_get(dev); + virtfn->is_virtfn = 1; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { res = dev->resource + PCI_IOV_RESOURCES + i; @@ -113,9 +115,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - virtfn->physfn = pci_dev_get(dev); - virtfn->is_virtfn = 1; - rc = pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2c1075213bec..aca7578b05e5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -81,7 +81,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev) int i, nvec; if (entry->irq == 0) continue; - nvec = 1 << entry->msi_attrib.multiple; + if (entry->nvec_used) + nvec = entry->nvec_used; + else + nvec = 1 << entry->msi_attrib.multiple; for (i = 0; i < nvec; i++) arch_teardown_msi_irq(entry->irq + i); } @@ -336,7 +339,10 @@ static void free_msi_irqs(struct pci_dev *dev) int i, nvec; if (!entry->irq) continue; - nvec = 1 << entry->msi_attrib.multiple; + if (entry->nvec_used) + nvec = entry->nvec_used; + else + nvec = 1 << entry->msi_attrib.multiple; #ifdef CONFIG_GENERIC_HARDIRQS for (i = 0; i < nvec; i++) BUG_ON(irq_has_action(entry->irq + i)); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e4b1fb2c0f5d..6c15d6a96935 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -376,12 +376,12 @@ static int __init acpi_pci_init(void) int ret; if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) { - printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); + pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n"); pci_no_msi(); } if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { - printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); + pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); pcie_no_aspm(); } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5b4a9d9cd200..c0dbe1f61362 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -66,7 +66,7 @@ static ssize_t broken_parity_status_store(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; pdev->broken_parity_status = !!val; @@ -188,7 +188,7 @@ static ssize_t is_enabled_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = strict_strtoul(buf, 0, &val); + ssize_t result = kstrtoul(buf, 0, &val); if (result < 0) return result; @@ -259,7 +259,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; /* bad things may happen if the no_msi flag is changed @@ -291,7 +291,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, unsigned long val; struct pci_bus *b = NULL; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -315,7 +315,7 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, unsigned long val; struct pci_dev *pdev = to_pci_dev(dev); - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -325,6 +325,8 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, } return count; } +struct device_attribute dev_rescan_attr = __ATTR(rescan, (S_IWUSR|S_IWGRP), + NULL, dev_rescan_store); static void remove_callback(struct device *dev) { @@ -342,7 +344,7 @@ remove_store(struct device *dev, struct device_attribute *dummy, int ret = 0; unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; /* An attribute cannot be unregistered by one of its own methods, @@ -354,6 +356,8 @@ remove_store(struct device *dev, struct device_attribute *dummy, count = ret; return count; } +struct device_attribute dev_remove_attr = __ATTR(remove, (S_IWUSR|S_IWGRP), + NULL, remove_store); static ssize_t dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, @@ -362,7 +366,7 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, unsigned long val; struct pci_bus *bus = to_pci_bus(dev); - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -384,7 +388,7 @@ static ssize_t d3cold_allowed_store(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; pdev->d3cold_allowed = !!val; @@ -504,8 +508,6 @@ struct device_attribute pci_dev_attrs[] = { __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), - __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), - __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) __ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store), #endif @@ -1236,7 +1238,7 @@ static ssize_t reset_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = strict_strtoul(buf, 0, &val); + ssize_t result = kstrtoul(buf, 0, &val); if (result < 0) return result; @@ -1463,6 +1465,29 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, return a->mode; } +static struct attribute *pci_dev_hp_attrs[] = { + &dev_remove_attr.attr, + &dev_rescan_attr.attr, + NULL, +}; + +static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (pdev->is_virtfn) + return 0; + + return a->mode; +} + +static struct attribute_group pci_dev_hp_attr_group = { + .attrs = pci_dev_hp_attrs, + .is_visible = pci_dev_hp_attrs_are_visible, +}; + #ifdef CONFIG_PCI_IOV static struct attribute *sriov_dev_attrs[] = { &sriov_totalvfs_attr.attr, @@ -1494,6 +1519,7 @@ static struct attribute_group pci_dev_attr_group = { static const struct attribute_group *pci_dev_attr_groups[] = { &pci_dev_attr_group, + &pci_dev_hp_attr_group, #ifdef CONFIG_PCI_IOV &sriov_dev_attr_group, #endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a899d8bb190d..e5f4e55d407d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2421,7 +2421,7 @@ bool pci_acs_path_enabled(struct pci_dev *start, /** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device - * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) + * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) * * Perform INTx swizzling for a device behind one level of bridge. This is * required by section 9.1 of the PCI-to-PCI bridge specification for devices diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index d320df6375a2..403a44374ed5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -714,19 +714,12 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) up_read(&pci_bus_sem); } -/* - * pci_disable_link_state - disable pci device's link state, so the link will - * never enter specific states - */ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, bool force) { struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link; - if (aspm_disabled && !force) - return; - if (!pci_is_pcie(pdev)) return; @@ -736,6 +729,19 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, if (!parent || !parent->link_state) return; + /* + * A driver requested that ASPM be disabled on this device, but + * if we don't have permission to manage ASPM (e.g., on ACPI + * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and + * the _OSC method), we can't honor that request. Windows has + * a similar mechanism using "PciASPMOptOut", which is also + * ignored in this situation. + */ + if (aspm_disabled && !force) { + dev_warn(&pdev->dev, "can't disable ASPM; OS doesn't have ASPM control\n"); + return; + } + if (sem) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); @@ -761,6 +767,15 @@ void pci_disable_link_state_locked(struct pci_dev *pdev, int state) } EXPORT_SYMBOL(pci_disable_link_state_locked); +/** + * pci_disable_link_state - Disable device's link state, so the link will + * never enter specific states. Note that if the BIOS didn't grant ASPM + * control to the OS, this does nothing because we can't touch the LNKCTL + * register. + * + * @pdev: PCI device + * @state: ASPM link state to disable + */ void pci_disable_link_state(struct pci_dev *pdev, int state) { __pci_disable_link_state(pdev, state, true, false); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa3c1b2..fe5b50bd7536 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -170,7 +170,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, { u32 l, sz, mask; u16 orig_cmd; - struct pci_bus_region region; + struct pci_bus_region region, inverted_region; bool bar_too_big = false, bar_disabled = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_write_config_dword(dev, pos + 4, 0); region.start = 0; region.end = sz64; - pcibios_bus_to_resource(dev, res, ®ion); bar_disabled = true; } else { region.start = l64; region.end = l64 + sz64; - pcibios_bus_to_resource(dev, res, ®ion); } } else { sz = pci_size(l, sz, mask); @@ -265,7 +263,28 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, region.start = l; region.end = l + sz; - pcibios_bus_to_resource(dev, res, ®ion); + } + + pcibios_bus_to_resource(dev, res, ®ion); + pcibios_resource_to_bus(dev, &inverted_region, res); + + /* + * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is + * the corresponding resource address (the physical address used by + * the CPU. Converting that resource address back to a bus address + * should yield the original BAR value: + * + * resource_to_bus(bus_to_resource(A)) == A + * + * If it doesn't, CPU accesses to "bus_to_resource(A)" will not + * be claimed by the device. + */ + if (inverted_region.start != region.start) { + dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n", + pos, ®ion.start); + res->flags |= IORESOURCE_UNSET; + res->end -= res->start; + res->start = 0; } goto out; @@ -278,9 +297,9 @@ out: pci_write_config_word(dev, PCI_COMMAND, orig_cmd); if (bar_too_big) - dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); + dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); if (res->flags && !bar_disabled) - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); + dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7d68aeebf56b..c3a04026cca8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1022,6 +1022,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode @@ -2865,6 +2867,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); +/* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To + * work around this, query the size it should be configured to by the device and + * modify the resource end to correspond to this new size. + */ +static void quirk_intel_ntb(struct pci_dev *dev) +{ + int rc; + u8 val; + + rc = pci_read_config_byte(dev, 0x00D0, &val); + if (rc) + return; + + dev->resource[2].end = dev->resource[2].start + ((u64) 1 << val) - 1; + + rc = pci_read_config_byte(dev, 0x00D1, &val); + if (rc) + return; + + dev->resource[4].end = dev->resource[4].start + ((u64) 1 << val) - 1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); + static ktime_t fixup_debug_start(struct pci_dev *dev, void (*fn)(struct pci_dev *dev)) { |