|
@@ -112,6 +112,7 @@ static struct ioapic {
|
|
|
struct ioapic_domain_cfg irqdomain_cfg;
|
|
|
struct irq_domain *irqdomain;
|
|
|
struct mp_pin_info *pin_info;
|
|
|
+ struct resource *iomem_res;
|
|
|
} ioapics[MAX_IO_APICS];
|
|
|
|
|
|
#define mpc_ioapic_ver(ioapic_idx) ioapics[ioapic_idx].mp_config.apicver
|
|
@@ -250,6 +251,12 @@ static void alloc_ioapic_saved_registers(int idx)
|
|
|
pr_err("IOAPIC %d: suspend/resume impossible!\n", idx);
|
|
|
}
|
|
|
|
|
|
+static void free_ioapic_saved_registers(int idx)
|
|
|
+{
|
|
|
+ kfree(ioapics[idx].saved_registers);
|
|
|
+ ioapics[idx].saved_registers = NULL;
|
|
|
+}
|
|
|
+
|
|
|
int __init arch_early_irq_init(void)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
@@ -2973,6 +2980,16 @@ static int mp_irqdomain_create(int ioapic)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ioapic_destroy_irqdomain(int idx)
|
|
|
+{
|
|
|
+ if (ioapics[idx].irqdomain) {
|
|
|
+ irq_domain_remove(ioapics[idx].irqdomain);
|
|
|
+ ioapics[idx].irqdomain = NULL;
|
|
|
+ }
|
|
|
+ kfree(ioapics[idx].pin_info);
|
|
|
+ ioapics[idx].pin_info = NULL;
|
|
|
+}
|
|
|
+
|
|
|
void __init setup_IO_APIC(void)
|
|
|
{
|
|
|
int ioapic;
|
|
@@ -3743,6 +3760,7 @@ static struct resource * __init ioapic_setup_resources(void)
|
|
|
snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
|
|
|
mem += IOAPIC_RESOURCE_NAME_SIZE;
|
|
|
num++;
|
|
|
+ ioapics[i].iomem_res = res;
|
|
|
}
|
|
|
|
|
|
ioapic_resources = res;
|
|
@@ -3971,6 +3989,43 @@ 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);
|
|
|
+ free_ioapic_saved_registers(ioapic);
|
|
|
+ if (ioapics[ioapic].iomem_res)
|
|
|
+ release_resource(ioapics[ioapic].iomem_res);
|
|
|
+ clear_fixmap(FIX_IO_APIC_BASE_0 + ioapic);
|
|
|
+ memset(&ioapics[ioapic], 0, sizeof(ioapics[ioapic]));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
|
|
|
irq_hw_number_t hwirq)
|
|
|
{
|