@@ -183,6 +183,7 @@ extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
extern void mp_unmap_irq(int irq);
extern int mp_register_ioapic(int id, u32 address, u32 gsi_base,
ioapic_create_domain_fn cb, void *arg);
+extern int mp_unregister_ioapic(u32 gsi_base);
extern struct irq_domain *mp_irqdomain_create(int ioapic,
struct device_node *np, const struct irq_domain_ops *ops);
extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
@@ -672,15 +672,20 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
return ret;
}
-
EXPORT_SYMBOL(acpi_register_ioapic);
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
{
- /* TBD */
- return -EINVAL;
-}
+ int ret = -ENOSYS;
+
+#ifdef CONFIG_X86_IO_APIC
+ down_write(&acpi_ioapic_rwsem);
+ ret = mp_unregister_ioapic(gsi_base);
+ up_write(&acpi_ioapic_rwsem);
+#endif
+ return ret;
+}
EXPORT_SYMBOL(acpi_unregister_ioapic);
static int __init acpi_parse_sbf(struct acpi_table_header *table)
@@ -2949,6 +2949,18 @@ static int ioapic_create_irqdomain(int idx)
return 0;
}
+static void ioapic_destroy_irqdomain(int idx)
+{
+ if (ioapics[idx].irqdomain) {
+ irq_domain_remove(ioapics[idx].irqdomain);
+ ioapics[idx].irqdomain = NULL;
+ }
+ if (ioapics[idx].pin_info) {
+ kfree(ioapics[idx].pin_info);
+ ioapics[idx].pin_info = NULL;
+ }
+}
+
static void ioapic_create_irqdomains(void)
{
int idx;
@@ -3904,6 +3916,40 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
return 0;
}
+int mp_unregister_ioapic(u32 gsi_base)
+{
+ int ioapic, pin;
+ int found = 0;
+ struct mp_pin_info *pin_info;
+
+ for_each_ioapic(ioapic)
+ if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
+ found = 1;
+ break;
+ }
+ if (!found) {
+ pr_warn("can't find IOAPIC for GSI %d\n", gsi_base);
+ return -ENODEV;
+ }
+
+ for_each_pin(ioapic, pin) {
+ pin_info = mp_pin_info(ioapic, pin);
+ if (pin_info->count) {
+ pr_warn("pin%d on IOAPIC%d is still in use.\n",
+ pin, ioapic);
+ return -EBUSY;
+ }
+ }
+
+ /* Mark entry not present */
+ ioapics[ioapic].nr_registers = 0;
+ ioapic_destroy_irqdomain(ioapic);
+ clear_fixmap(FIX_IO_APIC_BASE_0 + ioapic);
+ memset(&ioapics[ioapic], 0, sizeof(ioapics[ioapic]));
+
+ return 0;
+}
+
struct irq_domain *mp_irqdomain_create(int ioapic, struct device_node *np,
const struct irq_domain_ops *ops)
{
Implement acpi_unregister_ioapic() to support ACPI based IOAPIC hot-removal. An IOAPIC could only be removed when all its pins are unused. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> --- arch/x86/include/asm/io_apic.h | 1 + arch/x86/kernel/acpi/boot.c | 13 ++++++++---- arch/x86/kernel/apic/io_apic.c | 46 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-)