diff options
Diffstat (limited to 'drivers/pci')
41 files changed, 1131 insertions, 1075 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index fdc864f9cf23..b1ecefa2a23d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -27,10 +27,10 @@ config PCI_LEGACY default y help Say Y here if you want to include support for the deprecated - pci_find_slot() and pci_find_device() APIs. Most drivers have - been converted over to using the proper hotplug APIs, so this - option serves to include/exclude only a few drivers that are - still using this API. + pci_find_device() API. Most drivers have been converted over + to using the proper hotplug APIs, so this option serves to + include/exclude only a few drivers that are still using this + API. config PCI_DEBUG bool "PCI Debugging" @@ -69,3 +69,10 @@ config PCI_IOV physical resources. If unsure, say N. + +config PCI_IOAPIC + bool + depends on PCI + depends on ACPI + depends on HOTPLUG + default y diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 4a7f11d8f432..4df48d58eaa6 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -14,6 +14,8 @@ CFLAGS_legacy.o += -Wno-deprecated-declarations # Build PCI Express stuff if needed obj-$(CONFIG_PCIEPORTBUS) += pcie/ +obj-$(CONFIG_PCI_IOAPIC) += ioapic.o + obj-$(CONFIG_HOTPLUG) += hotplug.o # Build the PCI Hotplug drivers if we were asked to diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 416f6ac65b76..83aae4747594 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -320,7 +320,7 @@ found: for (bus = dev->bus; bus; bus = bus->parent) { struct pci_dev *bridge = bus->self; - if (!bridge || !bridge->is_pcie || + if (!bridge || !pci_is_pcie(bridge) || bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) return 0; @@ -339,6 +339,35 @@ found: } #endif +#ifdef CONFIG_ACPI_NUMA +static int __init +dmar_parse_one_rhsa(struct acpi_dmar_header *header) +{ + struct acpi_dmar_rhsa *rhsa; + struct dmar_drhd_unit *drhd; + + rhsa = (struct acpi_dmar_rhsa *)header; + for_each_drhd_unit(drhd) { + if (drhd->reg_base_addr == rhsa->base_address) { + int node = acpi_map_pxm_to_node(rhsa->proximity_domain); + + if (!node_online(node)) + node = -1; + drhd->iommu->node = node; + return 0; + } + } + WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + drhd->reg_base_addr, + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + + return 0; +} +#endif + static void __init dmar_table_print_dmar_entry(struct acpi_dmar_header *header) { @@ -458,7 +487,9 @@ parse_dmar_table(void) #endif break; case ACPI_DMAR_HARDWARE_AFFINITY: - /* We don't do anything with RHSA (yet?) */ +#ifdef CONFIG_ACPI_NUMA + ret = dmar_parse_one_rhsa(entry_header); +#endif break; default: printk(KERN_WARNING PREFIX @@ -582,6 +613,8 @@ int __init dmar_table_init(void) return 0; } +static int bios_warned; + int __init check_zero_address(void) { struct acpi_table_dmar *dmar; @@ -601,6 +634,9 @@ int __init check_zero_address(void) } if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { + void __iomem *addr; + u64 cap, ecap; + drhd = (void *)entry_header; if (!drhd->address) { /* Promote an attitude of violence to a BIOS engineer today */ @@ -609,17 +645,40 @@ int __init check_zero_address(void) dmi_get_system_info(DMI_BIOS_VENDOR), dmi_get_system_info(DMI_BIOS_VERSION), dmi_get_system_info(DMI_PRODUCT_VERSION)); -#ifdef CONFIG_DMAR - dmar_disabled = 1; -#endif - return 0; + bios_warned = 1; + goto failed; + } + + addr = early_ioremap(drhd->address, VTD_PAGE_SIZE); + if (!addr ) { + printk("IOMMU: can't validate: %llx\n", drhd->address); + goto failed; + } + cap = dmar_readq(addr + DMAR_CAP_REG); + ecap = dmar_readq(addr + DMAR_ECAP_REG); + early_iounmap(addr, VTD_PAGE_SIZE); + if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) { + /* Promote an attitude of violence to a BIOS engineer today */ + WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + drhd->address, + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + bios_warned = 1; + goto failed; } - break; } entry_header = ((void *)entry_header + entry_header->length); } return 1; + +failed: +#ifdef CONFIG_DMAR + dmar_disabled = 1; +#endif + return 0; } void __init detect_intel_iommu(void) @@ -645,8 +704,11 @@ void __init detect_intel_iommu(void) "x2apic and Intr-remapping.\n"); #endif #ifdef CONFIG_DMAR - if (ret && !no_iommu && !iommu_detected && !dmar_disabled) + if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { iommu_detected = 1; + /* Make sure ACS will be enabled */ + pci_request_acs(); + } #endif #ifdef CONFIG_X86 if (ret) @@ -667,6 +729,18 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) int agaw = 0; int msagaw = 0; + if (!drhd->reg_base_addr) { + if (!bios_warned) { + WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + bios_warned = 1; + } + return -EINVAL; + } + iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); if (!iommu) return -ENOMEM; @@ -683,13 +757,16 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { - /* Promote an attitude of violence to a BIOS engineer today */ - WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" - "BIOS vendor: %s; Ver: %s; Product Version: %s\n", - drhd->reg_base_addr, - dmi_get_system_info(DMI_BIOS_VENDOR), - dmi_get_system_info(DMI_BIOS_VERSION), - dmi_get_system_info(DMI_PRODUCT_VERSION)); + if (!bios_warned) { + /* Promote an attitude of violence to a BIOS engineer today */ + WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + drhd->reg_base_addr, + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + bios_warned = 1; + } goto err_unmap; } @@ -712,6 +789,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->agaw = agaw; iommu->msagaw = msagaw; + iommu->node = -1; + /* the registers might be more than one page */ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), cap_max_fault_reg_offset(iommu->cap)); @@ -1053,6 +1132,7 @@ static void __dmar_enable_qi(struct intel_iommu *iommu) int dmar_enable_qi(struct intel_iommu *iommu) { struct q_inval *qi; + struct page *desc_page; if (!ecap_qis(iommu->ecap)) return -ENOENT; @@ -1069,13 +1149,16 @@ int dmar_enable_qi(struct intel_iommu *iommu) qi = iommu->qi; - qi->desc = (void *)(get_zeroed_page(GFP_ATOMIC)); - if (!qi->desc) { + + desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); + if (!desc_page) { kfree(qi); iommu->qi = 0; return -ENOMEM; } + qi->desc = page_address(desc_page); + qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); if (!qi->desc_status) { free_page((unsigned long) qi->desc); diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 3625b094bf7e..6cd9f3c9887d 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -6,18 +6,22 @@ obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o -# pciehp should be linked before acpiphp in order to allow the native driver -# to attempt to bind first. We can then fall back to generic support. +# native drivers should be linked before acpiphp in order to allow the +# native driver to attempt to bind first. We can then fall back to +# generic support. obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o + +# acpiphp_ibm extends acpiphp, so should be linked afterwards. + +obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o # Link this last so it doesn't claim devices that have a real hotplug driver obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 0f32571b94df..3c76fc67cf0e 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -362,6 +362,8 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) status = acpi_pci_osc_control_set(handle, flags); if (ACPI_SUCCESS(status)) goto got_one; + if (status == AE_SUPPORT) + goto no_control; kfree(string.pointer); string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; } @@ -394,10 +396,9 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) if (ACPI_FAILURE(status)) break; } - +no_control: dbg("Cannot get control of hotplug hardware for pci %s\n", pci_name(pdev)); - kfree(string.pointer); return -ENODEV; got_one: diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 7d938df79206..bab52047baa8 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -146,12 +146,6 @@ struct acpiphp_attention_info struct module *owner; }; -struct acpiphp_ioapic { - struct pci_dev *dev; - u32 gsi_base; - struct list_head list; -}; - /* PCI bus bridge HID */ #define ACPI_PCI_HOST_HID "PNP0A03" diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index df1b0ea089d1..8e952fdab764 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -52,8 +52,6 @@ #include "acpiphp.h" static LIST_HEAD(bridge_list); -static LIST_HEAD(ioapic_list); -static DEFINE_SPINLOCK(ioapic_list_lock); #define MY_NAME "acpiphp_glue" @@ -311,17 +309,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) /* find acpiphp_func from acpiphp_bridge */ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) { - struct list_head *node, *l; struct acpiphp_bridge *bridge; struct acpiphp_slot *slot; struct acpiphp_func *func; - list_for_each(node, &bridge_list) { - bridge = list_entry(node, struct acpiphp_bridge, list); + list_for_each_entry(bridge, &bridge_list, list) { for (slot = bridge->slots; slot; slot = slot->next) { - list_for_each(l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, - sibling); + list_for_each_entry(func, &slot->funcs, sibling) { if (func->handle == handle) return func; } @@ -495,21 +489,19 @@ static int add_bridge(acpi_handle handle) static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { - struct list_head *head; - list_for_each(head, &bridge_list) { - struct acpiphp_bridge *bridge = list_entry(head, - struct acpiphp_bridge, list); + struct acpiphp_bridge *bridge; + + list_for_each_entry(bridge, &bridge_list, list) if (bridge->handle == handle) return bridge; - } return NULL; } static void cleanup_bridge(struct acpiphp_bridge *bridge) { - struct list_head *list, *tmp; - struct acpiphp_slot *slot; + struct acpiphp_slot *slot, *next; + struct acpiphp_func *func, *tmp; acpi_status status; acpi_handle handle = bridge->handle; @@ -530,10 +522,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) slot = bridge->slots; while (slot) { - struct acpiphp_slot *next = slot->next; - list_for_each_safe (list, tmp, &slot->funcs) { - struct acpiphp_func *func; - func = list_entry(list, struct acpiphp_func, sibling); + next = slot->next; + list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); unregister_dock_notifier(&func->nb); @@ -545,7 +535,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } - list_del(list); + list_del(&func->sibling); kfree(func); } acpiphp_unregister_hotplug_slot(slot); @@ -606,204 +596,17 @@ static void remove_bridge(acpi_handle handle) handle_hotplug_event_bridge); } -static struct pci_dev * get_apic_pci_info(acpi_handle handle) -{ - struct pci_dev *dev; - - dev = acpi_get_pci_dev(handle); - if (!dev) - return NULL; - - if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && - (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) - { - pci_dev_put(dev); - return NULL; - } - - return dev; -} - -static int get_gsi_base(acpi_handle handle, u32 *gsi_base) -{ - acpi_status status; - int result = -1; - unsigned long long gsb; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; - void *table; - - status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); - if (ACPI_SUCCESS(status)) { - *gsi_base = (u32)gsb; - return 0; - } - - status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); - if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) - return -1; - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER) - goto out; - - table = obj->buffer.pointer; - switch (((struct acpi_subtable_header *)table)->type) { - case ACPI_MADT_TYPE_IO_SAPIC: - *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base; - result = 0; - break; - case ACPI_MADT_TYPE_IO_APIC: - *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base; - result = 0; - break; - default: - break; - } - out: - kfree(buffer.pointer); - return result; -} - -static acpi_status -ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - unsigned long long sta; - acpi_handle tmp; - struct pci_dev *pdev; - u32 gsi_base; - u64 phys_addr; - struct acpiphp_ioapic *ioapic; - - /* Evaluate _STA if present */ - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) - return AE_CTRL_DEPTH; - - /* Scan only PCI bus scope */ - status = acpi_get_handle(handle, "_HID", &tmp); - if (ACPI_SUCCESS(status)) - return AE_CTRL_DEPTH; - - if (get_gsi_base(handle, &gsi_base)) - return AE_OK; - - ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL); - if (!ioapic) - return AE_NO_MEMORY; - - pdev = get_apic_pci_info(handle); - if (!pdev) - goto exit_kfree; - - if (pci_enable_device(pdev)) - goto exit_pci_dev_put; - - pci_set_master(pdev); - - if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) - goto exit_pci_disable_device; - - phys_addr = pci_resource_start(pdev, 0); - if (acpi_register_ioapic(handle, phys_addr, gsi_base)) - goto exit_pci_release_region; - - ioapic->gsi_base = gsi_base; - ioapic->dev = pdev; - spin_lock(&ioapic_list_lock); - list_add_tail(&ioapic->list, &ioapic_list); - spin_unlock(&ioapic_list_lock); - - return AE_OK; - - exit_pci_release_region: - pci_release_region(pdev, 0); - exit_pci_disable_device: - pci_disable_device(pdev); - exit_pci_dev_put: - pci_dev_put(pdev); - exit_kfree: - kfree(ioapic); - - return AE_OK; -} - -static acpi_status -ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - unsigned long long sta; - acpi_handle tmp; - u32 gsi_base; - struct acpiphp_ioapic *pos, *n, *ioapic = NULL; - - /* Evaluate _STA if present */ - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) - return AE_CTRL_DEPTH; - - /* Scan only PCI bus scope */ - status = acpi_get_handle(handle, "_HID", &tmp); - if (ACPI_SUCCESS(status)) - return AE_CTRL_DEPTH; - - if (get_gsi_base(handle, &gsi_base)) - return AE_OK; - - acpi_unregister_ioapic(handle, gsi_base); - - spin_lock(&ioapic_list_lock); - list_for_each_entry_safe(pos, n, &ioapic_list, list) { - if (pos->gsi_base != gsi_base) - continue; - ioapic = pos; - list_del(&ioapic->list); - break; - } - spin_unlock(&ioapic_list_lock); - - if (!ioapic) - return AE_OK; - - pci_release_region(ioapic->dev, 0); - pci_disable_device(ioapic->dev); - pci_dev_put(ioapic->dev); - kfree(ioapic); - - return AE_OK; -} - -static int acpiphp_configure_ioapics(acpi_handle handle) -{ - ioapic_add(handle, 0, NULL, NULL); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, ioapic_add, NULL, NULL, NULL); - return 0; -} - -static int acpiphp_unconfigure_ioapics(acpi_handle handle) -{ - ioapic_remove(handle, 0, NULL, NULL); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, ioapic_remove, NULL, NULL, NULL); - return 0; -} - static int power_on_slot(struct acpiphp_slot *slot) { acpi_status status; struct acpiphp_func *func; - struct list_head *l; int retval = 0; /* if already enabled, just skip */ if (slot->flags & SLOT_POWEREDON) goto err_exit; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - + list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS0) { dbg("%s: executing _PS0\n", __func__); status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); @@ -829,7 +632,6 @@ static int power_off_slot(struct acpiphp_slot *slot) { acpi_status status; struct acpiphp_func *func; - struct list_head *l; int retval = 0; @@ -837,9 +639,7 @@ static int power_off_slot(struct acpiphp_slot *slot) if ((slot->flags & SLOT_POWEREDON) == 0) goto err_exit; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - + list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_PS3) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { @@ -966,7 +766,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bridge->pci_bus; - struct list_head *l; struct acpiphp_func *func; int retval = 0; int num, max, pass; @@ -1006,21 +805,16 @@ static int __ref enable_device(struct acpiphp_slot *slot) } } - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); + list_for_each_entry(func, &slot->funcs, sibling) acpiphp_bus_add(func); - } pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(bus); - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_configure_ioapics(func->handle); pci_enable_bridges(bus); pci_bus_add_devices(bus); - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); + list_for_each_entry(func, &slot->funcs, sibling) { dev = pci_get_slot(bus, PCI_DEVFN(slot->device, func->function)); if (!dev) @@ -1091,7 +885,6 @@ static int disable_device(struct acpiphp_slot *slot) } list_for_each_entry(func, &slot->funcs, sibling) { - acpiphp_unconfigure_ioapics(func->handle); acpiphp_bus_trim(func->handle); } @@ -1119,12 +912,9 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) acpi_status status; unsigned long long sta = 0; u32 dvid; - struct list_head *l; struct acpiphp_func *func; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - + list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) @@ -1152,13 +942,10 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot) { acpi_status status; struct acpiphp_func *func; - struct list_head *l; struct acpi_object_list arg_list; union acpi_object arg; - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - + list_for_each_entry(func, &slot->funcs, sibling) { /* We don't want to call _EJ0 on non-existing functions. */ if ((func->flags & FUNC_HAS_EJ0)) { /* _EJ0 method take one argument */ @@ -1275,7 +1062,6 @@ static int acpiphp_configure_bridge (acpi_handle handle) acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(bus); pci_enable_bridges(bus); - acpiphp_configure_ioapics(handle); return 0; } @@ -1542,7 +1328,7 @@ int __init acpiphp_get_num_slots(void) struct acpiphp_bridge *bridge; int num_slots = 0; - list_for_each_entry (bridge, &bridge_list, list) { + list_for_each_entry(bridge, &bridge_list, list) { dbg("Bus %04x:%02x has %d slot%s\n", pci_domain_nr(bridge->pci_bus), bridge->pci_bus->number, bridge->nr_slots, diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index 83f337c891a9..c7084f0eca5a 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -890,7 +890,7 @@ static int poll_hpc(void *data) msleep(POLL_INTERVAL_SEC * 1000); if (kthread_should_stop()) - break; + goto out_sleep; down (&semOperations); @@ -904,6 +904,7 @@ static int poll_hpc(void *data) /* give up the hardware semaphore */ up (&semOperations); /* sleep for a short time just for good measure */ +out_sleep: msleep(100); } up (&sem_exit); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 0325d989bb46..38183a534b65 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -68,26 +68,26 @@ static DEFINE_MUTEX(pci_hp_mutex); static char *pci_bus_speed_strings[] = { "33 MHz PCI", /* 0x00 */ "66 MHz PCI", /* 0x01 */ - "66 MHz PCIX", /* 0x02 */ - "100 MHz PCIX", /* 0x03 */ - "133 MHz PCIX", /* 0x04 */ + "66 MHz PCI-X", /* 0x02 */ + "100 MHz PCI-X", /* 0x03 */ + "133 MHz PCI-X", /* 0x04 */ NULL, /* 0x05 */ NULL, /* 0x06 */ NULL, /* 0x07 */ NULL, /* 0x08 */ - "66 MHz PCIX 266", /* 0x09 */ - "100 MHz PCIX 266", /* 0x0a */ - "133 MHz PCIX 266", /* 0x0b */ + "66 MHz PCI-X 266", /* 0x09 */ + "100 MHz PCI-X 266", /* 0x0a */ + "133 MHz PCI-X 266", /* 0x0b */ NULL, /* 0x0c */ NULL, /* 0x0d */ NULL, /* 0x0e */ NULL, /* 0x0f */ NULL, /* 0x10 */ - "66 MHz PCIX 533", /* 0x11 */ - "100 MHz PCIX 533", /* 0x12 */ - "133 MHz PCIX 533", /* 0x13 */ - "2.5 GT/s PCI-E", /* 0x14 */ - "5.0 GT/s PCI-E", /* 0x15 */ + "66 MHz PCI-X 533", /* 0x11 */ + "100 MHz PCI-X 533", /* 0x12 */ + "133 MHz PCI-X 533", /* 0x13 */ + "2.5 GT/s PCIe", /* 0x14 */ + "5.0 GT/s PCIe", /* 0x15 */ }; #ifdef CONFIG_HOTPLUG_PCI_CPCI diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 3070f77eb56a..4ed76b47b6dc 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -91,7 +91,6 @@ struct controller { struct slot *slot; wait_queue_head_t queue; /* sleep & wake process */ u32 slot_cap; - u8 cap_base; struct timer_list poll_timer; unsigned int cmd_busy:1; unsigned int no_cmd_complete:1; diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 37c8d3d0323e..b09b083011d6 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -87,7 +87,8 @@ static int __init dummy_probe(struct pcie_device *dev) /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ if (pciehp_get_hp_hw_control_from_firmware(pdev)) return -ENODEV; - if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP))) + pos = pci_pcie_cap(pdev); + if (!pos) return -ENODEV; pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); slot = kzalloc(sizeof(*slot), GFP_KERNEL); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index bc234719b1df..5674b2075bdc 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -72,18 +72,6 @@ static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); -static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { - .set_attention_status = set_attention_status, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -95,6 +83,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); + kfree(hotplug_slot->ops); kfree(hotplug_slot->info); kfree(hotplug_slot); } @@ -104,6 +93,7 @@ static int init_slot(struct controller *ctrl) struct slot *slot = ctrl->slot; struct hotplug_slot *hotplug = NULL; struct hotplug_slot_info *info = NULL; + struct hotplug_slot_ops *ops = NULL; char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; @@ -115,11 +105,28 @@ static int init_slot(struct controller *ctrl) if (!info) goto out; + /* Setup hotplug slot ops */ + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + goto out; + ops->enable_slot = enable_slot; + ops->disable_slot = disable_slot; + ops->get_power_status = get_power_status; + ops->get_adapter_status = get_adapter_status; + ops->get_max_bus_speed = get_max_bus_speed; + ops->get_cur_bus_speed = get_cur_bus_speed; + if (MRL_SENS(ctrl)) + ops->get_latch_status = get_latch_status; + if (ATTN_LED(ctrl)) { + ops->get_attention_status = get_attention_status; + ops->set_attention_status = set_attention_status; + } + /* register this slot with the hotplug pci core */ hotplug->info = info; hotplug->private = slot; hotplug->release = &release_slot; - hotplug->ops = &pciehp_hotplug_slot_ops; + hotplug->ops = ops; slot->hotplug_slot = hotplug; snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); @@ -128,17 +135,12 @@ static int init_slot(struct controller *ctrl) ctrl->pcie->port->subordinate->number, PSN(ctrl)); retval = pci_hp_register(hotplug, ctrl->pcie->port->subordinate, 0, name); - if (retval) { + if (retval) ctrl_err(ctrl, "pci_hp_register failed with error %d\n", retval); - goto out; - } - get_power_status(hotplug, &info->power_status); - get_attention_status(hotplug, &info->attention_status); - get_latch_status(hotplug, &info->latch_status); - get_adapter_status(hotplug, &info->adapter_status); out: if (retval) { + kfree(ops); kfree(info); kfree(hotplug); } @@ -160,12 +162,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - hotplug_slot->info->attention_status = status; - - if (ATTN_LED(slot->ctrl)) - pciehp_set_attention_status(slot, status); - - return 0; + return pciehp_set_attention_status(slot, status); } @@ -193,92 +190,62 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_power_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->power_status; - - return 0; + return pciehp_get_power_status(slot, value); } static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_attention_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->attention_status; - - return 0; + return pciehp_get_attention_status(slot, value); } static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_latch_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->latch_status; - - return 0; + return pciehp_get_latch_status(slot, value); } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_adapter_status(slot, value); - if (retval < 0) - *value = hotplug_slot->info->adapter_status; - - return 0; + return pciehp_get_adapter_status(slot, value); } static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_max_link_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; - - return 0; + return pciehp_get_max_link_speed(slot, value); } static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = hotplug_slot->private; - int retval; ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - retval = pciehp_get_cur_link_speed(slot, value); - if (retval < 0) - *value = PCI_SPEED_UNKNOWN; - - return 0; + return pciehp_get_cur_link_speed(slot, value); } static int pciehp_probe(struct pcie_device *dev) @@ -286,14 +253,13 @@ static int pciehp_probe(struct pcie_device *dev) int rc; struct controller *ctrl; struct slot *slot; - u8 value; - struct pci_dev *pdev = dev->port; + u8 occupied, poweron; if (pciehp_force) dev_info(&dev->device, "Bypassing BIOS check for pciehp use on %s\n", - pci_name(pdev)); - else if (pciehp_get_hp_hw_control_from_firmware(pdev)) + pci_name(dev->port)); + else if (pciehp_get_hp_hw_control_from_firmware(dev->port)) goto err_out_none; ctrl = pcie_init(dev); @@ -318,23 +284,18 @@ static int pciehp_probe(struct pcie_device *dev) rc = pcie_init_notification(ctrl); if (rc) { ctrl_err(ctrl, "Notification initialization failed\n"); - goto err_out_release_ctlr; + goto err_out_free_ctrl_slot; } /* Check if slot is occupied */ slot = ctrl->slot; - pciehp_get_adapter_status(slot, &value); - if (value) { - if (pciehp_force) - pciehp_enable_slot(slot); - } else { - /* Power off slot if not occupied */ - if (POWER_CTRL(ctrl)) { - rc = pciehp_power_off_slot(slot); - if (rc) - goto err_out_free_ctrl_slot; - } - } + pciehp_get_adapter_status(slot, &occupied); + pciehp_get_power_status(slot, &poweron); + if (occupied && pciehp_force) + pciehp_enable_slot(slot); + /* If empty slot's power status is on, turn power off */ + if (!occupied && poweron && POWER_CTRL(ctrl)) + pciehp_power_off_slot(slot); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 84487d126e4d..d6ac1b261dd9 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -142,23 +142,9 @@ u8 pciehp_handle_power_fault(struct slot *p_slot) /* power fault */ ctrl_dbg(ctrl, "Power fault interrupt received\n"); - - if (!pciehp_query_power_fault(p_slot)) { - /* - * power fault Cleared - */ - ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n", - slot_name(p_slot)); - event_type = INT_POWER_FAULT_CLEAR; - } else { - /* - * power fault - */ - ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot)); - event_type = INT_POWER_FAULT; - ctrl_info(ctrl, "Power fault bit %x set\n", 0); - } - + ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); + event_type = INT_POWER_FAULT; + ctrl_info(ctrl, "Power fault bit %x set\n", 0); queue_interrupt_event(p_slot, event_type); return 1; @@ -224,13 +210,12 @@ static int board_added(struct slot *p_slot) retval = pciehp_check_link_status(ctrl); if (retval) { ctrl_err(ctrl, "Failed to check link status\n"); - set_slot_off(ctrl, p_slot); - return retval; + goto err_exit; } /* Check for a power fault */ - if (pciehp_query_power_fault(p_slot)) { - ctrl_dbg(ctrl, "Power fault detected\n"); + if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { + ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); retval = -EIO; goto err_exit; } @@ -363,25 +348,6 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) mutex_unlock(&p_slot->lock); } -static int update_slot_info(struct slot *slot) -{ - struct hotplug_slot_info *info; - int result; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - pciehp_get_power_status(slot, &info->power_status); - pciehp_get_attention_status(slot, &info->attention_status); - pciehp_get_latch_status(slot, &info->latch_status); - pciehp_get_adapter_status(slot, &info->adapter_status); - - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree (info); - return result; -} - /* * Note: This function must be called with slot->lock held */ @@ -442,7 +408,6 @@ static void handle_button_press_event(struct slot *p_slot) * to hot-add or hot-remove is undergoing */ ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); - update_slot_info(p_slot); break; default: ctrl_warn(ctrl, "Not a valid state\n"); @@ -500,11 +465,9 @@ static void interrupt_event_handler(struct work_struct *work) if (!HP_SUPR_RM(ctrl)) break; ctrl_dbg(ctrl, "Surprise Removal\n"); - update_slot_info(p_slot); handle_surprise_event(p_slot); break; default: - update_slot_info(p_slot); break; } mutex_unlock(&p_slot->lock); @@ -547,9 +510,6 @@ int pciehp_enable_slot(struct slot *p_slot) if (rc) { pciehp_get_latch_status(p_slot, &getstatus); } - - update_slot_info(p_slot); - return rc; } @@ -590,10 +550,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - ret = remove_board(p_slot); - update_slot_info(p_slot); - - return ret; + return remove_board(p_slot); } int pciehp_sysfs_enable_slot(struct slot *p_slot) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9ef4605c1ef6..10040d58c8ef 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -45,25 +45,25 @@ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) { struct pci_dev *dev = ctrl->pcie->port; - return pci_read_config_word(dev, ctrl->cap_base + reg, value); + return pci_read_config_word(dev, pci_pcie_cap(dev) + reg, value); } static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) { struct pci_dev *dev = ctrl->pcie->port; - return pci_read_config_dword(dev, ctrl->cap_base + reg, value); + return pci_read_config_dword(dev, pci_pcie_cap(dev) + reg, value); } static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) { struct pci_dev *dev = ctrl->pcie->port; - return pci_write_config_word(dev, ctrl->cap_base + reg, value); + return pci_write_config_word(dev, pci_pcie_cap(dev) + reg, value); } static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) { struct pci_dev *dev = ctrl->pcie->port; - return pci_write_config_dword(dev, ctrl->cap_base + reg, value); + return pci_write_config_dword(dev, pci_pcie_cap(dev) + reg, value); } /* Power Control Command */ @@ -318,8 +318,8 @@ int pciehp_get_attention_status(struct slot *slot, u8 *status) return retval; } - ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; @@ -356,8 +356,8 @@ int pciehp_get_power_status(struct slot *slot, u8 *status) ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); return retval; } - ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; @@ -427,27 +427,24 @@ int pciehp_set_attention_status(struct slot *slot, u8 value) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - int rc; cmd_mask = PCI_EXP_SLTCTL_AIC; switch (value) { - case 0 : /* turn off */ - slot_cmd = 0x00C0; - break; - case 1: /* turn on */ - slot_cmd = 0x0040; - break; - case 2: /* turn blink */ - slot_cmd = 0x0080; - break; - default: - return -1; + case 0 : /* turn off */ + slot_cmd = 0x00C0; + break; + case 1: /* turn on */ + slot_cmd = 0x0040; + break; + case 2: /* turn blink */ + slot_cmd = 0x0080; + break; + default: + return -EINVAL; } - rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); - - return rc; + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); + return pcie_write_cmd(ctrl, slot_cmd, cmd_mask); } void pciehp_green_led_on(struct slot *slot) @@ -459,8 +456,8 @@ void pciehp_green_led_on(struct slot *slot) slot_cmd = 0x0100; cmd_mask = PCI_EXP_SLTCTL_PIC; pcie_write_cmd(ctrl, slot_cmd, cmd_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); } void pciehp_green_led_off(struct slot *slot) @@ -472,8 +469,8 @@ void pciehp_green_led_off(struct slot *slot) slot_cmd = 0x0300; cmd_mask = PCI_EXP_SLTCTL_PIC; pcie_write_cmd(ctrl, slot_cmd, cmd_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); } void pciehp_green_led_blink(struct slot *slot) @@ -485,8 +482,8 @@ void pciehp_green_led_blink(struct slot *slot) slot_cmd = 0x0200; cmd_mask = PCI_EXP_SLTCTL_PIC; pcie_write_cmd(ctrl, slot_cmd, cmd_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); } int pciehp_power_on_slot(struct slot * slot) @@ -514,97 +511,38 @@ int pciehp_power_on_slot(struct slot * slot) return retval; } } + ctrl->power_fault_detected = 0; slot_cmd = POWER_ON; cmd_mask = PCI_EXP_SLTCTL_PCC; - if (!pciehp_poll_mode) { - /* Enable power fault detection turned off at power off time */ - slot_cmd |= PCI_EXP_SLTCTL_PFDE; - cmd_mask |= PCI_EXP_SLTCTL_PFDE; - } - retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); return retval; } - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); - ctrl->power_fault_detected = 0; return retval; } -static inline int pcie_mask_bad_dllp(struct controller *ctrl) -{ - struct pci_dev *dev = ctrl->pcie->port; - int pos; - u32 reg; - - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); - if (!pos) - return 0; - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); - if (reg & PCI_ERR_COR_BAD_DLLP) - return 0; - reg |= PCI_ERR_COR_BAD_DLLP; - pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); - return 1; -} - -static inline void pcie_unmask_bad_dllp(struct controller *ctrl) -{ - struct pci_dev *dev = ctrl->pcie->port; - u32 reg; - int pos; - - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); - if (!pos) - return; - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®); - if (!(reg & PCI_ERR_COR_BAD_DLLP)) - return; - reg &= ~PCI_ERR_COR_BAD_DLLP; - pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg); -} - int pciehp_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - int retval = 0; - int changed; - - /* - * Set Bad DLLP Mask bit in Correctable Error Mask - * Register. This is the workaround against Bad DLLP error - * that sometimes happens during turning power off the slot - * which conforms to PCI Express 1.0a spec. - */ - changed = pcie_mask_bad_dllp(ctrl); + int retval; slot_cmd = POWER_OFF; cmd_mask = PCI_EXP_SLTCTL_PCC; - if (!pciehp_poll_mode) { - /* Disable power fault detection */ - slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; - cmd_mask |= PCI_EXP_SLTCTL_PFDE; - } - retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write command failed!\n"); - retval = -1; - goto out; + return retval; } - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", - __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); - out: - if (changed) - pcie_unmask_bad_dllp(ctrl); - - return retval; + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); + return 0; } static irqreturn_t pcie_isr(int irq, void *dev_id) @@ -840,11 +778,19 @@ int pcie_enable_notification(struct controller *ctrl) { u16 cmd, mask; + /* + * TBD: Power fault detected software notification support. + * + * Power fault detected software notification is not enabled + * now, because it caused power fault detected interrupt storm + * on some machines. On those machines, power fault detected + * bit in the slot status register was set again immediately + * when it is cleared in the interrupt service routine, and + * next power fault detected interrupt was notified again. + */ cmd = PCI_EXP_SLTCTL_PDCE; if (ATTN_BUTTN(ctrl)) cmd |= PCI_EXP_SLTCTL_ABPE; - if (POWER_CTRL(ctrl)) - cmd |= PCI_EXP_SLTCTL_PFDE; if (MRL_SENS(ctrl)) cmd |= PCI_EXP_SLTCTL_MRLSCE; if (!pciehp_poll_mode) @@ -866,7 +812,8 @@ static void pcie_disable_notification(struct controller *ctrl) u16 mask; mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | - PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); + PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_DLLSCE); if (pcie_write_cmd(ctrl, 0, mask)) ctrl_warn(ctrl, "Cannot disable software notification\n"); } @@ -934,7 +881,8 @@ static inline void dbg_ctrl(struct controller *ctrl) pdev->subsystem_device); ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor); - ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base); + ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", + pci_pcie_cap(pdev)); for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (!pci_resource_len(pdev, i)) continue; @@ -978,8 +926,7 @@ struct controller *pcie_init(struct pcie_device *dev) goto abort; } ctrl->pcie = dev; - ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (!ctrl->cap_base) { + if (!pci_pcie_cap(pdev)) { ctrl_err(ctrl, "Cannot find PCI Express capability\n"); goto abort_ctrl; } diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index cc8ec3aa41a7..80b461c98557 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -43,7 +43,7 @@ static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) * Perhaps we *should* use default settings for PCIe, but * pciehp didn't, so we won't either. */ - if (dev->is_pcie) + if (pci_is_pcie(dev)) return; dev_info(&dev->dev, "using default PCI settings\n"); hpp = &pci_default_type0; @@ -102,7 +102,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) return; /* Find PCI Express capability */ - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); if (!pos) return; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index bd588eb8e922..8e210cd76e55 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -121,7 +121,7 @@ struct controller { #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 #define PCI_DEVICE_ID_AMD_POGO_7458 0x7458 -/* AMD PCIX bridge registers */ +/* AMD PCI-X bridge registers */ #define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C #define PCIX_MISCII_OFFSET 0x48 #define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80 diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 9261327b49f3..417312528ddf 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -277,6 +277,7 @@ static int hw_pass_through = 1; struct dmar_domain { int id; /* domain id */ + int nid; /* node id */ unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/ struct list_head devices; /* all devices' list */ @@ -304,7 +305,7 @@ struct device_domain_info { int segment; /* PCI domain */ u8 bus; /* PCI bus number */ u8 devfn; /* PCI devfn number */ - struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ + struct pci_dev *dev; /* it's NULL for PCIe-to-PCI bridge */ struct intel_iommu *iommu; /* IOMMU used by this device */ struct dmar_domain *domain; /* pointer to domain */ }; @@ -386,30 +387,14 @@ static struct kmem_cache *iommu_domain_cache; static struct kmem_cache *iommu_devinfo_cache; static struct kmem_cache *iommu_iova_cache; -static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep) +static inline void *alloc_pgtable_page(int node) { - unsigned int flags; - void *vaddr; - - /* trying to avoid low memory issues */ - flags = current->flags & PF_MEMALLOC; - current->flags |= PF_MEMALLOC; - vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC); - current->flags &= (~PF_MEMALLOC | flags); - return vaddr; -} - + struct page *page; + void *vaddr = NULL; -static inline void *alloc_pgtable_page(void) -{ - unsigned int flags; - void *vaddr; - - /* trying to avoid low memory issues */ - flags = current->flags & PF_MEMALLOC; - current->flags |= PF_MEMALLOC; - vaddr = (void *)get_zeroed_page(GFP_ATOMIC); - current->flags &= (~PF_MEMALLOC | flags); + page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0); + if (page) + vaddr = page_address(page); return vaddr; } @@ -420,7 +405,7 @@ static inline void free_pgtable_page(void *vaddr) static inline void *alloc_domain_mem(void) { - return iommu_kmem_cache_alloc(iommu_domain_cache); + return kmem_cache_alloc(iommu_domain_cache, GFP_ATOMIC); } static void free_domain_mem(void *vaddr) @@ -430,7 +415,7 @@ static void free_domain_mem(void *vaddr) static inline void * alloc_devinfo_mem(void) { - return iommu_kmem_cache_alloc(iommu_devinfo_cache); + return kmem_cache_alloc(iommu_devinfo_cache, GFP_ATOMIC); } static inline void free_devinfo_mem(void *vaddr) @@ -440,7 +425,7 @@ static inline void free_devinfo_mem(void *vaddr) struct iova *alloc_iova_mem(void) { - return iommu_kmem_cache_alloc(iommu_iova_cache); + return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC); } void free_iova_mem(struct iova *iova) @@ -589,7 +574,8 @@ static struct context_entry * device_to_context_entry(struct intel_iommu *iommu, root = &iommu->root_entry[bus]; context = get_context_addr_from_root(root); if (!context) { - context = (struct context_entry *)alloc_pgtable_page(); + context = (struct context_entry *) + alloc_pgtable_page(iommu->node); if (!context) { spin_unlock_irqrestore(&iommu->lock, flags); return NULL; @@ -732,7 +718,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, if (!dma_pte_present(pte)) { uint64_t pteval; - tmp_page = alloc_pgtable_page(); + tmp_page = alloc_pgtable_page(domain->nid); if (!tmp_page) return NULL; @@ -868,7 +854,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu) struct root_entry *root; unsigned long flags; - root = (struct root_entry *)alloc_pgtable_page(); + root = (struct root_entry *)alloc_pgtable_page(iommu->node); if (!root) return -ENOMEM; @@ -1263,6 +1249,7 @@ static struct dmar_domain *alloc_domain(void) if (!domain) return NULL; + domain->nid = -1; memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); domain->flags = 0; @@ -1420,9 +1407,10 @@ static int domain_init(struct dmar_domain *domain, int guest_width) domain->iommu_snooping = 0; domain->iommu_count = 1; + domain->nid = iommu->node; /* always allocate the top pgd */ - domain->pgd = (struct dma_pte *)alloc_pgtable_page(); + domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); if (!domain->pgd) return -ENOMEM; __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE); @@ -1523,12 +1511,15 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, /* Skip top levels of page tables for * iommu which has less agaw than default. + * Unnecessary for PT mode. */ - for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { - pgd = phys_to_virt(dma_pte_addr(pgd)); - if (!dma_pte_present(pgd)) { - spin_unlock_irqrestore(&iommu->lock, flags); - return -ENOMEM; + if (translation != CONTEXT_TT_PASS_THROUGH) { + for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { + pgd = phys_to_virt(dma_pte_addr(pgd)); + if (!dma_pte_present(pgd)) { + spin_unlock_irqrestore(&iommu->lock, flags); + return -ENOMEM; + } } } } @@ -1577,6 +1568,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, spin_lock_irqsave(&domain->iommu_lock, flags); if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) { domain->iommu_count++; + if (domain->iommu_count == 1) + domain->nid = iommu->node; domain_update_iommu_cap(domain); } spin_unlock_irqrestore(&domain->iommu_lock, flags); @@ -1611,7 +1604,7 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev, return ret; parent = parent->bus->self; } - if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ + if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */ return domain_context_mapping_one(domain, pci_domain_nr(tmp->subordinate), tmp->subordinate->number, 0, @@ -1651,7 +1644,7 @@ static int domain_context_mapped(struct pci_dev *pdev) return ret; parent = parent->bus->self; } - if (tmp->is_pcie) + if (pci_is_pcie(tmp)) return device_context_mapped(iommu, tmp->subordinate->number, 0); else @@ -1821,7 +1814,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) dev_tmp = pci_find_upstream_pcie_bridge(pdev); if (dev_tmp) { - if (dev_tmp->is_pcie) { + if (pci_is_pcie(dev_tmp)) { bus = dev_tmp->subordinate->number; devfn = 0; } else { @@ -1991,6 +1984,16 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", pci_name(pdev), start, end); + if (end < start) { + WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + ret = -EIO; + goto error; + } + if (end >> agaw_to_width(domain->agaw)) { WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n" "BIOS vendor: %s; Ver: %s; Product Version: %s\n", @@ -2182,7 +2185,7 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup) * the 1:1 domain, just in _case_ one of their siblings turns out * not to be able to map all of memory. */ - if (!pdev->is_pcie) { + if (!pci_is_pcie(pdev)) { if (!pci_is_root_bus(pdev->bus)) return 0; if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) @@ -3228,6 +3231,9 @@ static int device_notifier(struct notifier_block *nb, struct pci_dev *pdev = to_pci_dev(dev); struct dmar_domain *domain; + if (iommu_no_mapping(dev)) + return 0; + domain = find_domain(pdev); if (!domain) return 0; @@ -3319,7 +3325,7 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu, parent->devfn); parent = parent->bus->self; } - if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ + if (pci_is_pcie(tmp)) /* this is a PCIe-to-PCI bridge */ iommu_detach_dev(iommu, tmp->subordinate->number, 0); else /* this is a legacy PCI bridge */ @@ -3455,6 +3461,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void) return NULL; domain->id = vm_domid++; + domain->nid = -1; memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE; @@ -3481,9 +3488,10 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) domain->iommu_coherency = 0; domain->iommu_snooping = 0; domain->max_addr = 0; + domain->nid = -1; /* always allocate the top pgd */ - domain->pgd = (struct dma_pte *)alloc_pgtable_page(); + domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid); if (!domain->pgd) return -ENOMEM; domain_flush_cache(domain, domain->pgd, PAGE_SIZE); diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 3b3658669bee..95b849130ad4 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -520,7 +520,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev) return -1; /* PCIe device or Root Complex integrated PCI device */ - if (dev->is_pcie || !dev->bus->parent) { + if (pci_is_pcie(dev) || !dev->bus->parent) { set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, (dev->bus->number << 8) | dev->devfn); return 0; @@ -528,7 +528,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev) bridge = pci_find_upstream_pcie_bridge(dev); if (bridge) { - if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */ + if (pci_is_pcie(bridge))/* this is a PCIe-to-PCI/PCIX bridge */ set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, (bridge->bus->number << 8) | dev->bus->number); else /* this is a legacy PCI bridge */ @@ -590,7 +590,8 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode) if (!iommu->ir_table) return -ENOMEM; - pages = alloc_pages(GFP_ATOMIC | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); + pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, + INTR_REMAP_PAGE_ORDER); if (!pages) { printk(KERN_ERR "failed to allocate pages of order %d\n", diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c new file mode 100644 index 000000000000..3e0d7b5dd1b9 --- /dev/null +++ b/drivers/pci/ioapic.c @@ -0,0 +1,127 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/* + * This driver manages PCI I/O APICs added by hotplug after boot. We try to + * claim all I/O APIC PCI devices, but those present at boot were registered + * when we parsed the ACPI MADT, so we'll fail when we try to re-register + * them. + */ + +#include <linux/pci.h> +#include <linux/acpi.h> +#include <acpi/acpi_bus.h> + +struct ioapic { + acpi_handle handle; + u32 gsi_base; +}; + +static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + acpi_handle handle; + acpi_status status; + unsigned long long gsb; + struct ioapic *ioapic; + u64 addr; + int ret; + char *type; + + handle = DEVICE_ACPI_HANDLE(&dev->dev); + if (!handle) + return -EINVAL; + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); + if (ACPI_FAILURE(status)) + return -EINVAL; + + /* + * The previous code in acpiphp evaluated _MAT if _GSB failed, but + * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs. + */ + + ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); + if (!ioapic) + return -ENOMEM; + + ioapic->handle = handle; + ioapic->gsi_base = (u32) gsb; + + if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC) + type = "IOAPIC"; + else + type = "IOxAPIC"; + + ret = pci_enable_device(dev); + if (ret < 0) + goto exit_free; + + pci_set_master(dev); + + if (pci_request_region(dev, 0, type)) + goto exit_disable; + + addr = pci_resource_start(dev, 0); + if (acpi_register_ioapic(ioapic->handle, addr, ioapic->gsi_base)) + goto exit_release; + + pci_set_drvdata(dev, ioapic); + dev_info(&dev->dev, "%s at %#llx, GSI %u\n", type, addr, + ioapic->gsi_base); + return 0; + +exit_release: + pci_release_region(dev, 0); +exit_disable: + pci_disable_device(dev); +exit_free: + kfree(ioapic); + return -ENODEV; +} + +static void ioapic_remove(struct pci_dev *dev) +{ + struct ioapic *ioapic = pci_get_drvdata(dev); + + acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base); + pci_release_region(dev, 0); + pci_disable_device(dev); + kfree(ioapic); +} + + +static struct pci_device_id ioapic_devices[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SYSTEM_PIC_IOAPIC << 8, 0xffff00, }, + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SYSTEM_PIC_IOXAPIC << 8, 0xffff00, }, + { } +}; + +static struct pci_driver ioapic_driver = { + .name = "ioapic", + .id_table = ioapic_devices, + .probe = ioapic_probe, + .remove = __devexit_p(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); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index e03fe98f0619..b2a448e19fe6 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -555,7 +555,7 @@ int pci_iov_init(struct pci_dev *dev) { int pos; - if (!dev->is_pcie) + if (!pci_is_pcie(dev)) return -ENODEV; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 33317df47699..7e2829538a4c 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -112,11 +112,7 @@ static bool acpi_pci_can_wakeup(struct pci_dev *dev) static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable) { while (bus->parent) { - struct pci_dev *bridge = bus->self; - int ret; - - ret = acpi_pm_device_sleep_wake(&bridge->dev, enable); - if (!ret || bridge->is_pcie) + if (!acpi_pm_device_sleep_wake(&bus->self->dev, enable)) return; bus = bus->parent; } @@ -131,9 +127,7 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) if (acpi_pci_can_wakeup(dev)) return acpi_pm_device_sleep_wake(&dev->dev, enable); - if (!dev->is_pcie) - acpi_pci_propagate_wakeup_enable(dev->bus, enable); - + acpi_pci_propagate_wakeup_enable(dev->bus, enable); return 0; } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 0f6382f090ee..807224ec8351 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -74,7 +74,12 @@ static ssize_t local_cpus_show(struct device *dev, const struct cpumask *mask; int len; +#ifdef CONFIG_NUMA + mask = (dev_to_node(dev) == -1) ? cpu_online_mask : + cpumask_of_node(dev_to_node(dev)); +#else mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); +#endif len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); buf[len++] = '\n'; buf[len] = '\0'; @@ -88,7 +93,12 @@ static ssize_t local_cpulist_show(struct device *dev, const struct cpumask *mask; int len; +#ifdef CONFIG_NUMA + mask = (dev_to_node(dev) == -1) ? cpu_online_mask : + cpumask_of_node(dev_to_node(dev)); +#else mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); +#endif len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); buf[len++] = '\n'; buf[len] = '\0'; @@ -176,6 +186,21 @@ numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) #endif static ssize_t +dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf (buf, "%d\n", fls64(pdev->dma_mask)); +} + +static ssize_t +consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask)); +} + +static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); @@ -306,6 +331,8 @@ struct device_attribute pci_dev_attrs[] = { #ifdef CONFIG_NUMA __ATTR_RO(numa_node), #endif + __ATTR_RO(dma_mask_bits), + __ATTR_RO(consistent_dma_mask_bits), __ATTR(enable, 0600, is_enabled_show, is_enabled_store), __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4e4c295a049f..315fea47e784 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -29,7 +29,17 @@ const char *pci_power_names[] = { }; EXPORT_SYMBOL_GPL(pci_power_names); -unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT; +unsigned int pci_pm_d3_delay; + +static void pci_dev_d3_sleep(struct pci_dev *dev) +{ + unsigned int delay = dev->d3_delay; + + if (delay < pci_pm_d3_delay) + delay = pci_pm_d3_delay; + + msleep(delay); +} #ifdef CONFIG_PCI_DOMAINS int pci_domains_supported = 1; @@ -47,6 +57,15 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; +/* + * The default CLS is used if arch didn't set CLS explicitly and not + * all pci devices agree on the same value. Arch can override either + * the dfl or actual value as it sees fit. Don't forget this is + * measured in 32-bit words, not bytes. + */ +u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2; +u8 pci_cache_line_size; + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -373,8 +392,12 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) continue; /* Wrong type */ if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) return r; /* Exact match */ - if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) - best = r; /* Approximating prefetchable by non-prefetchable */ + /* We can't insert a non-prefetch resource inside a prefetchable parent .. */ + if (r->flags & IORESOURCE_PREFETCH) + continue; + /* .. but we can put a prefetchable resource inside a non-prefetchable one */ + if (!best) + best = r; } return best; } @@ -509,7 +532,7 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) /* Mandatory power management transition delays */ /* see PCI PM 1.1 5.6.1 table 18 */ if (state == PCI_D3hot || dev->current_state == PCI_D3hot) - msleep(pci_pm_d3_delay); + pci_dev_d3_sleep(dev); else if (state == PCI_D2 || dev->current_state == PCI_D2) udelay(PCI_PM_D2_DELAY); @@ -728,8 +751,8 @@ static int pci_save_pcie_state(struct pci_dev *dev) u16 *cap; u16 flags; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); - if (pos <= 0) + pos = pci_pcie_cap(dev); + if (!pos) return 0; save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); @@ -837,7 +860,7 @@ pci_save_state(struct pci_dev *dev) int i; /* XXX: 100% dword access ok here? */ for (i = 0; i < 16; i++) - pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); + pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]); dev->state_saved = true; if ((i = pci_save_pcie_state(dev)) != 0) return i; @@ -1140,11 +1163,11 @@ pci_disable_device(struct pci_dev *dev) /** * pcibios_set_pcie_reset_state - set reset state for device dev - * @dev: the PCI-E device reset + * @dev: the PCIe device reset * @state: Reset state to enter into * * - * Sets the PCI-E reset state for the device. This is the default + * Sets the PCIe reset state for the device. This is the default * implementation. Architecture implementations can override this. */ int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev, @@ -1155,7 +1178,7 @@ int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev, /** * pci_set_pcie_reset_state - set reset state for device dev - * @dev: the PCI-E device reset + * @dev: the PCIe device reset * @state: Reset state to enter into * * @@ -1202,7 +1225,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); - dev_printk(KERN_INFO, &dev->dev, "PME# %s\n", + dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n", enable ? "enabled" : "disabled"); } @@ -1396,6 +1419,7 @@ void pci_pm_init(struct pci_dev *dev) } dev->pm_cap = pm; + dev->d3_delay = PCI_PM_D3_WAIT; dev->d1_support = false; dev->d2_support = false; @@ -1413,7 +1437,8 @@ void pci_pm_init(struct pci_dev *dev) pmc &= PCI_PM_CAP_PME_MASK; if (pmc) { - dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n", + dev_printk(KERN_DEBUG, &dev->dev, + "PME# supported from%s%s%s%s%s\n", (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "", (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", @@ -1510,7 +1535,7 @@ void pci_enable_ari(struct pci_dev *dev) u16 ctrl; struct pci_dev *bridge; - if (!dev->is_pcie || dev->devfn) + if (!pci_is_pcie(dev) || dev->devfn) return; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); @@ -1518,10 +1543,10 @@ void pci_enable_ari(struct pci_dev *dev) return; bridge = dev->bus->self; - if (!bridge || !bridge->is_pcie) + if (!bridge || !pci_is_pcie(bridge)) return; - pos = pci_find_capability(bridge, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(bridge); if (!pos) return; @@ -1536,6 +1561,54 @@ void pci_enable_ari(struct pci_dev *dev) bridge->ari_enabled = 1; } +static int pci_acs_enable; + +/** + * pci_request_acs - ask for ACS to be enabled if supported + */ +void pci_request_acs(void) +{ + pci_acs_enable = 1; +} + +/** + * pci_enable_acs - enable ACS if hardware support it + * @dev: the PCI device + */ +void pci_enable_acs(struct pci_dev *dev) +{ + int pos; + u16 cap; + u16 ctrl; + + if (!pci_acs_enable) + return; + + if (!pci_is_pcie(dev)) + return; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); + if (!pos) + return; + + pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); + pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); + + /* Source Validation */ + ctrl |= (cap & PCI_ACS_SV); + + /* P2P Request Redirect */ + ctrl |= (cap & PCI_ACS_RR); + + /* P2P Completion Redirect */ + ctrl |= (cap & PCI_ACS_CR); + + /* Upstream Forwarding */ + ctrl |= (cap & PCI_ACS_UF); + + pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); +} + /** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device @@ -1669,9 +1742,7 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_n return 0; err_out: - dev_warn(&pdev->dev, "BAR %d: can't reserve %s region %pR\n", - bar, - pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem", + dev_warn(&pdev->dev, "BAR %d: can't reserve %pR\n", bar, &pdev->resource[bar]); return -EBUSY; } @@ -1866,31 +1937,6 @@ void pci_clear_master(struct pci_dev *dev) __pci_set_master(dev, false); } -#ifdef PCI_DISABLE_MWI -int pci_set_mwi(struct pci_dev *dev) -{ - return 0; -} - -int pci_try_set_mwi(struct pci_dev *dev) -{ - return 0; -} - -void pci_clear_mwi(struct pci_dev *dev) -{ -} - -#else - -#ifndef PCI_CACHE_LINE_BYTES -#define PCI_CACHE_LINE_BYTES L1_CACHE_BYTES -#endif - -/* This can be overridden by arch code. */ -/* Don't forget this is measured in 32-bit words, not bytes */ -u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4; - /** * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed * @dev: the PCI device for which MWI is to be enabled @@ -1901,13 +1947,12 @@ u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4; * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -static int -pci_set_cacheline_size(struct pci_dev *dev) +int pci_set_cacheline_size(struct pci_dev *dev) { u8 cacheline_size; if (!pci_cache_line_size) - return -EINVAL; /* The system doesn't support MWI. */ + return -EINVAL; /* Validate current setting: the PCI_CACHE_LINE_SIZE must be equal to or multiple of the right value. */ @@ -1928,6 +1973,24 @@ pci_set_cacheline_size(struct pci_dev *dev) return -EINVAL; } +EXPORT_SYMBOL_GPL(pci_set_cacheline_size); + +#ifdef PCI_DISABLE_MWI +int pci_set_mwi(struct pci_dev *dev) +{ + return 0; +} + +int pci_try_set_mwi(struct pci_dev *dev) +{ + return 0; +} + +void pci_clear_mwi(struct pci_dev *dev) +{ +} + +#else /** * pci_set_mwi - enables memory-write-invalidate PCI transaction @@ -2062,6 +2125,7 @@ pci_set_dma_mask(struct pci_dev *dev, u64 mask) return -EIO; dev->dma_mask = mask; + dev_dbg(&dev->dev, "using %dbit DMA mask\n", fls64(mask)); return 0; } @@ -2073,6 +2137,7 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) return -EIO; dev->dev.coherent_dma_mask = mask; + dev_dbg(&dev->dev, "using %dbit consistent DMA mask\n", fls64(mask)); return 0; } @@ -2099,9 +2164,9 @@ static int pcie_flr(struct pci_dev *dev, int probe) int i; int pos; u32 cap; - u16 status; + u16 status, control; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); if (!pos) return -ENOTTY; @@ -2126,8 +2191,10 @@ static int pcie_flr(struct pci_dev *dev, int probe) "proceeding with reset anyway\n"); clear: - pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR); + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &control); + control |= PCI_EXP_DEVCTL_BCR_FLR; + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, control); + msleep(100); return 0; @@ -2191,12 +2258,12 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) csr &= ~PCI_PM_CTRL_STATE_MASK; csr |= PCI_D3hot; pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); - msleep(pci_pm_d3_delay); + pci_dev_d3_sleep(dev); csr &= ~PCI_PM_CTRL_STATE_MASK; csr |= PCI_D0; pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); - msleep(pci_pm_d3_delay); + pci_dev_d3_sleep(dev); return 0; } @@ -2240,6 +2307,10 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) down(&dev->dev.sem); } + rc = pci_dev_specific_reset(dev, probe); + if (rc != -ENOTTY) + goto done; + rc = pcie_flr(dev, probe); if (rc != -ENOTTY) goto done; @@ -2450,7 +2521,7 @@ int pcie_get_readrq(struct pci_dev *dev) int ret, cap; u16 ctl; - cap = pci_find_capability(dev, PCI_CAP_ID_EXP); + cap = pci_pcie_cap(dev); if (!cap) return -EINVAL; @@ -2480,7 +2551,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) v = (ffs(rq) - 8) << 12; - cap = pci_find_capability(dev, PCI_CAP_ID_EXP); + cap = pci_pcie_cap(dev); if (!cap) goto out; @@ -2540,7 +2611,7 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) return reg; } - dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno); + dev_err(&dev->dev, "BAR %d: invalid resource\n", resno); return 0; } @@ -2590,7 +2661,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; -spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(resource_alignment_lock); /** * pci_specified_resource_alignment - get resource alignment specified by user. @@ -2723,6 +2794,11 @@ int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev) return 1; } +void __weak pci_fixup_cardbus(struct pci_bus *bus) +{ +} +EXPORT_SYMBOL(pci_fixup_cardbus); + static int __init pci_setup(char *str) { while (str) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d92d1954a2fb..fbd0e3adbca3 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -311,4 +311,14 @@ static inline int pci_resource_alignment(struct pci_dev *dev, return resource_alignment(res); } +extern void pci_enable_acs(struct pci_dev *dev); + +struct pci_dev_reset_methods { + u16 vendor; + u16 device; + int (*reset)(struct pci_dev *dev, int probe); +}; + +extern int pci_dev_specific_reset(struct pci_dev *dev, int probe); + #endif /* DRIVERS_PCI_H */ diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug index b8c925c1f6aa..9142949734f5 100644 --- a/drivers/pci/pcie/aer/Kconfig.debug +++ b/drivers/pci/pcie/aer/Kconfig.debug @@ -3,14 +3,14 @@ # config PCIEAER_INJECT - tristate "PCIE AER error injector support" + tristate "PCIe AER error injector support" depends on PCIEAER default n help This enables PCI Express Root Port Advanced Error Reporting (AER) software error injector. - Debuging PCIE AER code is quite difficult because it is hard + Debugging PCIe AER code is quite difficult because it is hard to trigger various real hardware errors. Software based error injection can fake almost all kinds of errors with the help of a user space helper tool aer-inject, which can be diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 62d15f652bb6..223052b73563 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -1,7 +1,7 @@ /* - * PCIE AER software error injection support. + * PCIe AER software error injection support. * - * Debuging PCIE AER code is quite difficult because it is hard to + * Debuging PCIe AER code is quite difficult because it is hard to * trigger various real hardware errors. Software based error * injection can fake almost all kinds of errors with the help of a * user space helper tool aer-inject, which can be gotten from: @@ -23,6 +23,7 @@ #include <linux/pci.h> #include <linux/fs.h> #include <linux/uaccess.h> +#include <linux/stddef.h> #include "aerdrv.h" struct aer_error_inj { @@ -35,10 +36,12 @@ struct aer_error_inj { u32 header_log1; u32 header_log2; u32 header_log3; + u16 domain; }; struct aer_error { struct list_head list; + u16 domain; unsigned int bus; unsigned int devfn; int pos_cap_err; @@ -66,22 +69,27 @@ static LIST_HEAD(pci_bus_ops_list); /* Protect einjected and pci_bus_ops_list */ static DEFINE_SPINLOCK(inject_lock); -static void aer_error_init(struct aer_error *err, unsigned int bus, - unsigned int devfn, int pos_cap_err) +static void aer_error_init(struct aer_error *err, u16 domain, + unsigned int bus, unsigned int devfn, + int pos_cap_err) { INIT_LIST_HEAD(&err->list); + err->domain = domain; err->bus = bus; err->devfn = devfn; err->pos_cap_err = pos_cap_err; } /* inject_lock must be held before calling */ -static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) +static struct aer_error *__find_aer_error(u16 domain, unsigned int bus, + unsigned int devfn) { struct aer_error *err; list_for_each_entry(err, &einjected, list) { - if (bus == err->bus && devfn == err->devfn) + if (domain == err->domain && + bus == err->bus && + devfn == err->devfn) return err; } return NULL; @@ -90,7 +98,10 @@ static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) /* inject_lock must be held before calling */ static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) { - return __find_aer_error(dev->bus->number, dev->devfn); + int domain = pci_domain_nr(dev->bus); + if (domain < 0) + return NULL; + return __find_aer_error((u16)domain, dev->bus->number, dev->devfn); } /* inject_lock must be held before calling */ @@ -172,11 +183,15 @@ static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where, struct aer_error *err; unsigned long flags; struct pci_ops *ops; + int domain; spin_lock_irqsave(&inject_lock, flags); if (size != sizeof(u32)) goto out; - err = __find_aer_error(bus->number, devfn); + domain = pci_domain_nr(bus); + if (domain < 0) + goto out; + err = __find_aer_error((u16)domain, bus->number, devfn); if (!err) goto out; @@ -200,11 +215,15 @@ int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, unsigned long flags; int rw1cs; struct pci_ops *ops; + int domain; spin_lock_irqsave(&inject_lock, flags); if (size != sizeof(u32)) goto out; - err = __find_aer_error(bus->number, devfn); + domain = pci_domain_nr(bus); + if (domain < 0) + goto out; + err = __find_aer_error((u16)domain, bus->number, devfn); if (!err) goto out; @@ -262,7 +281,7 @@ out: static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) { while (1) { - if (!dev->is_pcie) + if (!pci_is_pcie(dev)) break; if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) return dev; @@ -302,28 +321,31 @@ static int aer_inject(struct aer_error_inj *einj) unsigned long flags; unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); int pos_cap_err, rp_pos_cap_err; - u32 sever; + u32 sever, cor_mask, uncor_mask; int ret = 0; - dev = pci_get_bus_and_slot(einj->bus, devfn); + dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); if (!dev) - return -EINVAL; + return -ENODEV; rpdev = pcie_find_root_port(dev); if (!rpdev) { - ret = -EINVAL; + ret = -ENOTTY; goto out_put; } pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (!pos_cap_err) { - ret = -EIO; + ret = -ENOTTY; goto out_put; } pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask); + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, + &uncor_mask); rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); if (!rp_pos_cap_err) { - ret = -EIO; + ret = -ENOTTY; goto out_put; } @@ -344,7 +366,8 @@ static int aer_inject(struct aer_error_inj *einj) if (!err) { err = err_alloc; err_alloc = NULL; - aer_error_init(err, einj->bus, devfn, pos_cap_err); + aer_error_init(err, einj->domain, einj->bus, devfn, + pos_cap_err); list_add(&err->list, &einjected); } err->uncor_status |= einj->uncor_status; @@ -354,11 +377,27 @@ static int aer_inject(struct aer_error_inj *einj) err->header_log2 = einj->header_log2; err->header_log3 = einj->header_log3; + if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { + ret = -EINVAL; + printk(KERN_WARNING "The correctable error(s) is masked " + "by device\n"); + spin_unlock_irqrestore(&inject_lock, flags); + goto out_put; + } + if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { + ret = -EINVAL; + printk(KERN_WARNING "The uncorrectable error(s) is masked " + "by device\n"); + spin_unlock_irqrestore(&inject_lock, flags); + goto out_put; + } + rperr = __find_aer_error_by_dev(rpdev); if (!rperr) { rperr = rperr_alloc; rperr_alloc = NULL; - aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, + aer_error_init(rperr, pci_domain_nr(rpdev->bus), + rpdev->bus->number, rpdev->devfn, rp_pos_cap_err); list_add(&rperr->list, &einjected); } @@ -392,8 +431,14 @@ static int aer_inject(struct aer_error_inj *einj) if (ret) goto out_put; - if (find_aer_device(rpdev, &edev)) + if (find_aer_device(rpdev, &edev)) { + if (!get_service_data(edev)) { + printk(KERN_WARNING "AER service is not initialized\n"); + ret = -EINVAL; + goto out_put; + } aer_irq(-1, edev); + } else ret = -EINVAL; out_put: @@ -411,10 +456,11 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - - if (usize != sizeof(struct aer_error_inj)) + if (usize < offsetof(struct aer_error_inj, domain) || + usize > sizeof(einj)) return -EINVAL; + memset(&einj, 0, sizeof(einj)); if (copy_from_user(&einj, ubuf, usize)) return -EFAULT; @@ -452,7 +498,7 @@ static void __exit aer_inject_exit(void) } spin_lock_irqsave(&inject_lock, flags); - list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { + list_for_each_entry_safe(err, err_next, &einjected, list) { list_del(&err->list); kfree(err); } @@ -462,5 +508,5 @@ static void __exit aer_inject_exit(void) module_init(aer_inject_init); module_exit(aer_inject_exit); -MODULE_DESCRIPTION("PCIE AER software error injector"); +MODULE_DESCRIPTION("PCIe AER software error injector"); MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 40c3cc5d1caf..21f215f4daa3 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -53,7 +53,7 @@ static struct pci_error_handlers aer_error_handlers = { static struct pcie_port_service_driver aerdriver = { .name = "aer", - .port_type = PCIE_RC_PORT, + .port_type = PCI_EXP_TYPE_ROOT_PORT, .service = PCIE_PORT_SERVICE_AER, .probe = aer_probe, @@ -155,7 +155,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) mutex_init(&rpc->rpc_mutex); init_waitqueue_head(&rpc->wait_release); - /* Use PCIE bus function to store rpc into PCIE device */ + /* Use PCIe bus function to store rpc into PCIe device */ set_service_data(dev, rpc); return rpc; @@ -295,7 +295,7 @@ static void aer_error_resume(struct pci_dev *dev) u16 reg16; /* Clean up Root device status */ - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 8edb2f300e8f..04814087658d 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -24,7 +24,7 @@ * * @return: Zero on success. Nonzero otherwise. * - * Invoked when PCIE bus loads AER service driver. To avoid conflict with + * Invoked when PCIe bus loads AER service driver. To avoid conflict with * BIOS AER support requires BIOS to yield AER control to OS native driver. **/ int aer_osc_setup(struct pcie_device *pciedev) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 9f5ccbeb4fa5..c843a799814d 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -35,11 +35,14 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev) u16 reg16 = 0; int pos; + if (dev->aer_firmware_first) + return -EIO; + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (!pos) return -EIO; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); if (!pos) return -EIO; @@ -60,7 +63,10 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev) u16 reg16 = 0; int pos; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (dev->aer_firmware_first) + return -EIO; + + pos = pci_pcie_cap(dev); if (!pos) return -EIO; @@ -78,48 +84,27 @@ EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) { int pos; - u32 status, mask; + u32 status; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (!pos) return -EIO; pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); - if (dev->error_state == pci_channel_io_normal) - status &= ~mask; /* Clear corresponding nonfatal bits */ - else - status &= mask; /* Clear corresponding fatal bits */ - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); + if (status) + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); return 0; } EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); -#if 0 -int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) -{ - int pos; - u32 status; - - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); - if (!pos) - return -EIO; - - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); - pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); - - return 0; -} -#endif /* 0 */ - static int set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); - if (dev->pcie_type == PCIE_RC_PORT || - dev->pcie_type == PCIE_SW_UPSTREAM_PORT || - dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) { + if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) || + (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) || + (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) { if (enable) pci_enable_pcie_error_reporting(dev); else @@ -218,7 +203,7 @@ static int find_device_iter(struct pci_dev *dev, void *data) */ if (atomic_read(&dev->enable_cnt) == 0) return 0; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); if (!pos) return 0; /* Check if AER is enabled */ @@ -431,10 +416,9 @@ static int find_aer_service_iter(struct device *device, void *data) result = (struct find_aer_service_data *) data; if (device->bus == &pcie_port_bus_type) { - struct pcie_port_data *port_data; + struct pcie_device *pcie = to_pcie_device(device); - port_data = pci_get_drvdata(to_pcie_device(device)->port); - if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT) + if (pcie->port->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) result->is_downstream = 1; driver = device->driver; @@ -603,7 +587,7 @@ static void handle_error_source(struct pcie_device *aerdev, * aer_enable_rootport - enable Root Port's interrupts when receiving messages * @rpc: pointer to a Root Port data structure * - * Invoked when PCIE bus loads AER service driver. + * Invoked when PCIe bus loads AER service driver. */ void aer_enable_rootport(struct aer_rpc *rpc) { @@ -612,8 +596,8 @@ void aer_enable_rootport(struct aer_rpc *rpc) u16 reg16; u32 reg32; - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - /* Clear PCIE Capability's Device Status */ + pos = pci_pcie_cap(pdev); + /* Clear PCIe Capability's Device Status */ pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); @@ -647,7 +631,7 @@ void aer_enable_rootport(struct aer_rpc *rpc) * disable_root_aer - disable Root Port's interrupts when receiving messages * @rpc: pointer to a Root Port data structure * - * Invoked when PCIE bus unloads AER service driver. + * Invoked when PCIe bus unloads AER service driver. */ static void disable_root_aer(struct aer_rpc *rpc) { @@ -874,8 +858,22 @@ void aer_delete_rootport(struct aer_rpc *rpc) */ int aer_init(struct pcie_device *dev) { - if (aer_osc_setup(dev) && !forceload) - return -ENXIO; + if (dev->port->aer_firmware_first) { + dev_printk(KERN_DEBUG, &dev->device, + "PCIe errors handled by platform firmware.\n"); + goto out; + } + + if (aer_osc_setup(dev)) + goto out; return 0; +out: + if (forceload) { + dev_printk(KERN_DEBUG, &dev->device, + "aerdrv forceload requested.\n"); + dev->port->aer_firmware_first = 0; + return 0; + } + return -ENXIO; } diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 44acde72294f..9d3e4c8d0184 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -184,7 +184,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) if (info->status == 0) { AER_PR(info, dev, - "PCIE Bus Error: severity=%s, type=Unaccessible, " + "PCIe Bus Error: severity=%s, type=Unaccessible, " "id=%04x(Unregistered Agent ID)\n", aer_error_severity_string[info->severity], id); } else { @@ -194,7 +194,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) agent = AER_GET_AGENT(info->severity, info->status); AER_PR(info, dev, - "PCIE Bus Error: severity=%s, type=%s, id=%04x(%s)\n", + "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", aer_error_severity_string[info->severity], aer_error_layer[layer], id, aer_agent_string[agent]); diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c index a928d8ab6bda..a2747a663bc9 100644 --- a/drivers/pci/pcie/aer/ecrc.c +++ b/drivers/pci/pcie/aer/ecrc.c @@ -51,7 +51,7 @@ static int enable_ecrc_checking(struct pci_dev *dev) int pos; u32 reg32; - if (!dev->is_pcie) + if (!pci_is_pcie(dev)) return -ENODEV; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); @@ -79,7 +79,7 @@ static int disable_ecrc_checking(struct pci_dev *dev) int pos; u32 reg32; - if (!dev->is_pcie) + if (!pci_is_pcie(dev)) return -ENODEV; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 5b7056cec00c..be53d98fa384 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1,6 +1,6 @@ /* * File: drivers/pci/pcie/aspm.c - * Enabling PCIE link L0s/L1 state and Clock Power Management + * Enabling PCIe link L0s/L1 state and Clock Power Management * * Copyright (C) 2007 Intel * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) @@ -122,7 +122,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) struct pci_bus *linkbus = link->pdev->subordinate; list_for_each_entry(child, &linkbus->devices, bus_list) { - pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(child); if (!pos) return; pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); @@ -156,7 +156,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) /* All functions should have the same cap and state, take the worst */ list_for_each_entry(child, &linkbus->devices, bus_list) { - pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(child); if (!pos) return; pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); @@ -191,23 +191,23 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) * Configuration, so just check one function */ child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); - BUG_ON(!child->is_pcie); + BUG_ON(!pci_is_pcie(child)); /* Check downstream component if bit Slot Clock Configuration is 1 */ - cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + cpos = pci_pcie_cap(child); pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Check upstream component if bit Slot Clock Configuration is 1 */ - ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); + ppos = pci_pcie_cap(parent); pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Configure downstream component, all functions */ list_for_each_entry(child, &linkbus->devices, bus_list) { - cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + cpos = pci_pcie_cap(child); pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); child_reg[PCI_FUNC(child->devfn)] = reg16; if (same_clock) @@ -247,7 +247,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) dev_printk(KERN_ERR, &parent->dev, "ASPM: Could not configure common clock\n"); list_for_each_entry(child, &linkbus->devices, bus_list) { - cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + cpos = pci_pcie_cap(child); pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, child_reg[PCI_FUNC(child->devfn)]); } @@ -300,7 +300,7 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev, u16 reg16; u32 reg32; - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(pdev); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; @@ -420,7 +420,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) child->pcie_type != PCI_EXP_TYPE_LEG_END) continue; - pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(child); pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); /* Calculate endpoint L0s acceptable latency */ encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; @@ -436,7 +436,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) { u16 reg16; - int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + int pos = pci_pcie_cap(pdev); pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); reg16 &= ~0x3; @@ -499,11 +499,11 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) int pos; u32 reg32; /* - * Some functions in a slot might not all be PCIE functions, + * Some functions in a slot might not all be PCIe functions, * very strange. Disable ASPM for the whole slot */ list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(child); if (!pos) return -EINVAL; /* @@ -563,7 +563,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) struct pcie_link_state *link; int blacklist = !!pcie_aspm_sanity_check(pdev); - if (aspm_disabled || !pdev->is_pcie || pdev->link_state) + if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) return; if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) @@ -629,7 +629,8 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link, *root, *parent_link; - if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) + if (aspm_disabled || !pci_is_pcie(pdev) || + !parent || !parent->link_state) return; if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) @@ -670,7 +671,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) { struct pcie_link_state *link = pdev->link_state; - if (aspm_disabled || !pdev->is_pcie || !link) + if (aspm_disabled || !pci_is_pcie(pdev) || !link) return; if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) @@ -696,7 +697,7 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link; - if (aspm_disabled || !pdev->is_pcie) + if (aspm_disabled || !pci_is_pcie(pdev)) return; if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) @@ -841,8 +842,9 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { struct pcie_link_state *link_state = pdev->link_state; - if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && - pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) + if (!pci_is_pcie(pdev) || + (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; if (link_state->aspm_support) @@ -857,8 +859,9 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { struct pcie_link_state *link_state = pdev->link_state; - if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && - pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) + if (!pci_is_pcie(pdev) || + (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; if (link_state->aspm_support) diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 17ad53868f9f..aaeb9d21cba5 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -11,31 +11,16 @@ #include <linux/compiler.h> -#if !defined(PCI_CAP_ID_PME) -#define PCI_CAP_ID_PME 1 -#endif - -#if !defined(PCI_CAP_ID_EXP) -#define PCI_CAP_ID_EXP 0x10 -#endif - -#define PORT_TYPE_MASK 0xf -#define PORT_TO_SLOT_MASK 0x100 -#define SLOT_HP_CAPABLE_MASK 0x40 -#define PCIE_CAPABILITIES_REG 0x2 -#define PCIE_SLOT_CAPABILITIES_REG 0x14 -#define PCIE_PORT_DEVICE_MAXSERVICES 4 -#define PCIE_PORT_MSI_VECTOR_MASK 0x1f +#define PCIE_PORT_DEVICE_MAXSERVICES 4 /* - * According to the PCI Express Base Specification 2.0, the indices of the MSI-X - * table entires used by port services must not exceed 31 + * According to the PCI Express Base Specification 2.0, the indices of + * the MSI-X table entires used by port services must not exceed 31 */ #define PCIE_PORT_MAX_MSIX_ENTRIES 32 #define get_descriptor_id(type, service) (((type - 4) << 4) | service) extern struct bus_type pcie_port_bus_type; -extern int pcie_port_device_probe(struct pci_dev *dev); extern int pcie_port_device_register(struct pci_dev *dev); #ifdef CONFIG_PM extern int pcie_port_device_suspend(struct device *dev); diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c index ef3a4eeaebb4..18bf90f748f6 100644 --- a/drivers/pci/pcie/portdrv_bus.c +++ b/drivers/pci/pcie/portdrv_bus.c @@ -26,7 +26,6 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type); static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) { struct pcie_device *pciedev; - struct pcie_port_data *port_data; struct pcie_port_service_driver *driver; if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) @@ -38,10 +37,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) if (driver->service != pciedev->service) return 0; - port_data = pci_get_drvdata(pciedev->port); - - if (driver->port_type != PCIE_ANY_PORT - && driver->port_type != port_data->port_type) + if ((driver->port_type != PCIE_ANY_PORT) && + (driver->port_type != pciedev->port->pcie_type)) return 0; return 1; diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 52f84fca9f7d..b174188ac121 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -27,7 +27,7 @@ */ static void release_pcie_device(struct device *dev) { - kfree(to_pcie_device(dev)); + kfree(to_pcie_device(dev)); } /** @@ -108,9 +108,9 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) * the value in this field indicates which MSI-X Table entry is * used to generate the interrupt message." */ - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); - pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); - entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK; + pos = pci_pcie_cap(dev); + pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); + entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9; if (entry >= nr_entries) goto Error; @@ -177,37 +177,40 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) } /** - * assign_interrupt_mode - choose interrupt mode for PCI Express port services - * (INTx, MSI-X, MSI) and set up vectors + * init_service_irqs - initialize irqs for PCI Express port services * @dev: PCI Express port to handle - * @vectors: Array of interrupt vectors to populate + * @irqs: Array of irqs to populate * @mask: Bitmask of port capabilities returned by get_port_device_capability() * * Return value: Interrupt mode associated with the port */ -static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) +static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) { - int irq, interrupt_mode = PCIE_PORT_NO_IRQ; - int i; + int i, irq; /* Try to use MSI-X if supported */ - if (!pcie_port_enable_msix(dev, vectors, mask)) - return PCIE_PORT_MSIX_MODE; - + if (!pcie_port_enable_msix(dev, irqs, mask)) + return 0; /* We're not going to use MSI-X, so try MSI and fall back to INTx */ - if (!pci_enable_msi(dev)) - interrupt_mode = PCIE_PORT_MSI_MODE; - - if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin) - interrupt_mode = PCIE_PORT_INTx_MODE; + irq = -1; + if (!pci_enable_msi(dev) || dev->pin) + irq = dev->irq; - irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1; for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) - vectors[i] = irq; + irqs[i] = irq; + irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1; - vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1; + if (irq < 0) + return -ENODEV; + return 0; +} - return interrupt_mode; +static void cleanup_service_irqs(struct pci_dev *dev) +{ + if (dev->msix_enabled) + pci_disable_msix(dev); + else if (dev->msi_enabled) + pci_disable_msi(dev); } /** @@ -226,13 +229,12 @@ static int get_port_device_capability(struct pci_dev *dev) u16 reg16; u32 reg32; - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); - pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); + pos = pci_pcie_cap(dev); + pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); /* Hot-Plug Capable */ - if (reg16 & PORT_TO_SLOT_MASK) { - pci_read_config_dword(dev, - pos + PCIE_SLOT_CAPABILITIES_REG, ®32); - if (reg32 & SLOT_HP_CAPABLE_MASK) + if (reg16 & PCI_EXP_FLAGS_SLOT) { + pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); + if (reg32 & PCI_EXP_SLTCAP_HPC) services |= PCIE_PORT_SERVICE_HP; } /* AER capable */ @@ -241,80 +243,47 @@ static int get_port_device_capability(struct pci_dev *dev) /* VC support */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) services |= PCIE_PORT_SERVICE_VC; + /* Root ports are capable of generating PME too */ + if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + services |= PCIE_PORT_SERVICE_PME; return services; } /** - * pcie_device_init - initialize PCI Express port service device - * @dev: Port service device to initialize - * @parent: PCI Express port to associate the service device with - * @port_type: Type of the port - * @service_type: Type of service to associate with the service device + * pcie_device_init - allocate and initialize PCI Express port service device + * @pdev: PCI Express port to associate the service device with + * @service: Type of service to associate with the service device * @irq: Interrupt vector to associate with the service device */ -static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, - int service_type, int irq) +static int pcie_device_init(struct pci_dev *pdev, int service, int irq) { - struct pcie_port_data *port_data = pci_get_drvdata(parent); + int retval; + struct pcie_device *pcie; struct device *device; - int port_type = port_data->port_type; - dev->port = parent; - dev->irq = irq; - dev->service = service_type; + pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + pcie->port = pdev; + pcie->irq = irq; + pcie->service = service; /* Initialize generic device interface */ - device = &dev->device; - memset(device, 0, sizeof(struct device)); + device = &pcie->device; device->bus = &pcie_port_bus_type; - device->driver = NULL; - dev_set_drvdata(device, NULL); device->release = release_pcie_device; /* callback to free pcie dev */ dev_set_name(device, "%s:pcie%02x", - pci_name(parent), get_descriptor_id(port_type, service_type)); - device->parent = &parent->dev; -} - -/** - * alloc_pcie_device - allocate PCI Express port service device structure - * @parent: PCI Express port to associate the service device with - * @port_type: Type of the port - * @service_type: Type of service to associate with the service device - * @irq: Interrupt vector to associate with the service device - */ -static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, - int service_type, int irq) -{ - struct pcie_device *device; - - device = kzalloc(sizeof(struct pcie_device), GFP_KERNEL); - if (!device) - return NULL; - - pcie_device_init(parent, device, service_type, irq); - return device; -} - -/** - * pcie_port_device_probe - check if device is a PCI Express port - * @dev: Device to check - */ -int pcie_port_device_probe(struct pci_dev *dev) -{ - int pos, type; - u16 reg; - - if (!(pos = pci_find_capability(dev, PCI_CAP_ID_EXP))) - return -ENODEV; - - pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); - type = (reg >> 4) & PORT_TYPE_MASK; - if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || - type == PCIE_SW_DOWNSTREAM_PORT ) - return 0; - - return -ENODEV; + pci_name(pdev), + get_descriptor_id(pdev->pcie_type, service)); + device->parent = &pdev->dev; + + retval = device_register(device); + if (retval) + kfree(pcie); + else + get_device(device); + return retval; } /** @@ -326,77 +295,49 @@ int pcie_port_device_probe(struct pci_dev *dev) */ int pcie_port_device_register(struct pci_dev *dev) { - struct pcie_port_data *port_data; - int status, capabilities, irq_mode, i, nr_serv; - int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; - u16 reg16; - - port_data = kzalloc(sizeof(*port_data), GFP_KERNEL); - if (!port_data) - return -ENOMEM; - pci_set_drvdata(dev, port_data); - - /* Get port type */ - pci_read_config_word(dev, - pci_find_capability(dev, PCI_CAP_ID_EXP) + - PCIE_CAPABILITIES_REG, ®16); - port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK; + int status, capabilities, i, nr_service; + int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; + /* Get and check PCI Express port services */ capabilities = get_port_device_capability(dev); - /* Root ports are capable of generating PME too */ - if (port_data->port_type == PCIE_RC_PORT) - capabilities |= PCIE_PORT_SERVICE_PME; - - irq_mode = assign_interrupt_mode(dev, vectors, capabilities); - if (irq_mode == PCIE_PORT_NO_IRQ) { - /* - * Don't use service devices that require interrupts if there is - * no way to generate them. - */ - if (!(capabilities & PCIE_PORT_SERVICE_VC)) { - status = -ENODEV; - goto Error; - } - capabilities = PCIE_PORT_SERVICE_VC; - } - port_data->port_irq_mode = irq_mode; + if (!capabilities) + return -ENODEV; + /* Enable PCI Express port device */ status = pci_enable_device(dev); if (status) - goto Error; + return status; pci_set_master(dev); + /* + * Initialize service irqs. Don't use service devices that + * require interrupts if there is no way to generate them. + */ + status = init_service_irqs(dev, irqs, capabilities); + if (status) { + capabilities &= PCIE_PORT_SERVICE_VC; + if (!capabilities) + goto error_disable; + } /* Allocate child services if any */ - for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { - struct pcie_device *child; + status = -ENODEV; + nr_service = 0; + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { int service = 1 << i; - if (!(capabilities & service)) continue; - - child = alloc_pcie_device(dev, service, vectors[i]); - if (!child) - continue; - - status = device_register(&child->device); - if (status) { - kfree(child); - continue; - } - - get_device(&child->device); - nr_serv++; - } - if (!nr_serv) { - pci_disable_device(dev); - status = -ENODEV; - goto Error; + if (!pcie_device_init(dev, service, irqs[i])) + nr_service++; } + if (!nr_service) + goto error_cleanup_irqs; return 0; - Error: - kfree(port_data); +error_cleanup_irqs: + cleanup_service_irqs(dev); +error_disable: + pci_disable_device(dev); return status; } @@ -405,12 +346,11 @@ static int suspend_iter(struct device *dev, void *data) { struct pcie_port_service_driver *service_driver; - if ((dev->bus == &pcie_port_bus_type) && - (dev->driver)) { - service_driver = to_service_driver(dev->driver); - if (service_driver->suspend) - service_driver->suspend(to_pcie_device(dev)); - } + if ((dev->bus == &pcie_port_bus_type) && dev->driver) { + service_driver = to_service_driver(dev->driver); + if (service_driver->suspend) + service_driver->suspend(to_pcie_device(dev)); + } return 0; } @@ -464,21 +404,9 @@ static int remove_iter(struct device *dev, void *data) */ void pcie_port_device_remove(struct pci_dev *dev) { - struct pcie_port_data *port_data = pci_get_drvdata(dev); - device_for_each_child(&dev->dev, NULL, remove_iter); + cleanup_service_irqs(dev); pci_disable_device(dev); - - switch (port_data->port_irq_mode) { - case PCIE_PORT_MSIX_MODE: - pci_disable_msix(dev); - break; - case PCIE_PORT_MSI_MODE: - pci_disable_msi(dev); - break; - } - - kfree(port_data); } /** @@ -565,6 +493,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) return driver_register(&new->driver); } +EXPORT_SYMBOL(pcie_port_service_register); /** * pcie_port_service_unregister - unregister PCI Express port service driver @@ -574,6 +503,4 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *drv) { driver_unregister(&drv->driver); } - -EXPORT_SYMBOL(pcie_port_service_register); EXPORT_SYMBOL(pcie_port_service_unregister); diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f635e476d632..13c8972886e6 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -24,7 +24,7 @@ */ #define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "tom.l.nguyen@intel.com" -#define DRIVER_DESC "PCIE Port Bus Driver" +#define DRIVER_DESC "PCIe Port Bus Driver" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); @@ -43,7 +43,7 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) } #ifdef CONFIG_PM -static struct dev_pm_ops pcie_portdrv_pm_ops = { +static const struct dev_pm_ops pcie_portdrv_pm_ops = { .suspend = pcie_port_device_suspend, .resume = pcie_port_device_resume, .freeze = pcie_port_device_suspend, @@ -63,20 +63,22 @@ static struct dev_pm_ops pcie_portdrv_pm_ops = { * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed * - * If detected invokes the pcie_port_device_register() method for + * If detected invokes the pcie_port_device_register() method for * this port device. * */ -static int __devinit pcie_portdrv_probe (struct pci_dev *dev, - const struct pci_device_id *id ) +static int __devinit pcie_portdrv_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int status; + int status; - status = pcie_port_device_probe(dev); - if (status) - return status; + if (!pci_is_pcie(dev) || + ((dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && + (dev->pcie_type != PCI_EXP_TYPE_UPSTREAM) && + (dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))) + return -ENODEV; - if (!dev->irq && dev->pin) { + if (!dev->irq && dev->pin) { dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " "check vendor BIOS\n", dev->vendor, dev->device); } @@ -89,7 +91,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, return 0; } -static void pcie_portdrv_remove (struct pci_dev *dev) +static void pcie_portdrv_remove(struct pci_dev *dev) { pcie_port_device_remove(dev); pci_disable_device(dev); @@ -127,14 +129,13 @@ static int error_detected_iter(struct device *device, void *data) static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, enum pci_channel_state error) { - struct aer_broadcast_data result_data = - {error, PCI_ERS_RESULT_CAN_RECOVER}; - int retval; + struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER}; + int ret; /* can not fail */ - retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); + ret = device_for_each_child(&dev->dev, &data, error_detected_iter); - return result_data.result; + return data.result; } static int mmio_enabled_iter(struct device *device, void *data) @@ -288,7 +289,7 @@ static int __init pcie_portdrv_init(void) return retval; } -static void __exit pcie_portdrv_exit(void) +static void __exit pcie_portdrv_exit(void) { pci_unregister_driver(&pcie_portdriver); pcie_port_bus_unregister(); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8105e32117f6..446e4a94d7d3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/cpumask.h> #include <linux/pci-aspm.h> +#include <acpi/acpi_hest.h> #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -163,12 +164,12 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, { u32 l, sz, mask; - mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0; + mask = type ? PCI_ROM_ADDRESS_MASK : ~0; res->name = pci_name(dev); pci_read_config_dword(dev, pos, &l); - pci_write_config_dword(dev, pos, mask); + pci_write_config_dword(dev, pos, l | mask); pci_read_config_dword(dev, pos, &sz); pci_write_config_dword(dev, pos, l); @@ -223,9 +224,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto fail; if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { - dev_err(&dev->dev, "can't handle 64-bit BAR\n"); + dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", + pos); goto fail; - } else if ((sizeof(resource_size_t) < 8) && l) { + } + + res->flags |= IORESOURCE_MEM_64; + if ((sizeof(resource_size_t) < 8) && l) { /* Address above 32-bit boundary; disable the BAR */ pci_write_config_dword(dev, pos, 0); pci_write_config_dword(dev, pos + 4, 0); @@ -234,14 +239,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } else { res->start = l64; res->end = l64 + sz64; - dev_printk(KERN_DEBUG, &dev->dev, - "reg %x %s: %pR\n", pos, - (res->flags & IORESOURCE_PREFETCH) ? - "64bit mmio pref" : "64bit mmio", - res); + dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", + pos, res); } - - res->flags |= IORESOURCE_MEM_64; } else { sz = pci_size(l, sz, mask); @@ -251,11 +251,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->start = l; res->end = l + sz; - dev_printk(KERN_DEBUG, &dev->dev, "reg %x %s: %pR\n", pos, - (res->flags & IORESOURCE_IO) ? "io port" : - ((res->flags & IORESOURCE_PREFETCH) ? - "32bit mmio pref" : "32bit mmio"), - res); + dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); } out: @@ -297,8 +293,11 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ return; + dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n", + child->secondary, child->subordinate, + dev->transparent ? " (subtractive decode)": ""); + if (dev->transparent) { - dev_info(&dev->dev, "transparent bridge\n"); for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) child->resource[i] = child->parent->resource[i - 3]; } @@ -323,7 +322,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) res->start = base; if (!res->end) res->end = limit + 0xfff; - dev_printk(KERN_DEBUG, &dev->dev, "bridge io port: %pR\n", res); + dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } res = child->resource[1]; @@ -335,8 +334,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->start = base; res->end = limit + 0xfffff; - dev_printk(KERN_DEBUG, &dev->dev, "bridge 32bit mmio: %pR\n", - res); + dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } res = child->resource[2]; @@ -375,9 +373,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) res->flags |= IORESOURCE_MEM_64; res->start = base; res->end = limit + 0xfffff; - dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n", - (res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32", - res); + dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } } @@ -651,13 +647,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, (child->number > bus->subordinate) || (child->number < bus->number) || (child->subordinate < bus->number)) { - pr_debug("PCI: Bus #%02x (-#%02x) is %s " - "hidden behind%s bridge #%02x (-#%02x)\n", + dev_info(&child->dev, "[bus %02x-%02x] %s " + "hidden behind%s bridge %s [bus %02x-%02x]\n", child->number, child->subordinate, (bus->number > child->subordinate && bus->subordinate < child->number) ? "wholly" : "partially", bus->self->transparent ? " transparent" : "", + dev_name(&bus->dev), bus->number, bus->subordinate); } bus = bus->parent; @@ -684,7 +681,7 @@ static void pci_read_irq(struct pci_dev *dev) dev->irq = irq; } -static void set_pcie_port_type(struct pci_dev *pdev) +void set_pcie_port_type(struct pci_dev *pdev) { int pos; u16 reg16; @@ -693,17 +690,18 @@ static void set_pcie_port_type(struct pci_dev *pdev) if (!pos) return; pdev->is_pcie = 1; + pdev->pcie_cap = pos; pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; } -static void set_pcie_hotplug_bridge(struct pci_dev *pdev) +void set_pcie_hotplug_bridge(struct pci_dev *pdev) { int pos; u16 reg16; u32 reg32; - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(pdev); if (!pos) return; pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); @@ -714,6 +712,12 @@ static void set_pcie_hotplug_bridge(struct pci_dev *pdev) pdev->is_hotplug_bridge = 1; } +static void set_pci_aer_firmware_first(struct pci_dev *pdev) +{ + if (acpi_hest_firmware_first_pci(pdev)) + pdev->aer_firmware_first = 1; +} + #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) /** @@ -731,6 +735,7 @@ int pci_setup_device(struct pci_dev *dev) u32 class; u8 hdr_type; struct pci_slot *slot; + int pos = 0; if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) return -EIO; @@ -742,6 +747,7 @@ int pci_setup_device(struct pci_dev *dev) dev->multifunction = !!(hdr_type & 0x80); dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); + set_pci_aer_firmware_first(dev); list_for_each_entry(slot, &dev->bus->slots, list) if (PCI_SLOT(dev->devfn) == slot->number) @@ -822,6 +828,11 @@ int pci_setup_device(struct pci_dev *dev) dev->transparent = ((dev->class & 0xff) == 1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); set_pcie_hotplug_bridge(dev); + pos = pci_find_capability(dev, PCI_CAP_ID_SSVID); + if (pos) { + pci_read_config_word(dev, pos + PCI_SSVID_VENDOR_ID, &dev->subsystem_vendor); + pci_read_config_word(dev, pos + PCI_SSVID_DEVICE_ID, &dev->subsystem_device); + } break; case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ @@ -907,7 +918,7 @@ int pci_cfg_space_size(struct pci_dev *dev) if (class == PCI_CLASS_BRIDGE_HOST) return pci_cfg_space_size_ext(dev); - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(dev); if (!pos) { pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!pos) @@ -1014,6 +1025,9 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Single Root I/O Virtualization */ pci_iov_init(dev); + + /* Enable ACS P2P upstream forwarding */ + pci_enable_acs(dev); } void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) @@ -1110,7 +1124,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) unsigned int devfn, pass, max = bus->secondary; struct pci_dev *dev; - pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number); + dev_dbg(&bus->dev, "scanning bus\n"); /* Go find them, Rover! */ for (devfn = 0; devfn < 0x100; devfn += 8) @@ -1124,8 +1138,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) * all PCI-to-PCI bridges on this bus. */ if (!bus->is_added) { - pr_debug("PCI: Fixups for bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + dev_dbg(&bus->dev, "fixups for bus\n"); pcibios_fixup_bus(bus); if (pci_is_root_bus(bus)) bus->is_added = 1; @@ -1145,8 +1158,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) * * Return how far we've got finding sub-buses. */ - pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n", - pci_domain_nr(bus), bus->number, max); + dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max); return max; } @@ -1154,7 +1166,7 @@ struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { int error; - struct pci_bus *b; + struct pci_bus *b, *b2; struct device *dev; b = pci_alloc_bus(); @@ -1170,9 +1182,10 @@ struct pci_bus * pci_create_bus(struct device *parent, b->sysdata = sysdata; b->ops = ops; - if (pci_find_bus(pci_domain_nr(b), bus)) { + b2 = pci_find_bus(pci_domain_nr(b), bus); + if (b2) { /* If we already got to this bus through a different bridge, ignore it */ - pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); + dev_dbg(&b2->dev, "bus already known\n"); goto err_out; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 245d2cdb4765..c74694345b6e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -357,7 +357,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, pcibios_bus_to_resource(dev, res, &bus_region); pci_claim_resource(dev, nr); - dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); + dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name); } } @@ -1680,6 +1680,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_ */ #define AMD_813X_MISC 0x40 #define AMD_813X_NOIOAMODE (1<<0) +#define AMD_813X_REV_B1 0x12 #define AMD_813X_REV_B2 0x13 static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) @@ -1688,7 +1689,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) if (noioapicquirk) return; - if (dev->revision == AMD_813X_REV_B2) + if ((dev->revision == AMD_813X_REV_B1) || + (dev->revision == AMD_813X_REV_B2)) return; pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); @@ -1698,8 +1700,10 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) dev_info(&dev->dev, "disabled boot interrupts on device [%04x:%04x]\n", dev->vendor, dev->device); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); #define AMD_8111_PCI_IRQ_ROUTING 0x56 @@ -2595,16 +2599,116 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) static int __init pci_apply_final_quirks(void) { struct pci_dev *dev = NULL; + u8 cls = 0; + u8 tmp; + + if (pci_cache_line_size) + printk(KERN_DEBUG "PCI: CLS %u bytes\n", + pci_cache_line_size << 2); while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_fixup_device(pci_fixup_final, dev); + /* + * If arch hasn't set it explicitly yet, use the CLS + * value shared by all PCI devices. If there's a + * mismatch, fall back to the default value. + */ + if (!pci_cache_line_size) { + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp); + if (!cls) + cls = tmp; + if (!tmp || cls == tmp) + continue; + + printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), " + "using %u bytes\n", cls << 2, tmp << 2, + pci_dfl_cache_line_size << 2); + pci_cache_line_size = pci_dfl_cache_line_size; + } + } + if (!pci_cache_line_size) { + printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", + cls << 2, pci_dfl_cache_line_size << 2); + pci_cache_line_size = cls ? cls : pci_dfl_cache_line_size; } return 0; } fs_initcall_sync(pci_apply_final_quirks); + +/* + * Followings are device-specific reset methods which can be used to + * reset a single function if other methods (e.g. FLR, PM D0->D3) are + * not available. + */ +static int reset_intel_generic_dev(struct pci_dev *dev, int probe) +{ + int pos; + + /* only implement PCI_CLASS_SERIAL_USB at present */ + if (dev->class == PCI_CLASS_SERIAL_USB) { + pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); + if (!pos) + return -ENOTTY; + + if (probe) + return 0; + + pci_write_config_byte(dev, pos + 0x4, 1); + msleep(100); + + return 0; + } else { + return -ENOTTY; + } +} + +static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) +{ + int pos; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return -ENOTTY; + + if (probe) + return 0; + + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); + msleep(100); + + return 0; +} + +#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed + +static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF, + reset_intel_82599_sfp_virtfn }, + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + reset_intel_generic_dev }, + { 0 } +}; + +int pci_dev_specific_reset(struct pci_dev *dev, int probe) +{ + const struct pci_dev_reset_methods *i; + + for (i = pci_dev_reset_methods; i->reset; i++) { + if ((i->vendor == dev->vendor || + i->vendor == (u16)PCI_ANY_ID) && + (i->device == dev->device || + i->device == (u16)PCI_ANY_ID)) + return i->reset(dev, probe); + } + + return -ENOTTY; +} + #else void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} +int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; } #endif EXPORT_SYMBOL(pci_fixup_device); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ec415352d9ba..4a471dc4f4b9 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -15,9 +15,9 @@ DECLARE_RWSEM(pci_bus_sem); /* - * find the upstream PCIE-to-PCI bridge of a PCI device + * find the upstream PCIe-to-PCI bridge of a PCI device * if the device is PCIE, return NULL - * if the device isn't connected to a PCIE bridge (that is its parent is a + * if the device isn't connected to a PCIe bridge (that is its parent is a * legacy PCI bridge and the bridge is directly connected to bus 0), return its * parent */ @@ -26,18 +26,18 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) { struct pci_dev *tmp = NULL; - if (pdev->is_pcie) + if (pci_is_pcie(pdev)) return NULL; while (1) { if (pci_is_root_bus(pdev->bus)) break; pdev = pdev->bus->self; /* a p2p bridge */ - if (!pdev->is_pcie) { + if (!pci_is_pcie(pdev)) { tmp = pdev; continue; } - /* PCI device should connect to a PCIE bridge */ + /* PCI device should connect to a PCIe bridge */ if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) { /* Busted hardware? */ WARN_ON_ONCE(1); @@ -149,32 +149,33 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) } /** - * pci_get_bus_and_slot - locate PCI device from a given PCI bus & slot - * @bus: number of PCI bus on which desired PCI device resides - * @devfn: encodes number of PCI slot in which the desired PCI - * device resides and the logical device number within that slot - * in case of multi-function devices. - * - * Note: the bus/slot search is limited to PCI domain (segment) 0. + * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot + * @domain: PCI domain/segment on which the PCI device resides. + * @bus: PCI bus on which desired PCI device resides + * @devfn: encodes number of PCI slot in which the desired PCI device + * resides and the logical device number within that slot in case of + * multi-function devices. * - * Given a PCI bus and slot/function number, the desired PCI device - * is located in system global list of PCI devices. If the device - * is found, a pointer to its data structure is returned. If no - * device is found, %NULL is returned. The returned device has its - * reference count bumped by one. + * Given a PCI domain, bus, and slot/function number, the desired PCI + * device is located in the list of PCI devices. If the device is + * found, its reference count is increased and this function returns a + * pointer to its data structure. The caller must decrement the + * reference count by calling pci_dev_put(). If no device is found, + * %NULL is returned. */ - -struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) +struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, + unsigned int devfn) { struct pci_dev *dev = NULL; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_domain_nr(dev->bus) == 0 && - (dev->bus->number == bus && dev->devfn == devfn)) + if (pci_domain_nr(dev->bus) == domain && + (dev->bus->number == bus && dev->devfn == devfn)) return dev; } return NULL; } +EXPORT_SYMBOL(pci_get_domain_bus_and_slot); static int match_pci_dev_by_id(struct device *dev, void *data) { @@ -354,5 +355,4 @@ EXPORT_SYMBOL(pci_find_next_bus); EXPORT_SYMBOL(pci_get_device); EXPORT_SYMBOL(pci_get_subsys); EXPORT_SYMBOL(pci_get_slot); -EXPORT_SYMBOL(pci_get_bus_and_slot); EXPORT_SYMBOL(pci_get_class); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index cb1a027eb552..c48cd377b3f5 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -71,53 +71,50 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus) void pci_setup_cardbus(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; + struct resource *res; struct pci_bus_region region; - dev_info(&bridge->dev, "CardBus bridge, secondary bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", + bus->secondary, bus->subordinate); - pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); - if (bus->resource[0]->flags & IORESOURCE_IO) { + res = bus->resource[0]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { /* * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. */ - dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); - if (bus->resource[1]->flags & IORESOURCE_IO) { - dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[1]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); - if (bus->resource[2]->flags & IORESOURCE_MEM) { - dev_info(&bridge->dev, " PREFETCH window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[2]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); - if (bus->resource[3]->flags & IORESOURCE_MEM) { - dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[3]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, @@ -140,34 +137,33 @@ EXPORT_SYMBOL(pci_setup_cardbus); static void pci_setup_bridge(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; + struct resource *res; struct pci_bus_region region; u32 l, bu, lu, io_upper16; - int pref_mem64; if (pci_is_enabled(bridge)) return; - dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", + bus->secondary, bus->subordinate); /* Set up the top and bottom of the PCI I/O segment for this bus. */ - pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); - if (bus->resource[0]->flags & IORESOURCE_IO) { + res = bus->resource[0]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { pci_read_config_dword(bridge, PCI_IO_BASE, &l); l &= 0xffff0000; l |= (region.start >> 8) & 0x00f0; l |= region.end & 0xf000; /* Set up upper 16 bits of I/O base/limit. */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); - dev_info(&bridge->dev, " IO window: %#04lx-%#04lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { /* Clear upper 16 bits of I/O base/limit. */ io_upper16 = 0; l = 0x00f0; - dev_info(&bridge->dev, " IO window: disabled\n"); + dev_info(&bridge->dev, " bridge window [io disabled]\n"); } /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); @@ -178,17 +174,16 @@ static void pci_setup_bridge(struct pci_bus *bus) /* Set up the top and bottom of the PCI Memory segment for this bus. */ - pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); - if (bus->resource[1]->flags & IORESOURCE_MEM) { + res = bus->resource[1]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " MEM window: disabled\n"); + dev_info(&bridge->dev, " bridge window [mem disabled]\n"); } pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); @@ -198,34 +193,27 @@ static void pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ - pref_mem64 = 0; bu = lu = 0; - pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); - if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { - int width = 8; + res = bus->resource[2]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - if (bus->resource[2]->flags & IORESOURCE_MEM_64) { - pref_mem64 = 1; + if (res->flags & IORESOURCE_MEM_64) { bu = upper_32_bits(region.start); lu = upper_32_bits(region.end); - width = 16; } - dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", - width, (unsigned long long)region.start, - width, (unsigned long long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " PREFETCH window: disabled\n"); + dev_info(&bridge->dev, " bridge window [mem pref disabled]\n"); } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - if (pref_mem64) { - /* Set the upper 32 bits of PREF base & limit. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); - } + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -345,6 +333,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) #endif size = ALIGN(size + size1, 4096); if (!size) { + if (b_res->start || b_res->end) + dev_info(&bus->self->dev, "disabling bridge window " + "%pR to [bus %02x-%02x] (unused)\n", b_res, + bus->secondary, bus->subordinate); b_res->flags = 0; return; } @@ -390,8 +382,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, align = pci_resource_alignment(dev, r); order = __ffs(align) - 20; if (order > 11) { - dev_warn(&dev->dev, "BAR %d bad alignment %llx: " - "%pR\n", i, (unsigned long long)align, r); + dev_warn(&dev->dev, "disabling BAR %d: %pR " + "(bad alignment %#llx)\n", i, r, + (unsigned long long) align); r->flags = 0; continue; } @@ -425,6 +418,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, } size = ALIGN(size, min_align); if (!size) { + if (b_res->start || b_res->end) + dev_info(&bus->self->dev, "disabling bridge window " + "%pR to [bus %02x-%02x] (unused)\n", b_res, + bus->secondary, bus->subordinate); b_res->flags = 0; return 1; } @@ -582,10 +579,7 @@ static void pci_bus_dump_res(struct pci_bus *bus) if (!res || !res->end) continue; - dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, - (res->flags & IORESOURCE_IO) ? "io: " : - ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"), - res); + dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); } } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index c54526b206b5..7d678bb15ffb 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -51,12 +51,6 @@ void pci_update_resource(struct pci_dev *dev, int resno) pcibios_resource_to_bus(dev, ®ion, res); - dev_dbg(&dev->dev, "BAR %d: got res %pR bus [%#llx-%#llx] " - "flags %#lx\n", resno, res, - (unsigned long long)region.start, - (unsigned long long)region.end, - (unsigned long)res->flags); - new = region.start | (res->flags & PCI_REGION_FLAG_MASK); if (res->flags & IORESOURCE_IO) mask = (u32)PCI_BASE_ADDRESS_IO_MASK; @@ -91,9 +85,9 @@ void pci_update_resource(struct pci_dev *dev, int resno) } } res->flags &= ~IORESOURCE_UNSET; - dev_dbg(&dev->dev, "BAR %d: moved to bus [%#llx-%#llx] flags %#lx\n", - resno, (unsigned long long)region.start, - (unsigned long long)region.end, res->flags); + dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx]\n", + resno, res, (unsigned long long)region.start, + (unsigned long long)region.end); } int pci_claim_resource(struct pci_dev *dev, int resource) @@ -103,20 +97,17 @@ int pci_claim_resource(struct pci_dev *dev, int resource) int err; root = pci_find_parent_resource(dev, res); - - err = -EINVAL; - if (root != NULL) - err = request_resource(root, res); - - if (err) { - const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; - dev_err(&dev->dev, "BAR %d: %s of %s %pR\n", - resource, - root ? "address space collision on" : - "no parent found for", - dtype, res); + if (!root) { + dev_err(&dev->dev, "no compatible bridge window for %pR\n", + res); + return -EINVAL; } + err = request_resource(root, res); + if (err) + dev_err(&dev->dev, + "address space collision: %pR already in use\n", res); + return err; } EXPORT_SYMBOL(pci_claim_resource); @@ -124,7 +115,7 @@ EXPORT_SYMBOL(pci_claim_resource); #ifdef CONFIG_PCI_QUIRKS void pci_disable_bridge_window(struct pci_dev *dev) { - dev_dbg(&dev->dev, "Disabling bridge window.\n"); + dev_info(&dev->dev, "disabling bridge mem windows\n"); /* MMIO Base/Limit */ pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0); @@ -165,6 +156,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, if (!ret) { res->flags &= ~IORESOURCE_STARTALIGN; + dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); if (resno < PCI_BRIDGE_RESOURCES) pci_update_resource(dev, resno); } @@ -178,12 +170,12 @@ int pci_assign_resource(struct pci_dev *dev, int resno) resource_size_t align; struct pci_bus *bus; int ret; + char *type; align = pci_resource_alignment(dev, res); if (!align) { - dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " - "alignment) %pR flags %#lx\n", - resno, res, res->flags); + dev_info(&dev->dev, "BAR %d: can't assign %pR " + "(bogus alignment)\n", resno, res); return -EINVAL; } @@ -198,9 +190,20 @@ int pci_assign_resource(struct pci_dev *dev, int resno) break; } - if (ret) - dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", - resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); + if (ret) { + if (res->flags & IORESOURCE_MEM) + if (res->flags & IORESOURCE_PREFETCH) + type = "mem pref"; + else + type = "mem"; + else if (res->flags & IORESOURCE_IO) + type = "io"; + else + type = "unknown"; + dev_info(&dev->dev, + "BAR %d: can't assign %s (size %#llx)\n", + resno, type, (unsigned long long) resource_size(res)); + } return ret; } @@ -225,9 +228,8 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) r_align = pci_resource_alignment(dev, r); if (!r_align) { - dev_warn(&dev->dev, "BAR %d: bogus alignment " - "%pR flags %#lx\n", - i, r, r->flags); + dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n", + i, r); continue; } for (list = head; ; list = list->next) { @@ -274,8 +276,8 @@ int pci_enable_resources(struct pci_dev *dev, int mask) continue; if (!r->parent) { - dev_err(&dev->dev, "device not available because of " - "BAR %d %pR collisions\n", i, r); + dev_err(&dev->dev, "device not available " + "(can't reserve %pR)\n", r); return -EINVAL; } |