x86, io_apic: Introduce x86_io_apic_ops.disable()
authorJoerg Roedel <joro@8bytes.org>
Wed, 26 Sep 2012 10:44:35 +0000 (12:44 +0200)
committerJoerg Roedel <joro@8bytes.org>
Mon, 28 Jan 2013 09:48:30 +0000 (10:48 +0100)
This function pointer is used to call a system-specific
function for disabling the IO-APIC. Currently this is used
for IRQ remapping which has its own disable routine.

Also introduce the necessary infrastructure in the interrupt
remapping code to overwrite this and other function pointers
as necessary by interrupt remapping.

Signed-off-by: Joerg Roedel <joro@8bytes.org>
Acked-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/x86_init.c
drivers/iommu/irq_remapping.c

index 73d8c5398ea995dd685ad00ad99b17fd69c5c1b4..d59e17232c4d62e397866b9ddc086d2c9b6d44b0 100644 (file)
@@ -179,6 +179,7 @@ extern void __init native_io_apic_init_mappings(void);
 extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
 extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
 extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+extern void native_disable_io_apic(void);
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
@@ -223,6 +224,7 @@ static inline void disable_ioapic_support(void) { }
 #define native_io_apic_read            NULL
 #define native_io_apic_write           NULL
 #define native_io_apic_modify          NULL
+#define native_disable_io_apic         NULL
 #endif
 
 #endif /* _ASM_X86_IO_APIC_H */
index 57693498519c4a69962417c8889b376182b49e2f..b1d2d6aefcc951efa0df240b14fe7f7efa080c25 100644 (file)
@@ -190,10 +190,11 @@ struct x86_msi_ops {
 };
 
 struct x86_io_apic_ops {
-       void            (*init)  (void);
-       unsigned int    (*read)  (unsigned int apic, unsigned int reg);
-       void            (*write) (unsigned int apic, unsigned int reg, unsigned int value);
-       void            (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*init)   (void);
+       unsigned int    (*read)   (unsigned int apic, unsigned int reg);
+       void            (*write)  (unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*disable)(void);
 };
 
 extern struct x86_init_ops x86_init;
index 2016f9dabd72153081221960f016297dfd154ffb..cd5f4d7cc163d2218e95db136f066488b2dbfe80 100644 (file)
@@ -1921,30 +1921,14 @@ void __init enable_IO_APIC(void)
        clear_IO_APIC();
 }
 
-/*
- * Not an __init, needed by the reboot code
- */
-void disable_IO_APIC(void)
+void native_disable_io_apic(void)
 {
-       /*
-        * Clear the IO-APIC before rebooting:
-        */
-       clear_IO_APIC();
-
-       if (!legacy_pic->nr_legacy_irqs)
-               return;
-
        /*
         * If the i8259 is routed through an IOAPIC
         * Put that IOAPIC in virtual wire mode
         * so legacy interrupts can be delivered.
-        *
-        * With interrupt-remapping, for now we will use virtual wire A mode,
-        * as virtual wire B is little complex (need to configure both
-        * IOAPIC RTE as well as interrupt-remapping table entry).
-        * As this gets called during crash dump, keep this simple for now.
         */
-       if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) {
+       if (ioapic_i8259.pin != -1) {
                struct IO_APIC_route_entry entry;
 
                memset(&entry, 0, sizeof(entry));
@@ -1964,12 +1948,25 @@ void disable_IO_APIC(void)
                ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
        }
 
+       if (cpu_has_apic || apic_from_smp_config())
+               disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+
+}
+
+/*
+ * Not an __init, needed by the reboot code
+ */
+void disable_IO_APIC(void)
+{
        /*
-        * Use virtual wire A mode when interrupt remapping is enabled.
+        * Clear the IO-APIC before rebooting:
         */
-       if (cpu_has_apic || apic_from_smp_config())
-               disconnect_bsp_APIC(!irq_remapping_enabled &&
-                               ioapic_i8259.pin != -1);
+       clear_IO_APIC();
+
+       if (!legacy_pic->nr_legacy_irqs)
+               return;
+
+       x86_io_apic_ops.disable();
 }
 
 #ifdef CONFIG_X86_32
index 7a3d075a814a9c83a603df93b5961f247049e624..754524acc8459f3ef966fd4e688a7a0ec1e5ff0f 100644 (file)
@@ -118,8 +118,9 @@ struct x86_msi_ops x86_msi = {
 };
 
 struct x86_io_apic_ops x86_io_apic_ops = {
-       .init   = native_io_apic_init_mappings,
-       .read   = native_io_apic_read,
-       .write  = native_io_apic_write,
-       .modify = native_io_apic_modify,
+       .init                   = native_io_apic_init_mappings,
+       .read                   = native_io_apic_read,
+       .write                  = native_io_apic_write,
+       .modify                 = native_io_apic_modify,
+       .disable                = native_disable_io_apic,
 };
index 19381b90e619175028fdabfb806ffe791d3fed19..db3dcaf4ddf08374f92036af32ccb7d3b5ea4f82 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/cpumask.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/cpumask.h>
@@ -6,6 +7,9 @@
 
 #include <asm/hw_irq.h>
 #include <asm/irq_remapping.h>
+#include <asm/processor.h>
+#include <asm/x86_init.h>
+#include <asm/apic.h>
 
 #include "irq_remapping.h"
 
@@ -17,6 +21,24 @@ int no_x2apic_optout;
 
 static struct irq_remap_ops *remap_ops;
 
+static void irq_remapping_disable_io_apic(void)
+{
+       /*
+        * With interrupt-remapping, for now we will use virtual wire A
+        * mode, as virtual wire B is little complex (need to configure
+        * both IOAPIC RTE as well as interrupt-remapping table entry).
+        * As this gets called during crash dump, keep this simple for
+        * now.
+        */
+       if (cpu_has_apic || apic_from_smp_config())
+               disconnect_bsp_APIC(0);
+}
+
+static void __init irq_remapping_modify_x86_ops(void)
+{
+       x86_io_apic_ops.disable =       irq_remapping_disable_io_apic;
+}
+
 static __init int setup_nointremap(char *str)
 {
        disable_irq_remap = 1;
@@ -79,10 +101,17 @@ int __init irq_remapping_prepare(void)
 
 int __init irq_remapping_enable(void)
 {
+       int ret;
+
        if (!remap_ops || !remap_ops->enable)
                return -ENODEV;
 
-       return remap_ops->enable();
+       ret = remap_ops->enable();
+
+       if (irq_remapping_enabled)
+               irq_remapping_modify_x86_ops();
+
+       return ret;
 }
 
 void irq_remapping_disable(void)