From: Linus Torvalds Date: Tue, 26 Feb 2013 05:18:18 +0000 (-0800) Subject: Merge tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci X-Git-Tag: v3.9-rc1~82 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=556f12f602ac0a18a82ca83e9f8e8547688fc633;p=users%2Fdwmw2%2Flinux.git Merge tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI changes from Bjorn Helgaas: "Host bridge hotplug - Major overhaul of ACPI host bridge add/start (Rafael Wysocki, Yinghai Lu) - Major overhaul of PCI/ACPI binding (Rafael Wysocki, Yinghai Lu) - Split out ACPI host bridge and ACPI PCI device hotplug (Yinghai Lu) - Stop caching _PRT and make independent of bus numbers (Yinghai Lu) PCI device hotplug - Clean up cpqphp dead code (Sasha Levin) - Disable ARI unless device and upstream bridge support it (Yijing Wang) - Initialize all hot-added devices (not functions 0-7) (Yijing Wang) Power management - Don't touch ASPM if disabled (Joe Lawrence) - Fix ASPM link state management (Myron Stowe) Miscellaneous - Fix PCI_EXP_FLAGS accessor (Alex Williamson) - Disable Bus Master in pci_device_shutdown (Konstantin Khlebnikov) - Document hotplug resource and MPS parameters (Yijing Wang) - Add accessor for PCIe capabilities (Myron Stowe) - Drop pciehp suspend/resume messages (Paul Bolle) - Make pci_slot built-in only (not a module) (Jiang Liu) - Remove unused PCI/ACPI bind ops (Jiang Liu) - Removed used pci_root_bus (Bjorn Helgaas)" * tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (51 commits) PCI/ACPI: Don't cache _PRT, and don't associate them with bus numbers PCI: Fix PCI Express Capability accessors for PCI_EXP_FLAGS ACPI / PCI: Make pci_slot built-in only, not a module PCI/PM: Clear state_saved during suspend PCI: Use atomic_inc_return() rather than atomic_add_return() PCI: Catch attempts to disable already-disabled devices PCI: Disable Bus Master unconditionally in pci_device_shutdown() PCI: acpiphp: Remove dead code for PCI host bridge hotplug PCI: acpiphp: Create companion ACPI devices before creating PCI devices PCI: Remove unused "rc" in virtfn_add_bus() PCI: pciehp: Drop suspend/resume ENTRY messages PCI/ASPM: Don't touch ASPM if forcibly disabled PCI/ASPM: Deallocate upstream link state even if device is not PCIe PCI: Document MPS parameters pci=pcie_bus_safe, pci=pcie_bus_perf, etc PCI: Document hpiosize= and hpmemsize= resource reservation parameters PCI: Use PCI Express Capability accessor PCI: Introduce accessor to retrieve PCIe Capabilities Register PCI: Put pci_dev in device tree as early as possible PCI: Skip attaching driver in device_add() PCI: acpiphp: Keep driver loaded even if no slots found ... --- 556f12f602ac0a18a82ca83e9f8e8547688fc633 diff --cc arch/ia64/pci/pci.c index 55b72ad573292,00e59c7ad3c05..60532ab273468 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@@ -393,7 -396,15 +393,15 @@@ out1 return NULL; } + int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) + { + struct pci_controller *controller = bridge->bus->sysdata; + + ACPI_HANDLE_SET(&bridge->dev, controller->acpi_handle); + return 0; + } + -static int __devinit is_valid_resource(struct pci_dev *dev, int idx) +static int is_valid_resource(struct pci_dev *dev, int idx) { unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; struct resource *devr = &dev->resource[idx], *busr; diff --cc drivers/acpi/internal.h index 79092328cf064,e09ce0373d41f..c8b70b5b2814d --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@@ -25,16 -25,7 +25,22 @@@ int init_acpi_device_notify(void); int acpi_scan_init(void); ++#ifdef CONFIG_ACPI_PCI_SLOT ++void acpi_pci_slot_init(void); ++#else ++static inline void acpi_pci_slot_init(void) { } ++#endif +void acpi_pci_root_init(void); +void acpi_pci_link_init(void); ++void acpi_pci_root_hp_init(void); +void acpi_platform_init(void); int acpi_sysfs_init(void); +void acpi_csrt_init(void); +#ifdef CONFIG_ACPI_CONTAINER +void acpi_container_init(void); +#else +static inline void acpi_container_init(void) {} +#endif #ifdef CONFIG_DEBUG_FS extern struct dentry *acpi_debugfs_dir; diff --cc drivers/acpi/pci_root.c index b3cc69c5caf1e,8b5a73b762020..0ac546d5e53f5 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@@ -624,10 -599,8 +596,8 @@@ end return result; } -static int acpi_pci_root_remove(struct acpi_device *device, int type) +static void acpi_pci_root_remove(struct acpi_device *device) { - acpi_status status; - acpi_handle handle; struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; @@@ -658,8 -628,142 +624,138 @@@ void __init acpi_pci_root_init(void { acpi_hest_init(); - if (acpi_pci_disabled) - return 0; - - pci_acpi_crs_quirks(); - if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) - return -ENODEV; - - return 0; + if (!acpi_pci_disabled) { + pci_acpi_crs_quirks(); + acpi_scan_add_handler(&pci_root_handler); + } } + /* Support root bridge hotplug */ + + static void handle_root_bridge_insertion(acpi_handle handle) + { + struct acpi_device *device; + + if (!acpi_bus_get_device(handle, &device)) { + printk(KERN_DEBUG "acpi device exists...\n"); + return; + } + + if (acpi_bus_scan(handle)) + printk(KERN_ERR "cannot add bridge to acpi list\n"); + } + + static void handle_root_bridge_removal(struct acpi_device *device) + { + struct acpi_eject_event *ej_event; + + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + /* Inform firmware the hot-remove operation has error */ + (void) acpi_evaluate_hotplug_ost(device->handle, + ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_NON_SPECIFIC_FAILURE, + NULL); + return; + } + + ej_event->device = device; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + + acpi_bus_hot_remove_device(ej_event); + } + + static void _handle_hotplug_event_root(struct work_struct *work) + { + struct acpi_pci_root *root; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER }; + struct acpi_hp_work *hp_work; + acpi_handle handle; + u32 type; + + hp_work = container_of(work, struct acpi_hp_work, work); + handle = hp_work->handle; + type = hp_work->type; + + root = acpi_pci_find_root(handle); + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* bus enumerate */ + printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, + (char *)buffer.pointer); + if (!root) + handle_root_bridge_insertion(handle); + + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* device check */ + printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__, + (char *)buffer.pointer); + if (!root) + handle_root_bridge_insertion(handle); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* request device eject */ + printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__, + (char *)buffer.pointer); + if (root) + handle_root_bridge_removal(root->device); + break; + default: + printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n", + type, (char *)buffer.pointer); + break; + } + + kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ + kfree(buffer.pointer); + } + + static void handle_hotplug_event_root(acpi_handle handle, u32 type, + void *context) + { + alloc_acpi_hp_work(handle, type, context, + _handle_hotplug_event_root); + } + + static acpi_status __init + find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) + { + acpi_status status; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + int *count = (int *)context; + + if (!acpi_is_root_bridge(handle)) + return AE_OK; + + (*count)++; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_root, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n", + objname, (unsigned int)status); + else + printk(KERN_DEBUG "acpi root: %s notify handler is installed\n", + objname); + + return AE_OK; + } + + void __init acpi_pci_root_hp_init(void) + { + int num = 0; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); + + printk(KERN_DEBUG "Found %d acpi root devices\n", num); + } diff --cc drivers/acpi/scan.c index daee7497efd30,b643aed8b74bf..4be408756adc1 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@@ -1778,13 -1685,10 +1778,14 @@@ int __init acpi_scan_init(void printk(KERN_ERR PREFIX "Could not register bus type\n"); } - acpi_power_init(); acpi_pci_root_init(); + acpi_pci_link_init(); + acpi_platform_init(); + acpi_csrt_init(); + acpi_container_init(); + acpi_pci_slot_init(); + mutex_lock(&acpi_scan_lock); /* * Enumerate devices in the ACPI namespace. */ @@@ -1804,7 -1708,7 +1805,9 @@@ acpi_update_all_gpes(); + acpi_pci_root_hp_init(); + - return 0; + out: + mutex_unlock(&acpi_scan_lock); + return result; } diff --cc drivers/pci/hotplug/acpiphp_glue.c index a951c22921d16,4681d2c9b1dd9..270fdbadc19c9 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@@ -1214,29 -1136,11 +1132,13 @@@ static void _handle_hotplug_event_bridg acpi_handle handle; u32 type; - hp_work = container_of(work, struct acpiphp_hp_work, work); + hp_work = container_of(work, struct acpi_hp_work, work); handle = hp_work->handle; type = hp_work->type; + bridge = (struct acpiphp_bridge *)hp_work->context; + acpi_scan_lock_acquire(); + - if (acpi_bus_get_device(handle, &device)) { - /* This bridge must have just been physically inserted */ - handle_bridge_insertion(handle, type); - goto out; - } - - bridge = acpiphp_handle_to_bridge(handle); - if (type == ACPI_NOTIFY_BUS_CHECK) { - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, - count_sub_bridges, NULL, &num_sub_bridges, NULL); - } - - if (!bridge && !num_sub_bridges) { - err("cannot get bridge info\n"); - goto out; - } - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@@ -1296,8 -1195,6 +1193,7 @@@ break; } - out: + acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ } @@@ -1330,22 -1226,17 +1225,19 @@@ static void _handle_hotplug_event_func( char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpiphp_hp_work *hp_work; + struct acpi_hp_work *hp_work; acpi_handle handle; u32 type; - void *context; - hp_work = container_of(work, struct acpiphp_hp_work, work); + hp_work = container_of(work, struct acpi_hp_work, work); handle = hp_work->handle; type = hp_work->type; - context = hp_work->context; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - func = (struct acpiphp_func *)context; + func = (struct acpiphp_func *)hp_work->context; + acpi_scan_lock_acquire(); + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ diff --cc drivers/pci/pci-acpi.c index e407c61559ca0,c685ff5e12d24..39c937f9b426e --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@@ -325,26 -307,8 +307,7 @@@ static void pci_acpi_setup(struct devic struct pci_dev *pci_dev = to_pci_dev(dev); acpi_handle handle = ACPI_HANDLE(dev); struct acpi_device *adev; - acpi_status status; - acpi_handle dummy; - - /* - * Evaluate and parse _PRT, if exists. This code allows parsing of - * _PRT objects within the scope of non-bridge devices. Note that - * _PRTs within the scope of a PCI bridge assume the bridge's - * subordinate bus number. - * - * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? - */ - status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy); - if (ACPI_SUCCESS(status)) { - unsigned char bus; - - bus = pci_dev->subordinate ? - pci_dev->subordinate->number : pci_dev->bus->number; - acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus); - } - acpi_power_resource_register_device(dev, handle); if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) return; @@@ -367,10 -330,7 +329,6 @@@ static void pci_acpi_cleanup(struct dev device_set_run_wake(dev, false); pci_acpi_remove_pm_notifier(adev); } - - if (pci_dev->subordinate) - acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus), - pci_dev->subordinate->number); - acpi_power_resource_unregister_device(dev, handle); } static struct acpi_bus_type acpi_pci_bus = {