[PATCH] genirq: convert the i386 architecture to irq-chips
authorIngo Molnar <mingo@elte.hu>
Wed, 4 Oct 2006 09:16:26 +0000 (02:16 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 4 Oct 2006 14:55:25 +0000 (07:55 -0700)
This patch converts all the i386 PIC controllers (except VisWS and Voyager,
which I could not test - but which should still work as old-style IRQ layers)
to the new and simpler irq-chip interrupt handling layer.

[akpm@osdl.org: build fix]
[mingo@elte.hu: enable fasteoi handler for i386 level-triggered IO-APIC irqs]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Roland Dreier <rolandd@cisco.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/i8259.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
include/asm-i386/hw_irq.h

index ea5f4e7958d8f072108576fb33000af089d93ab0..d07ed31f11e3269aed95d97c7cb8784c00cd3c11 100644 (file)
  * moves to arch independent land
  */
 
-DEFINE_SPINLOCK(i8259A_lock);
-
-static void end_8259A_irq (unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
-                                                       irq_desc[irq].action)
-               enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq     disable_8259A_irq
-
 static int i8259A_auto_eoi;
-
+DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
-unsigned int startup_8259A_irq(unsigned int irq)
-{ 
-       enable_8259A_irq(irq);
-       return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
-       .typename = "XT-PIC",
-       .startup = startup_8259A_irq,
-       .shutdown = shutdown_8259A_irq,
-       .enable = enable_8259A_irq,
-       .disable = disable_8259A_irq,
-       .ack = mask_and_ack_8259A,
-       .end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+       .name           = "XT-PIC",
+       .mask           = disable_8259A_irq,
+       .unmask         = enable_8259A_irq,
+       .mask_ack       = mask_and_ack_8259A,
 };
 
 /*
@@ -133,7 +113,7 @@ void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       irq_desc[irq].chip = &i8259A_irq_type;
+       set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
        enable_irq(irq);
 }
 
@@ -327,12 +307,12 @@ void init_8259A(int auto_eoi)
        outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
        if (auto_eoi)
                /*
-                * in AEOI mode we just have to mask the interrupt
+                * In AEOI mode we just have to mask the interrupt
                 * when acking.
                 */
-               i8259A_irq_type.ack = disable_8259A_irq;
+               i8259A_chip.mask_ack = disable_8259A_irq;
        else
-               i8259A_irq_type.ack = mask_and_ack_8259A;
+               i8259A_chip.mask_ack = mask_and_ack_8259A;
 
        udelay(100);            /* wait for 8259A to initialize */
 
@@ -389,12 +369,13 @@ void __init init_ISA_irqs (void)
                        /*
                         * 16 old-style INTA-cycle interrupts:
                         */
-                       irq_desc[i].chip = &i8259A_irq_type;
+                       set_irq_chip_and_handler(i, &i8259A_chip,
+                                                handle_level_irq);
                } else {
                        /*
                         * 'high' PCI IRQs filled in on demand
                         */
-                       irq_desc[i].chip = &no_irq_type;
+                       irq_desc[i].chip = &no_irq_chip;
                }
        }
 }
index fd0df75cfbdadd3fd19afd2f5aeaf0308d9e96ba..b3b01894ca690fbfc9775f0dc971aa3cdbfaa3e6 100644 (file)
@@ -1219,8 +1219,7 @@ next:
        return vector;
 }
 
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+static struct irq_chip ioapic_chip;
 
 #define IOAPIC_AUTO    -1
 #define IOAPIC_EDGE    0
@@ -1234,9 +1233,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].chip = &ioapic_level_type;
+               set_irq_chip_and_handler(idx, &ioapic_chip,
+                                        handle_fasteoi_irq);
        else
-               irq_desc[idx].chip = &ioapic_edge_type;
+               set_irq_chip_and_handler(idx, &ioapic_chip,
+                                        handle_edge_irq);
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -1346,7 +1347,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].chip = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_chip;
+       set_irq_handler(0, handle_edge_irq);
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -1918,6 +1920,8 @@ static int __init timer_irq_works(void)
  */
 
 /*
+ * Startup quirk:
+ *
  * Starting up a edge-triggered IO-APIC interrupt is
  * nasty - we need to make sure that we get the edge.
  * If it is already asserted for some reason, we need
@@ -1925,8 +1929,10 @@ static int __init timer_irq_works(void)
  *
  * This is not complete - we should be able to fake
  * an edge even if it isn't on the 8259A...
+ *
+ * (We do this for level-triggered IRQs too - it cannot hurt.)
  */
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
 {
        int was_pending = 0;
        unsigned long flags;
@@ -1943,42 +1949,13 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
        return was_pending;
 }
 
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static void ack_ioapic_irq(unsigned int irq)
 {
        move_irq(irq);
-       if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
-                                       == (IRQ_PENDING | IRQ_DISABLED))
-               mask_IO_APIC_irq(irq);
        ack_APIC_irq();
 }
 
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
-       unmask_IO_APIC_irq(irq);
-
-       return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
+static void ack_ioapic_quirk_irq(unsigned int irq)
 {
        unsigned long v;
        int i;
@@ -2018,35 +1995,27 @@ static void end_level_ioapic_irq (unsigned int irq)
        }
 }
 
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
+static unsigned int startup_ioapic_vector(unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
-       return startup_edge_ioapic_irq(irq);
+       return startup_ioapic_irq(irq);
 }
 
-static void ack_edge_ioapic_vector(unsigned int vector)
+static void ack_ioapic_vector(unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
        move_native_irq(vector);
-       ack_edge_ioapic_irq(irq);
+       ack_ioapic_irq(irq);
 }
 
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
-       int irq = vector_to_irq(vector);
-
-       return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
+static void ack_ioapic_quirk_vector(unsigned int vector)
 {
        int irq = vector_to_irq(vector);
 
        move_native_irq(vector);
-       end_level_ioapic_irq(irq);
+       ack_ioapic_quirk_irq(irq);
 }
 
 static void mask_IO_APIC_vector (unsigned int vector)
@@ -2063,7 +2032,12 @@ static void unmask_IO_APIC_vector (unsigned int vector)
        unmask_IO_APIC_irq(irq);
 }
 
-#ifdef CONFIG_SMP
+/*
+ * Oh just glorious.  If CONFIG_PCI_MSI we've done
+ * #define set_ioapic_affinity set_ioapic_affinity_vector
+ */
+#if defined (CONFIG_SMP) && defined(CONFIG_X86_IO_APIC) && \
+               defined(CONFIG_PCI_MSI)
 static void set_ioapic_affinity_vector (unsigned int vector,
                                        cpumask_t cpu_mask)
 {
@@ -2073,50 +2047,29 @@ static void set_ioapic_affinity_vector (unsigned int vector,
        set_ioapic_affinity_irq(irq, cpu_mask);
 }
 #endif
-#endif
 
-static int ioapic_retrigger(unsigned int irq)
+static int ioapic_retrigger_vector(unsigned int vector)
 {
+       int irq = vector_to_irq(vector);
+
        send_IPI_self(IO_APIC_VECTOR(irq));
 
        return 1;
 }
 
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
-       .typename       = "IO-APIC-edge",
-       .startup        = startup_edge_ioapic,
-       .shutdown       = shutdown_edge_ioapic,
-       .enable         = enable_edge_ioapic,
-       .disable        = disable_edge_ioapic,
-       .ack            = ack_edge_ioapic,
-       .end            = end_edge_ioapic,
+static struct irq_chip ioapic_chip __read_mostly = {
+       .name           = "IO-APIC",
+       .startup        = startup_ioapic_vector,
+       .mask           = mask_IO_APIC_vector,
+       .unmask         = unmask_IO_APIC_vector,
+       .ack            = ack_ioapic_vector,
+       .eoi            = ack_ioapic_quirk_vector,
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
-       .retrigger      = ioapic_retrigger,
+       .retrigger      = ioapic_retrigger_vector,
 };
 
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
-       .typename       = "IO-APIC-level",
-       .startup        = startup_level_ioapic,
-       .shutdown       = shutdown_level_ioapic,
-       .enable         = enable_level_ioapic,
-       .disable        = disable_level_ioapic,
-       .ack            = mask_and_ack_level_ioapic,
-       .end            = end_level_ioapic,
-#ifdef CONFIG_SMP
-       .set_affinity   = set_ioapic_affinity,
-#endif
-       .retrigger      = ioapic_retrigger,
-};
 
 static inline void init_IO_APIC_traps(void)
 {
@@ -2150,20 +2103,21 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].chip = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_chip;
                }
        }
 }
 
-static void enable_lapic_irq (unsigned int irq)
-{
-       unsigned long v;
+/*
+ * The local APIC irq-chip implementation:
+ */
 
-       v = apic_read(APIC_LVT0);
-       apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+static void ack_apic(unsigned int irq)
+{
+       ack_APIC_irq();
 }
 
-static void disable_lapic_irq (unsigned int irq)
+static void mask_lapic_irq (unsigned int irq)
 {
        unsigned long v;
 
@@ -2171,21 +2125,19 @@ static void disable_lapic_irq (unsigned int irq)
        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
 }
 
-static void ack_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq (unsigned int irq)
 {
-       ack_APIC_irq();
-}
+       unsigned long v;
 
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
+       v = apic_read(APIC_LVT0);
+       apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+}
 
-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
-       .typename       = "local-APIC-edge",
-       .startup        = NULL, /* startup_irq() not used for IRQ0 */
-       .shutdown       = NULL, /* shutdown_irq() not used for IRQ0 */
-       .enable         = enable_lapic_irq,
-       .disable        = disable_lapic_irq,
-       .ack            = ack_lapic_irq,
-       .end            = end_lapic_irq
+static struct irq_chip lapic_chip __read_mostly = {
+       .name           = "local-APIC-edge",
+       .mask           = mask_lapic_irq,
+       .unmask         = unmask_lapic_irq,
+       .eoi            = ack_apic,
 };
 
 static void setup_nmi (void)
@@ -2356,7 +2308,7 @@ static inline void check_timer(void)
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].chip = &lapic_irq_type;
+       set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
index 5fe547cd8f9fe48ab7d2e3dae930283b6baff70b..3dd2e180151bcc868c80be75875d9c054b316a26 100644 (file)
@@ -55,6 +55,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
 {      
        /* high bit used in ret_from_ code */
        int irq = ~regs->orig_eax;
+       struct irq_desc *desc = irq_desc + irq;
 #ifdef CONFIG_4KSTACKS
        union irq_ctx *curctx, *irqctx;
        u32 *isp;
@@ -94,7 +95,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
         * current stack (which is the irq stack already after all)
         */
        if (curctx != irqctx) {
-               int arg1, arg2, ebx;
+               int arg1, arg2, arg3, ebx;
 
                /* build the stack frame on the IRQ stack */
                isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -110,16 +111,17 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
                        (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
 
                asm volatile(
-                       "       xchgl   %%ebx,%%esp      \n"
-                       "       call    __do_IRQ         \n"
+                       "       xchgl  %%ebx,%%esp      \n"
+                       "       call   *%%edi           \n"
                        "       movl   %%ebx,%%esp      \n"
-                       : "=a" (arg1), "=d" (arg2), "=b" (ebx)
-                       :  "0" (irq),   "1" (regs),  "2" (isp)
-                       : "memory", "cc", "ecx"
+                       : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
+                       :  "0" (irq),   "1" (desc),  "2" (regs),  "3" (isp),
+                          "D" (desc->handle_irq)
+                       : "memory", "cc"
                );
        } else
 #endif
-               __do_IRQ(irq, regs);
+               desc->handle_irq(irq, desc, regs);
 
        irq_exit();
 
@@ -253,7 +255,8 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %8s", irq_desc[i].chip->name);
+               seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 87e5a351d8812b369bf1fc88187214d947d87fa9..8e8fbfaa252a236e21d717211c66f26b37529256 100644 (file)
@@ -17,8 +17,6 @@
 #include <asm/irq.h>
 #include <asm/sections.h>
 
-struct hw_interrupt_type;
-
 #define NMI_VECTOR             0x02
 
 /*