From 62a08c5a3173c4462239804b959c0d29dc74493b Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:32 -0600 Subject: PCI/ACPI: Assign unassigned resource for hot-added root bus After we get hot-added IOAPIC registered. pci_enable_bridges() will try to enable IOAPIC IRQ for PCI bridges. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index bce469c0b48..27adbfdffb0 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -644,12 +644,19 @@ static int acpi_pci_root_start(struct acpi_device *device) struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; + if (system_state != SYSTEM_BOOTING) + pci_assign_unassigned_bus_resources(root->bus); + mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->add) driver->add(root); mutex_unlock(&acpi_pci_root_lock); + /* need to after hot-added ioapic is registered */ + if (system_state != SYSTEM_BOOTING) + pci_enable_bridges(root->bus); + pci_bus_add_devices(root->bus); return 0; -- cgit v1.2.3-18-g5258 From 9738a1fd214b8f617b31503307c79b6af72ee464 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:43 -0600 Subject: PCI/ACPI: Make acpi_pci_root_remove() stop/remove pci root bus It will call pci_stop_and_remove_bus() to stop/remove pci root bus. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki CC: Len Brown CC: linux-acpi@vger.kernel.org --- drivers/acpi/pci_root.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 27adbfdffb0..aed09537861 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -667,14 +667,20 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; + pci_stop_root_bus(root->bus); + mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) if (driver->remove) driver->remove(root); + mutex_unlock(&acpi_pci_root_lock); device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); + pci_remove_root_bus(root->bus); + + mutex_lock(&acpi_pci_root_lock); list_del(&root->node); mutex_unlock(&acpi_pci_root_lock); kfree(root); -- cgit v1.2.3-18-g5258 From 13b6a916409adbc47f3d13f9580be0bd413e446e Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:48 -0600 Subject: PCI/ACPI: Delete host bridge _PRT during hot remove path Corresponding to add path. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index aed09537861..a27cbb572fe 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -664,6 +664,8 @@ static int acpi_pci_root_start(struct acpi_device *device) static int acpi_pci_root_remove(struct acpi_device *device, int type) { + acpi_status status; + acpi_handle handle; struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; @@ -678,6 +680,10 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); + status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) + acpi_pci_irq_del_prt(root->bus); + pci_remove_root_bus(root->bus); mutex_lock(&acpi_pci_root_lock); -- cgit v1.2.3-18-g5258 From f426cef3bc58806284e0fee55d29262b10279f9c Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:52 -0600 Subject: PCI/ACPI: Remove acpi_root_driver in reverse order Call the sub-driver .remove() methods in the reverse order of the .add() methods for symmetry. [bhelgaas: changelog] Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a27cbb572fe..012f40d1d75 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -672,7 +672,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) pci_stop_root_bus(root->bus); mutex_lock(&acpi_pci_root_lock); - list_for_each_entry(driver, &acpi_pci_drivers, node) + list_for_each_entry_reverse(driver, &acpi_pci_drivers, node) if (driver->remove) driver->remove(root); mutex_unlock(&acpi_pci_root_lock); -- cgit v1.2.3-18-g5258 From 79c4412298771b8996302806abc8a11e760da9b3 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Oct 2012 15:24:06 +0900 Subject: ACPI: Pass segment/bus to _PRT add/del so they don't depend on pci_bus This effectively reverts 859a3f86ca8 ("ACPI: simplify acpi_pci_irq_add_prt() API") and d9efae3688a ("ACPI: simplify acpi_pci_irq_del_prt() API"). The reason is to disentangle these routines from the struct pci_bus. We want to be able to add the _PRT before the struct pci_bus exists, and delete the _PRT after we've removed the pci_bus. Signed-off-by: Bjorn Helgaas Signed-off-by: Taku Izumi --- drivers/acpi/pci_root.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 012f40d1d75..db31edaab9c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -554,7 +554,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(device->handle, root->bus); + result = acpi_pci_irq_add_prt(device->handle, root->segment, + root->secondary.start); /* * Scan and bind all _ADR-Based Devices @@ -682,7 +683,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) - acpi_pci_irq_del_prt(root->bus); + acpi_pci_irq_del_prt(root->segment, root->secondary.start); pci_remove_root_bus(root->bus); -- cgit v1.2.3-18-g5258 From d4761ba2d6adbe24c792ec6223a5884ae4e82430 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Oct 2012 15:24:50 +0900 Subject: PCI/ACPI: Add _PRT interrupt routing info before enumerating devices We used to add the _PRT after enumerating devices behind a new host bridge. This moves the _PRT addition *before* the enumeration, since it no longer depends on the struct pci_bus existing. This is one step towards consolidating the .add/.start methods. Signed-off-by: Bjorn Helgaas Signed-off-by: Taku Izumi --- drivers/acpi/pci_root.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index db31edaab9c..66f3ae74d13 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -501,6 +501,20 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); device->driver_data = root; + printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", + acpi_device_name(device), acpi_device_bid(device), + root->segment, &root->secondary); + + /* + * PCI Routing Table + * ----------------- + * Evaluate and parse _PRT, if exists. + */ + status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); + if (ACPI_SUCCESS(status)) + result = acpi_pci_irq_add_prt(device->handle, root->segment, + root->secondary.start); + root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle); /* @@ -518,10 +532,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) list_add_tail(&root->node, &acpi_pci_roots); mutex_unlock(&acpi_pci_root_lock); - printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", - acpi_device_name(device), acpi_device_bid(device), - root->segment, &root->secondary); - /* * Scan the Root Bridge * -------------------- @@ -547,16 +557,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (result) goto out_del_root; - /* - * PCI Routing Table - * ----------------- - * Evaluate and parse _PRT, if exists. - */ - status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); - if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(device->handle, root->segment, - root->secondary.start); - /* * Scan and bind all _ADR-Based Devices */ @@ -635,6 +635,8 @@ out_del_root: mutex_lock(&acpi_pci_root_lock); list_del(&root->node); mutex_unlock(&acpi_pci_root_lock); + + acpi_pci_irq_del_prt(root->segment, root->secondary.start); end: kfree(root); return result; -- cgit v1.2.3-18-g5258 From 642c92da36ae0bed3c31fdd408411ab95f4e326b Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 30 Oct 2012 15:26:18 +0900 Subject: PCI: Don't pass pci_dev to pci_ext_cfg_avail() pci_ext_cfg_avail() doesn't use the "struct pci_dev *" passed to it, and there's no requirement that a host bridge even be represented by a pci_dev. This drops the pci_ext_cfg_avail() parameter. [bhelgaas: changelog] Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 66f3ae74d13..50f329d7ccf 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -564,7 +564,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) acpi_pci_bridge_scan(child); /* Indicate support for various _OSC capabilities. */ - if (pci_ext_cfg_avail(root->bus->self)) + if (pci_ext_cfg_avail()) flags |= OSC_EXT_PCI_CONFIG_SUPPORT; if (pcie_aspm_support_enabled()) flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | -- cgit v1.2.3-18-g5258 From 8c33f51df406e1a1f7fa4e9b244845b7ebd61fa6 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 30 Oct 2012 15:27:13 +0900 Subject: PCI/ACPI: Request _OSC control before scanning PCI root bus This patch moves up the code block to request _OSC control in order to separate ACPI work and PCI work in acpi_pci_root_add(). Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 121 +++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 59 deletions(-) (limited to 'drivers/acpi/pci_root.c') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 50f329d7ccf..ab781f00e32 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -454,6 +454,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) acpi_handle handle; struct acpi_device *child; u32 flags, base_flags; + bool is_osc_granted = false; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) @@ -524,6 +525,60 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; acpi_pci_osc_support(root, flags); + /* Indicate support for various _OSC capabilities. */ + if (pci_ext_cfg_avail()) + flags |= OSC_EXT_PCI_CONFIG_SUPPORT; + if (pcie_aspm_support_enabled()) { + flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | + OSC_CLOCK_PWR_CAPABILITY_SUPPORT; + } + if (pci_msi_enabled()) + flags |= OSC_MSI_SUPPORT; + if (flags != base_flags) { + status = acpi_pci_osc_support(root, flags); + if (ACPI_FAILURE(status)) { + dev_info(&device->dev, "ACPI _OSC support " + "notification failed, disabling PCIe ASPM\n"); + pcie_no_aspm(); + flags = base_flags; + } + } + if (!pcie_ports_disabled + && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { + flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL + | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL + | OSC_PCI_EXPRESS_PME_CONTROL; + + if (pci_aer_available()) { + if (aer_acpi_firmware_first()) + dev_dbg(&device->dev, + "PCIe errors handled by BIOS.\n"); + else + flags |= OSC_PCI_EXPRESS_AER_CONTROL; + } + + dev_info(&device->dev, + "Requesting ACPI _OSC control (0x%02x)\n", flags); + + status = acpi_pci_osc_control_set(device->handle, &flags, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + if (ACPI_SUCCESS(status)) { + is_osc_granted = true; + dev_info(&device->dev, + "ACPI _OSC control (0x%02x) granted\n", flags); + } else { + is_osc_granted = false; + dev_info(&device->dev, + "ACPI _OSC request failed (%s), " + "returned control mask: 0x%02x\n", + acpi_format_exception(status), flags); + } + } else { + dev_info(&device->dev, + "Unable to request _OSC control " + "(_OSC support mask: 0x%02x)\n", flags); + } + /* * TBD: Need PCI interface for enumeration/configuration of roots. */ @@ -563,66 +618,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) list_for_each_entry(child, &device->children, node) acpi_pci_bridge_scan(child); - /* Indicate support for various _OSC capabilities. */ - if (pci_ext_cfg_avail()) - flags |= OSC_EXT_PCI_CONFIG_SUPPORT; - if (pcie_aspm_support_enabled()) - flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | - OSC_CLOCK_PWR_CAPABILITY_SUPPORT; - if (pci_msi_enabled()) - flags |= OSC_MSI_SUPPORT; - if (flags != base_flags) { - status = acpi_pci_osc_support(root, flags); - if (ACPI_FAILURE(status)) { - dev_info(root->bus->bridge, "ACPI _OSC support " - "notification failed, disabling PCIe ASPM\n"); - pcie_no_aspm(); - flags = base_flags; - } - } - - if (!pcie_ports_disabled - && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { - flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL - | OSC_PCI_EXPRESS_PME_CONTROL; - - if (pci_aer_available()) { - if (aer_acpi_firmware_first()) - dev_dbg(root->bus->bridge, - "PCIe errors handled by BIOS.\n"); - else - flags |= OSC_PCI_EXPRESS_AER_CONTROL; - } - - dev_info(root->bus->bridge, - "Requesting ACPI _OSC control (0x%02x)\n", flags); - - status = acpi_pci_osc_control_set(device->handle, &flags, - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - if (ACPI_SUCCESS(status)) { - dev_info(root->bus->bridge, - "ACPI _OSC control (0x%02x) granted\n", flags); - if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { - /* - * We have ASPM control, but the FADT indicates - * that it's unsupported. Clear it. - */ - pcie_clear_aspm(root->bus); - } - } else { - dev_info(root->bus->bridge, - "ACPI _OSC request failed (%s), " - "returned control mask: 0x%02x\n", - acpi_format_exception(status), flags); - pr_info("ACPI _OSC control for PCIe not granted, " - "disabling ASPM\n"); - pcie_no_aspm(); - } + /* ASPM setting */ + if (is_osc_granted) { + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) + pcie_clear_aspm(root->bus); } else { - dev_info(root->bus->bridge, - "Unable to request _OSC control " - "(_OSC support mask: 0x%02x)\n", flags); + pr_info("ACPI _OSC control for PCIe not granted, " + "disabling ASPM\n"); + pcie_no_aspm(); } pci_acpi_add_bus_pm_notifier(device, root->bus); -- cgit v1.2.3-18-g5258