Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / ppc / syslib / i8259.c
index b9391e6..eb35353 100644 (file)
@@ -1,18 +1,26 @@
+/*
+ * i8259 interrupt controller driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/i8259.h>
 
-static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
+static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */
 
-unsigned char cached_8259[2] = { 0xff, 0xff };
+static unsigned char cached_8259[2] = { 0xff, 0xff };
 #define cached_A1 (cached_8259[0])
 #define cached_21 (cached_8259[1])
 
 static DEFINE_SPINLOCK(i8259_lock);
 
-int i8259_pic_irq_offset;
+static int i8259_pic_irq_offset;
 
 /*
  * Acknowledge the IRQ using either the PCI host bridge's interrupt
@@ -20,8 +28,7 @@ int i8259_pic_irq_offset;
  * which is called.  It should be noted that polling is broken on some
  * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
  */
-int
-i8259_irq(struct pt_regs *regs)
+int i8259_irq(struct pt_regs *regs)
 {
        int irq;
 
@@ -29,7 +36,7 @@ i8259_irq(struct pt_regs *regs)
 
        /* Either int-ack or poll for the IRQ */
        if (pci_intack)
-               irq = *pci_intack;
+               irq = readb(pci_intack);
        else {
                /* Perform an interrupt acknowledge cycle on controller 1. */
                outb(0x0C, 0x20);               /* prepare for poll */
@@ -59,7 +66,7 @@ i8259_irq(struct pt_regs *regs)
        }
 
        spin_unlock(&i8259_lock);
-       return irq;
+       return irq + i8259_pic_irq_offset;
 }
 
 static void i8259_mask_and_ack_irq(unsigned int irq_nr)
@@ -67,20 +74,18 @@ static void i8259_mask_and_ack_irq(unsigned int irq_nr)
        unsigned long flags;
 
        spin_lock_irqsave(&i8259_lock, flags);
-       if ( irq_nr >= i8259_pic_irq_offset )
-               irq_nr -= i8259_pic_irq_offset;
-
+       irq_nr -= i8259_pic_irq_offset;
        if (irq_nr > 7) {
                cached_A1 |= 1 << (irq_nr-8);
-               inb(0xA1); /* DUMMY */
-               outb(cached_A1,0xA1);
-               outb(0x20,0xA0); /* Non-specific EOI */
-               outb(0x20,0x20); /* Non-specific EOI to cascade */
+               inb(0xA1);      /* DUMMY */
+               outb(cached_A1, 0xA1);
+               outb(0x20, 0xA0);       /* Non-specific EOI */
+               outb(0x20, 0x20);       /* Non-specific EOI to cascade */
        } else {
                cached_21 |= 1 << irq_nr;
-               inb(0x21); /* DUMMY */
-               outb(cached_21,0x21);
-               outb(0x20,0x20); /* Non-specific EOI */
+               inb(0x21);      /* DUMMY */
+               outb(cached_21, 0x21);
+               outb(0x20, 0x20);       /* Non-specific EOI */
        }
        spin_unlock_irqrestore(&i8259_lock, flags);
 }
@@ -96,9 +101,8 @@ static void i8259_mask_irq(unsigned int irq_nr)
        unsigned long flags;
 
        spin_lock_irqsave(&i8259_lock, flags);
-       if ( irq_nr >= i8259_pic_irq_offset )
-               irq_nr -= i8259_pic_irq_offset;
-       if ( irq_nr < 8 )
+       irq_nr -= i8259_pic_irq_offset;
+       if (irq_nr < 8)
                cached_21 |= 1 << irq_nr;
        else
                cached_A1 |= 1 << (irq_nr-8);
@@ -111,9 +115,8 @@ static void i8259_unmask_irq(unsigned int irq_nr)
        unsigned long flags;
 
        spin_lock_irqsave(&i8259_lock, flags);
-       if ( irq_nr >= i8259_pic_irq_offset )
-               irq_nr -= i8259_pic_irq_offset;
-       if ( irq_nr < 8 )
+       irq_nr -= i8259_pic_irq_offset;
+       if (irq_nr < 8)
                cached_21 &= ~(1 << irq_nr);
        else
                cached_A1 &= ~(1 << (irq_nr-8));
@@ -121,22 +124,11 @@ static void i8259_unmask_irq(unsigned int irq_nr)
        spin_unlock_irqrestore(&i8259_lock, flags);
 }
 
-static void i8259_end_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-           && irq_desc[irq].action)
-               i8259_unmask_irq(irq);
-}
-
-struct hw_interrupt_type i8259_pic = {
-       " i8259    ",
-       NULL,
-       NULL,
-       i8259_unmask_irq,
-       i8259_mask_irq,
-       i8259_mask_and_ack_irq,
-       i8259_end_irq,
-       NULL
+static struct irq_chip i8259_pic = {
+       .typename       = " i8259    ",
+       .mask           = i8259_mask_irq,
+       .unmask         = i8259_unmask_irq,
+       .mask_ack       = i8259_mask_and_ack_irq,
 };
 
 static struct resource pic1_iores = {
@@ -172,12 +164,14 @@ static struct irqaction i8259_irqaction = {
  * intack_addr - PCI interrupt acknowledge (real) address which will return
  *               the active irq from the 8259
  */
-void __init
-i8259_init(long intack_addr)
+void __init i8259_init(unsigned long intack_addr, int offset)
 {
        unsigned long flags;
+       int i;
 
        spin_lock_irqsave(&i8259_lock, flags);
+       i8259_pic_irq_offset = offset;
+
        /* init master interrupt controller */
        outb(0x11, 0x20); /* Start init sequence */
        outb(0x00, 0x21); /* Vector base */
@@ -200,12 +194,19 @@ i8259_init(long intack_addr)
 
        spin_unlock_irqrestore(&i8259_lock, flags);
 
+       for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) {
+               set_irq_chip_and_handler(offset + i, &i8259_pic,
+                                        handle_level_irq);
+               irq_desc[offset + i].status |= IRQ_LEVEL;
+       }
+
        /* reserve our resources */
-       setup_irq( i8259_pic_irq_offset + 2, &i8259_irqaction);
+       setup_irq(offset + 2, &i8259_irqaction);
        request_resource(&ioport_resource, &pic1_iores);
        request_resource(&ioport_resource, &pic2_iores);
        request_resource(&ioport_resource, &pic_edgectrl_iores);
 
        if (intack_addr != 0)
                pci_intack = ioremap(intack_addr, 1);
+
 }