aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRui Wang <rui.y.wang@intel.com>2017-02-28 08:34:29 -0500
committerThomas Gleixner <tglx@linutronix.de>2017-03-01 04:51:41 -0500
commitf2ae5da726172fcf82f7be801489dd585f6a38eb (patch)
tree35a6ee0f1d018f201f3ab0c145c1fc61d84b49ec /drivers
parent153654dbe595a68845ba14d5b0bfe299fa6a7e99 (diff)
x86/ioapic: Split IOAPIC hot-removal into two steps
The hot removal of IOAPIC is handling PCI and ACPI removal in one go. That only works when the PCI drivers released the interrupt resources, but breaks when a IOAPIC interrupt is still associated to a PCI device. The new pcibios_release_device() callback allows to solve that problem by splitting the removal into two steps: 1) PCI removal: Release all PCI resources including eventually not yet released IOAPIC interrupts via the new pcibios_release_device() callback. 2) ACPI removal: After release of all PCI resources the ACPI resources can be released without issue. [ tglx: Rewrote changelog ] Signed-off-by: Rui Wang <rui.y.wang@intel.com> Cc: tony.luck@intel.com Cc: linux-pci@vger.kernel.org Cc: rjw@rjwysocki.net Cc: linux-acpi@vger.kernel.org Cc: fengguang.wu@intel.com Cc: helgaas@kernel.org Cc: kbuild-all@01.org Cc: bhelgaas@google.com Link: http://lkml.kernel.org/r/1488288869-31290-3-git-send-email-rui.y.wang@intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/ioapic.c22
-rw-r--r--drivers/acpi/pci_root.c4
3 files changed, 20 insertions, 8 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 219b90bc0922..f15900132912 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,8 +41,10 @@ void acpi_gpe_apply_masked_gpes(void);
41void acpi_container_init(void); 41void acpi_container_init(void);
42void acpi_memory_hotplug_init(void); 42void acpi_memory_hotplug_init(void);
43#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC 43#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
44void pci_ioapic_remove(struct acpi_pci_root *root);
44int acpi_ioapic_remove(struct acpi_pci_root *root); 45int acpi_ioapic_remove(struct acpi_pci_root *root);
45#else 46#else
47static inline void pci_ioapic_remove(struct acpi_pci_root *root) { return; }
46static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } 48static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; }
47#endif 49#endif
48#ifdef CONFIG_ACPI_DOCK 50#ifdef CONFIG_ACPI_DOCK
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 6d7ce6e12aaa..1120dfd625b8 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -206,24 +206,34 @@ int acpi_ioapic_add(acpi_handle root_handle)
206 return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; 206 return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV;
207} 207}
208 208
209int acpi_ioapic_remove(struct acpi_pci_root *root) 209void pci_ioapic_remove(struct acpi_pci_root *root)
210{ 210{
211 int retval = 0;
212 struct acpi_pci_ioapic *ioapic, *tmp; 211 struct acpi_pci_ioapic *ioapic, *tmp;
213 212
214 mutex_lock(&ioapic_list_lock); 213 mutex_lock(&ioapic_list_lock);
215 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { 214 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
216 if (root->device->handle != ioapic->root_handle) 215 if (root->device->handle != ioapic->root_handle)
217 continue; 216 continue;
218
219 if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
220 retval = -EBUSY;
221
222 if (ioapic->pdev) { 217 if (ioapic->pdev) {
223 pci_release_region(ioapic->pdev, 0); 218 pci_release_region(ioapic->pdev, 0);
224 pci_disable_device(ioapic->pdev); 219 pci_disable_device(ioapic->pdev);
225 pci_dev_put(ioapic->pdev); 220 pci_dev_put(ioapic->pdev);
226 } 221 }
222 }
223 mutex_unlock(&ioapic_list_lock);
224}
225
226int acpi_ioapic_remove(struct acpi_pci_root *root)
227{
228 int retval = 0;
229 struct acpi_pci_ioapic *ioapic, *tmp;
230
231 mutex_lock(&ioapic_list_lock);
232 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
233 if (root->device->handle != ioapic->root_handle)
234 continue;
235 if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
236 retval = -EBUSY;
227 if (ioapic->res.flags && ioapic->res.parent) 237 if (ioapic->res.flags && ioapic->res.parent)
228 release_resource(&ioapic->res); 238 release_resource(&ioapic->res);
229 list_del(&ioapic->list); 239 list_del(&ioapic->list);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index bf601d4df8cf..919be0aa2578 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -648,12 +648,12 @@ static void acpi_pci_root_remove(struct acpi_device *device)
648 648
649 pci_stop_root_bus(root->bus); 649 pci_stop_root_bus(root->bus);
650 650
651 WARN_ON(acpi_ioapic_remove(root)); 651 pci_ioapic_remove(root);
652
653 device_set_run_wake(root->bus->bridge, false); 652 device_set_run_wake(root->bus->bridge, false);
654 pci_acpi_remove_bus_pm_notifier(device); 653 pci_acpi_remove_bus_pm_notifier(device);
655 654
656 pci_remove_root_bus(root->bus); 655 pci_remove_root_bus(root->bus);
656 WARN_ON(acpi_ioapic_remove(root));
657 657
658 dmar_device_remove(device->handle); 658 dmar_device_remove(device->handle);
659 659