acpiphp: add support for ioapic hot-remove
This patch adds support for ioapics hot-remove. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com> Signed-off-by: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
2318627965
commit
600812ecea
@ -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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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))
|
||||||
pci_release_region(pdev, 0);
|
goto exit_pci_release_region;
|
||||||
pci_disable_device(pdev);
|
|
||||||
pci_dev_put(pdev);
|
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);
|
||||||
|
exit_pci_disable_device:
|
||||||
|
pci_disable_device(pdev);
|
||||||
|
exit_pci_dev_put:
|
||||||
|
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)
|
|||||||
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)
|
|||||||
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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user