[tip:x86/urgent] x86/ioapic: Split IOAPIC hot-removal into two steps

From: tip-bot for Rui Wang
Date: Wed Mar 01 2017 - 05:44:34 EST


Commit-ID: f2ae5da726172fcf82f7be801489dd585f6a38eb
Gitweb: http://git.kernel.org/tip/f2ae5da726172fcf82f7be801489dd585f6a38eb
Author: Rui Wang <rui.y.wang@xxxxxxxxx>
AuthorDate: Tue, 28 Feb 2017 21:34:29 +0800
Committer: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
CommitDate: Wed, 1 Mar 2017 10:51:41 +0100

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@xxxxxxxxx>
Cc: tony.luck@xxxxxxxxx
Cc: linux-pci@xxxxxxxxxxxxxxx
Cc: rjw@xxxxxxxxxxxxx
Cc: linux-acpi@xxxxxxxxxxxxxxx
Cc: fengguang.wu@xxxxxxxxx
Cc: helgaas@xxxxxxxxxx
Cc: kbuild-all@xxxxxx
Cc: bhelgaas@xxxxxxxxxx
Link: http://lkml.kernel.org/r/1488288869-31290-3-git-send-email-rui.y.wang@xxxxxxxxx
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>

---
drivers/acpi/internal.h | 2 ++
drivers/acpi/ioapic.c | 22 ++++++++++++++++------
drivers/acpi/pci_root.c | 4 ++--
3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 219b90b..f159001 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,8 +41,10 @@ void acpi_gpe_apply_masked_gpes(void);
void acpi_container_init(void);
void acpi_memory_hotplug_init(void);
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
+void pci_ioapic_remove(struct acpi_pci_root *root);
int acpi_ioapic_remove(struct acpi_pci_root *root);
#else
+static inline void pci_ioapic_remove(struct acpi_pci_root *root) { return; }
static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; }
#endif
#ifdef CONFIG_ACPI_DOCK
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 6d7ce6e..1120dfd6 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -206,24 +206,34 @@ int acpi_ioapic_add(acpi_handle root_handle)
return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV;
}

-int acpi_ioapic_remove(struct acpi_pci_root *root)
+void pci_ioapic_remove(struct acpi_pci_root *root)
{
- int retval = 0;
struct acpi_pci_ioapic *ioapic, *tmp;

mutex_lock(&ioapic_list_lock);
list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
if (root->device->handle != ioapic->root_handle)
continue;
-
- if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
- retval = -EBUSY;
-
if (ioapic->pdev) {
pci_release_region(ioapic->pdev, 0);
pci_disable_device(ioapic->pdev);
pci_dev_put(ioapic->pdev);
}
+ }
+ mutex_unlock(&ioapic_list_lock);
+}
+
+int acpi_ioapic_remove(struct acpi_pci_root *root)
+{
+ int retval = 0;
+ struct acpi_pci_ioapic *ioapic, *tmp;
+
+ mutex_lock(&ioapic_list_lock);
+ list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
+ if (root->device->handle != ioapic->root_handle)
+ continue;
+ if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
+ retval = -EBUSY;
if (ioapic->res.flags && ioapic->res.parent)
release_resource(&ioapic->res);
list_del(&ioapic->list);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index bf601d4..919be0a 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)

pci_stop_root_bus(root->bus);

- WARN_ON(acpi_ioapic_remove(root));
-
+ pci_ioapic_remove(root);
device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device);

pci_remove_root_bus(root->bus);
+ WARN_ON(acpi_ioapic_remove(root));

dmar_device_remove(device->handle);