Commit 600812ec authored by Satoru Takeuchi's avatar Satoru Takeuchi Committed by Greg Kroah-Hartman

acpiphp: add support for ioapic hot-remove

This patch adds support for ioapics hot-remove.
Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarMUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
Signed-off-by: default avatarSatoru Takeuchi <takeuchi_satoru@jp.fujitsu.com>
Signed-off-by: default avatarKristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 23186279
...@@ -150,6 +150,11 @@ struct acpiphp_attention_info ...@@ -150,6 +150,11 @@ struct acpiphp_attention_info
struct module *owner; struct module *owner;
}; };
struct acpiphp_ioapic {
struct pci_dev *dev;
u32 gsi_base;
struct list_head list;
};
/* PCI bus bridge HID */ /* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID "PNP0A03" #define ACPI_PCI_HOST_HID "PNP0A03"
......
...@@ -53,6 +53,8 @@ ...@@ -53,6 +53,8 @@
#include "acpiphp.h" #include "acpiphp.h"
static LIST_HEAD(bridge_list); static LIST_HEAD(bridge_list);
static LIST_HEAD(ioapic_list);
static DEFINE_SPINLOCK(ioapic_list_lock);
#define MY_NAME "acpiphp_glue" #define MY_NAME "acpiphp_glue"
...@@ -797,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -797,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
struct pci_dev *pdev; struct pci_dev *pdev;
u32 gsi_base; u32 gsi_base;
u64 phys_addr; u64 phys_addr;
struct acpiphp_ioapic *ioapic;
/* Evaluate _STA if present */ /* Evaluate _STA if present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
...@@ -811,30 +814,87 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -811,30 +814,87 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
if (get_gsi_base(handle, &gsi_base)) if (get_gsi_base(handle, &gsi_base))
return AE_OK; return AE_OK;
ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
if (!ioapic)
return AE_NO_MEMORY;
pdev = get_apic_pci_info(handle); pdev = get_apic_pci_info(handle);
if (!pdev) if (!pdev)
return AE_OK; goto exit_kfree;
if (pci_enable_device(pdev)) { if (pci_enable_device(pdev))
pci_dev_put(pdev); goto exit_pci_dev_put;
return AE_OK;
}
pci_set_master(pdev); pci_set_master(pdev);
if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
pci_disable_device(pdev); goto exit_pci_disable_device;
pci_dev_put(pdev);
return AE_OK;
}
phys_addr = pci_resource_start(pdev, 0); phys_addr = pci_resource_start(pdev, 0);
if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { 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); pci_release_region(pdev, 0);
exit_pci_disable_device:
pci_disable_device(pdev); pci_disable_device(pdev);
exit_pci_dev_put:
pci_dev_put(pdev); 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 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; 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; return AE_OK;
} }
...@@ -847,6 +907,14 @@ static int acpiphp_configure_ioapics(acpi_handle handle) ...@@ -847,6 +907,14 @@ static int acpiphp_configure_ioapics(acpi_handle handle)
return 0; 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);
return 0;
}
static int power_on_slot(struct acpiphp_slot *slot) static int power_on_slot(struct acpiphp_slot *slot)
{ {
acpi_status status; acpi_status status;
...@@ -1146,7 +1214,12 @@ static int disable_device(struct acpiphp_slot *slot) ...@@ -1146,7 +1214,12 @@ static int disable_device(struct acpiphp_slot *slot)
pci_disable_device(func->pci_dev); pci_disable_device(func->pci_dev);
} }
} }
}
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle); acpiphp_bus_trim(func->handle);
/* try to remove anyway. /* try to remove anyway.
* acpiphp_bus_add might have been failed */ * acpiphp_bus_add might have been failed */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment