diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/iov.c | 5 | ||||
-rw-r--r-- | drivers/pci/msi.c | 10 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 30 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 47 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 17 | ||||
-rw-r--r-- | drivers/pci/probe.c | 31 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 2 |
8 files changed, 98 insertions, 48 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c93071d428f..a971a6f6268 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 2c1075213be..aca7578b05e 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-sysfs.c b/drivers/pci/pci-sysfs.c index 0b56e0865f3..c0dbe1f6136 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -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) { @@ -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, @@ -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 @@ -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/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index d12c77cd699..90ea3e88041 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -13,10 +13,6 @@ #include <linux/aer.h> #include <linux/interrupt.h> -#define AER_NONFATAL 0 -#define AER_FATAL 1 -#define AER_CORRECTABLE 2 - #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ PCI_EXP_RTCTL_SENFEE| \ PCI_EXP_RTCTL_SEFEE) diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 5194a7d4173..cf611ab2193 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -29,6 +29,22 @@ static inline int hest_match_pci(struct acpi_hest_aer_common *p, p->function == PCI_FUNC(pci->devfn)); } +static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, + struct pci_dev *dev) +{ + u16 hest_type = hest_hdr->type; + u8 pcie_type = pci_pcie_type(dev); + + if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT && + pcie_type == PCI_EXP_TYPE_ROOT_PORT) || + (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT && + pcie_type == PCI_EXP_TYPE_ENDPOINT) || + (hest_type == ACPI_HEST_TYPE_AER_BRIDGE && + (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)) + return true; + return false; +} + struct aer_hest_parse_info { struct pci_dev *pci_dev; int firmware_first; @@ -38,34 +54,16 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) { struct aer_hest_parse_info *info = data; struct acpi_hest_aer_common *p; - u8 pcie_type = 0; - u8 bridge = 0; - int ff = 0; - - switch (hest_hdr->type) { - case ACPI_HEST_TYPE_AER_ROOT_PORT: - pcie_type = PCI_EXP_TYPE_ROOT_PORT; - break; - case ACPI_HEST_TYPE_AER_ENDPOINT: - pcie_type = PCI_EXP_TYPE_ENDPOINT; - break; - case ACPI_HEST_TYPE_AER_BRIDGE: - if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) - bridge = 1; - break; - default: - return 0; - } + int ff; p = (struct acpi_hest_aer_common *)(hest_hdr + 1); + ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); if (p->flags & ACPI_HEST_GLOBAL) { - if ((pci_is_pcie(info->pci_dev) && - pci_pcie_type(info->pci_dev) == pcie_type) || bridge) - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + if (hest_match_type(hest_hdr, info->pci_dev)) + info->firmware_first = ff; } else if (hest_match_pci(p, info->pci_dev)) - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); - info->firmware_first = ff; + info->firmware_first = ff; return 0; } @@ -89,6 +87,9 @@ static void aer_set_firmware_first(struct pci_dev *pci_dev) int pcie_aer_get_firmware_first(struct pci_dev *dev) { + if (!pci_is_pcie(dev)) + return 0; + if (!dev->__aer_firmware_first_valid) aer_set_firmware_first(dev); return dev->__aer_firmware_first; diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 8ec8b4f4856..d9e776e69fe 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -400,16 +400,16 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev) } /** - * default_downstream_reset_link - default reset function for Downstream Port - * @dev: pointer to downstream port's pci_dev data structure + * default_reset_link - default reset function + * @dev: pointer to pci_dev data structure * - * Invoked when performing link reset at Downstream Port w/ no aer driver. + * Invoked when performing link reset on a Downstream Port or a + * Root Port with no aer driver. */ -static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev) +static pci_ers_result_t default_reset_link(struct pci_dev *dev) { aer_do_secondary_bus_reset(dev); - dev_printk(KERN_DEBUG, &dev->dev, - "Downstream Port link has been reset\n"); + dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n"); return PCI_ERS_RESULT_RECOVERED; } @@ -458,8 +458,9 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) if (driver && driver->reset_link) { status = driver->reset_link(udev); - } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM) { - status = default_downstream_reset_link(udev); + } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM || + pci_pcie_type(udev) == PCI_EXP_TYPE_ROOT_PORT) { + status = default_reset_link(udev); } else { dev_printk(KERN_DEBUG, &dev->dev, "no link-reset support at upstream device %s\n", diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 58cc0a8a097..d0c33aac768 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 7f492574dcf..c3a04026cca 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 |