vserver 2.0 rc7
[linux-2.6.git] / arch / ppc / syslib / cpm2_pic.c
index bd8335b..c867be6 100644 (file)
@@ -32,15 +32,17 @@ static      u_char  irq_to_siureg[] = {
        0, 0, 0, 0, 0, 0, 0, 0
 };
 
+/* bit numbers do not match the docs, these are precomputed so the bit for
+ * a given irq is (1 << irq_to_siubit[irq]) */
 static u_char  irq_to_siubit[] = {
-       31, 16, 17, 18, 19, 20, 21, 22,
-       23, 24, 25, 26, 27, 28, 29, 30,
-       29, 30, 16, 17, 18, 19, 20, 21,
-       22, 23, 24, 25, 26, 27, 28, 31,
-        0,  1,  2,  3,  4,  5,  6,  7,
-        8,  9, 10, 11, 12, 13, 14, 15,
-       15, 14, 13, 12, 11, 10,  9,  8,
-        7,  6,  5,  4,  3,  2,  1,  0
+        0, 15, 14, 13, 12, 11, 10,  9,
+        8,  7,  6,  5,  4,  3,  2,  1,
+        2,  1, 15, 14, 13, 12, 11, 10,
+        9,  8,  7,  6,  5,  4,  3,  0,
+       31, 30, 29, 28, 27, 26, 25, 24,
+       23, 22, 21, 20, 19, 18, 17, 16,
+       16, 17, 18, 19, 20, 21, 22, 23,
+       24, 25, 26, 27, 28, 29, 30, 31,
 };
 
 static void cpm2_mask_irq(unsigned int irq_nr)
@@ -48,11 +50,13 @@ static void cpm2_mask_irq(unsigned int irq_nr)
        int     bit, word;
        volatile uint   *simr;
 
+       irq_nr -= CPM_IRQ_OFFSET;
+
        bit = irq_to_siubit[irq_nr];
        word = irq_to_siureg[irq_nr];
 
        simr = &(cpm2_immr->im_intctl.ic_simrh);
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+       ppc_cached_irq_mask[word] &= ~(1 << bit);
        simr[word] = ppc_cached_irq_mask[word];
 }
 
@@ -61,11 +65,13 @@ static void cpm2_unmask_irq(unsigned int irq_nr)
        int     bit, word;
        volatile uint   *simr;
 
+       irq_nr -= CPM_IRQ_OFFSET;
+
        bit = irq_to_siubit[irq_nr];
        word = irq_to_siureg[irq_nr];
 
        simr = &(cpm2_immr->im_intctl.ic_simrh);
-       ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+       ppc_cached_irq_mask[word] |= 1 << bit;
        simr[word] = ppc_cached_irq_mask[word];
 }
 
@@ -74,14 +80,16 @@ static void cpm2_mask_and_ack(unsigned int irq_nr)
        int     bit, word;
        volatile uint   *simr, *sipnr;
 
+       irq_nr -= CPM_IRQ_OFFSET;
+
        bit = irq_to_siubit[irq_nr];
        word = irq_to_siureg[irq_nr];
 
        simr = &(cpm2_immr->im_intctl.ic_simrh);
        sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+       ppc_cached_irq_mask[word] &= ~(1 << bit);
        simr[word] = ppc_cached_irq_mask[word];
-       sipnr[word] = 1 << (31 - bit);
+       sipnr[word] = 1 << bit;
 }
 
 static void cpm2_end_irq(unsigned int irq_nr)
@@ -92,29 +100,30 @@ static void cpm2_end_irq(unsigned int irq_nr)
        if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
                        && irq_desc[irq_nr].action) {
 
+               irq_nr -= CPM_IRQ_OFFSET;
                bit = irq_to_siubit[irq_nr];
                word = irq_to_siureg[irq_nr];
 
                simr = &(cpm2_immr->im_intctl.ic_simrh);
-               ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+               ppc_cached_irq_mask[word] |= 1 << bit;
                simr[word] = ppc_cached_irq_mask[word];
+               /*
+                * Work around large numbers of spurious IRQs on PowerPC 82xx
+                * systems.
+                */
+               mb();
        }
 }
 
-struct hw_interrupt_type cpm2_pic = {
-       " CPM2 SIU  ",
-       NULL,
-       NULL,
-       cpm2_unmask_irq,
-       cpm2_mask_irq,
-       cpm2_mask_and_ack,
-       cpm2_end_irq,
-       0
+static struct hw_interrupt_type cpm2_pic = {
+       .typename = " CPM2 SIU ",
+       .enable = cpm2_unmask_irq,
+       .disable = cpm2_mask_irq,
+       .ack = cpm2_mask_and_ack,
+       .end = cpm2_end_irq,
 };
 
-
-int
-cpm2_get_irq(struct pt_regs *regs)
+int cpm2_get_irq(struct pt_regs *regs)
 {
        int irq;
         unsigned long bits;
@@ -126,5 +135,43 @@ cpm2_get_irq(struct pt_regs *regs)
 
        if (irq == 0)
                return(-1);
-       return irq;
+       return irq+CPM_IRQ_OFFSET;
+}
+
+void cpm2_init_IRQ(void)
+{
+       int i;
+
+       /* Clear the CPM IRQ controller, in case it has any bits set
+        * from the bootloader
+        */
+
+       /* Mask out everything */
+       cpm2_immr->im_intctl.ic_simrh = 0x00000000;
+       cpm2_immr->im_intctl.ic_simrl = 0x00000000;
+       wmb();
+
+       /* Ack everything */
+       cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
+       cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
+       wmb();
+
+       /* Dummy read of the vector */
+       i = cpm2_immr->im_intctl.ic_sivec;
+       rmb();
+
+       /* Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       cpm2_immr->im_intctl.ic_sicr = 0;
+       cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
+       cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
+
+
+       /* Enable chaining to OpenPIC, and make everything level
+        */
+       for (i = 0; i < NR_CPM_INTS; i++) {
+               irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+               irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
+       }
 }