linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / powerpc / sysdev / mpic.c
index b604926..7dcdfcb 100644 (file)
@@ -17,6 +17,7 @@
 #undef DEBUG_IRQ
 #undef DEBUG_LOW
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -54,94 +55,6 @@ static DEFINE_SPINLOCK(mpic_lock);
 #endif
 #endif
 
-#ifdef CONFIG_MPIC_WEIRD
-static u32 mpic_infos[][MPIC_IDX_END] = {
-       [0] = { /* Original OpenPIC compatible MPIC */
-               MPIC_GREG_BASE,
-               MPIC_GREG_FEATURE_0,
-               MPIC_GREG_GLOBAL_CONF_0,
-               MPIC_GREG_VENDOR_ID,
-               MPIC_GREG_IPI_VECTOR_PRI_0,
-               MPIC_GREG_IPI_STRIDE,
-               MPIC_GREG_SPURIOUS,
-               MPIC_GREG_TIMER_FREQ,
-
-               MPIC_TIMER_BASE,
-               MPIC_TIMER_STRIDE,
-               MPIC_TIMER_CURRENT_CNT,
-               MPIC_TIMER_BASE_CNT,
-               MPIC_TIMER_VECTOR_PRI,
-               MPIC_TIMER_DESTINATION,
-
-               MPIC_CPU_BASE,
-               MPIC_CPU_STRIDE,
-               MPIC_CPU_IPI_DISPATCH_0,
-               MPIC_CPU_IPI_DISPATCH_STRIDE,
-               MPIC_CPU_CURRENT_TASK_PRI,
-               MPIC_CPU_WHOAMI,
-               MPIC_CPU_INTACK,
-               MPIC_CPU_EOI,
-
-               MPIC_IRQ_BASE,
-               MPIC_IRQ_STRIDE,
-               MPIC_IRQ_VECTOR_PRI,
-               MPIC_VECPRI_VECTOR_MASK,
-               MPIC_VECPRI_POLARITY_POSITIVE,
-               MPIC_VECPRI_POLARITY_NEGATIVE,
-               MPIC_VECPRI_SENSE_LEVEL,
-               MPIC_VECPRI_SENSE_EDGE,
-               MPIC_VECPRI_POLARITY_MASK,
-               MPIC_VECPRI_SENSE_MASK,
-               MPIC_IRQ_DESTINATION
-       },
-       [1] = { /* Tsi108/109 PIC */
-               TSI108_GREG_BASE,
-               TSI108_GREG_FEATURE_0,
-               TSI108_GREG_GLOBAL_CONF_0,
-               TSI108_GREG_VENDOR_ID,
-               TSI108_GREG_IPI_VECTOR_PRI_0,
-               TSI108_GREG_IPI_STRIDE,
-               TSI108_GREG_SPURIOUS,
-               TSI108_GREG_TIMER_FREQ,
-
-               TSI108_TIMER_BASE,
-               TSI108_TIMER_STRIDE,
-               TSI108_TIMER_CURRENT_CNT,
-               TSI108_TIMER_BASE_CNT,
-               TSI108_TIMER_VECTOR_PRI,
-               TSI108_TIMER_DESTINATION,
-
-               TSI108_CPU_BASE,
-               TSI108_CPU_STRIDE,
-               TSI108_CPU_IPI_DISPATCH_0,
-               TSI108_CPU_IPI_DISPATCH_STRIDE,
-               TSI108_CPU_CURRENT_TASK_PRI,
-               TSI108_CPU_WHOAMI,
-               TSI108_CPU_INTACK,
-               TSI108_CPU_EOI,
-
-               TSI108_IRQ_BASE,
-               TSI108_IRQ_STRIDE,
-               TSI108_IRQ_VECTOR_PRI,
-               TSI108_VECPRI_VECTOR_MASK,
-               TSI108_VECPRI_POLARITY_POSITIVE,
-               TSI108_VECPRI_POLARITY_NEGATIVE,
-               TSI108_VECPRI_SENSE_LEVEL,
-               TSI108_VECPRI_SENSE_EDGE,
-               TSI108_VECPRI_POLARITY_MASK,
-               TSI108_VECPRI_SENSE_MASK,
-               TSI108_IRQ_DESTINATION
-       },
-};
-
-#define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name]
-
-#else /* CONFIG_MPIC_WEIRD */
-
-#define MPIC_INFO(name) MPIC_##name
-
-#endif /* CONFIG_MPIC_WEIRD */
-
 /*
  * Register accessor functions
  */
@@ -168,8 +81,7 @@ static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base,
 static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
 {
        unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0;
-       unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
-                             (ipi * MPIC_INFO(GREG_IPI_STRIDE));
+       unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
 
        if (mpic->flags & MPIC_BROKEN_IPI)
                be = !be;
@@ -178,8 +90,7 @@ static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
 
 static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value)
 {
-       unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
-                             (ipi * MPIC_INFO(GREG_IPI_STRIDE));
+       unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
 
        _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value);
 }
@@ -190,8 +101,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
 
        if (mpic->flags & MPIC_PRIMARY)
                cpu = hard_smp_processor_id();
-       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
-                         mpic->cpuregs[cpu], reg);
+
+       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg);
 }
 
 static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
@@ -210,7 +121,7 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne
        unsigned int    idx = src_no & mpic->isu_mask;
 
        return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
-                         reg + (idx * MPIC_INFO(IRQ_STRIDE)));
+                         reg + (idx * MPIC_IRQ_STRIDE));
 }
 
 static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
@@ -220,7 +131,7 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
        unsigned int    idx = src_no & mpic->isu_mask;
 
        _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
-                   reg + (idx * MPIC_INFO(IRQ_STRIDE)), value);
+                   reg + (idx * MPIC_IRQ_STRIDE), value);
 }
 
 #define mpic_read(b,r)         _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r))
@@ -246,8 +157,8 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
 {
        u32 r;
 
-       mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK);
-       r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0));
+       mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK);
+       r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0);
 
        if (r == le32_to_cpu(MPIC_VECPRI_MASK)) {
                printk(KERN_INFO "mpic: Detected reversed IPI registers\n");
@@ -294,7 +205,7 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
        if (fixup->base == NULL)
                return;
 
-       DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n",
+       DBG("startup_ht_interrupt(%u, %u) index: %d\n",
            source, irqflags, fixup->index);
        spin_lock_irqsave(&mpic->fixup_lock, flags);
        /* Enable and configure */
@@ -317,7 +228,7 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
        if (fixup->base == NULL)
                return;
 
-       DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags);
+       DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
 
        /* Disable */
        spin_lock_irqsave(&mpic->fixup_lock, flags);
@@ -427,33 +338,30 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
        }
 }
 
-#else /* CONFIG_MPIC_BROKEN_U3 */
-
-static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
-{
-       return 0;
-}
-
-static void __init mpic_scan_ht_pics(struct mpic *mpic)
-{
-}
-
 #endif /* CONFIG_MPIC_BROKEN_U3 */
 
 
-#define mpic_irq_to_hw(virq)   ((unsigned int)irq_map[virq].hwirq)
-
 /* Find an mpic associated with a given linux interrupt */
 static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
 {
-       unsigned int src = mpic_irq_to_hw(irq);
-
-       if (irq < NUM_ISA_INTERRUPTS)
-               return NULL;
-       if (is_ipi)
-               *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3);
-
-       return irq_desc[irq].chip_data;
+       struct mpic *mpic = mpics;
+
+       while(mpic) {
+               /* search IPIs first since they may override the main interrupts */
+               if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) {
+                       if (is_ipi)
+                               *is_ipi = 1;
+                       return mpic;
+               }
+               if (irq >= mpic->irq_offset &&
+                   irq < (mpic->irq_offset + mpic->irq_count)) {
+                       if (is_ipi)
+                               *is_ipi = 0;
+                       return mpic;
+               }
+               mpic = mpic -> next;
+       }
+       return NULL;
 }
 
 /* Convert a cpu mask from logical to physical cpu numbers. */
@@ -471,27 +379,29 @@ static inline u32 mpic_physmask(u32 cpumask)
 /* Get the mpic structure from the IPI number */
 static inline struct mpic * mpic_from_ipi(unsigned int ipi)
 {
-       return irq_desc[ipi].chip_data;
+       return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi);
 }
 #endif
 
 /* Get the mpic structure from the irq number */
 static inline struct mpic * mpic_from_irq(unsigned int irq)
 {
-       return irq_desc[irq].chip_data;
+       return container_of(irq_desc[irq].handler, struct mpic, hc_irq);
 }
 
 /* Send an EOI */
 static inline void mpic_eoi(struct mpic *mpic)
 {
-       mpic_cpu_write(MPIC_INFO(CPU_EOI), 0);
-       (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI));
+       mpic_cpu_write(MPIC_CPU_EOI, 0);
+       (void)mpic_cpu_read(MPIC_CPU_WHOAMI);
 }
 
 #ifdef CONFIG_SMP
 static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-       smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs);
+       struct mpic *mpic = dev_id;
+
+       smp_message_recv(irq - mpic->ipi_offset, regs);
        return IRQ_HANDLED;
 }
 #endif /* CONFIG_SMP */
@@ -501,36 +411,63 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
  */
 
 
-static void mpic_unmask_irq(unsigned int irq)
+static void mpic_enable_irq(unsigned int irq)
 {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
+       unsigned int src = irq - mpic->irq_offset;
 
        DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
-       mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
-                      mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
+       mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+                      mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
                       ~MPIC_VECPRI_MASK);
+
        /* make sure mask gets to controller before we return to user */
        do {
                if (!loops--) {
                        printk(KERN_ERR "mpic_enable_irq timeout\n");
                        break;
                }
-       } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
+       } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);    
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       if (mpic->flags & MPIC_BROKEN_U3) {
+               unsigned int src = irq - mpic->irq_offset;
+               if (mpic_is_ht_interrupt(mpic, src) &&
+                   (irq_desc[irq].status & IRQ_LEVEL))
+                       mpic_ht_end_irq(mpic, src);
+       }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+}
+
+static unsigned int mpic_startup_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       mpic_enable_irq(irq);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       if (mpic_is_ht_interrupt(mpic, src))
+               mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       return 0;
 }
 
-static void mpic_mask_irq(unsigned int irq)
+static void mpic_disable_irq(unsigned int irq)
 {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
+       unsigned int src = irq - mpic->irq_offset;
 
        DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 
-       mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
-                      mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
+       mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+                      mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
                       MPIC_VECPRI_MASK);
 
        /* make sure mask gets to controller before we return to user */
@@ -539,61 +476,26 @@ static void mpic_mask_irq(unsigned int irq)
                        printk(KERN_ERR "mpic_enable_irq timeout\n");
                        break;
                }
-       } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
+       } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
 }
 
-static void mpic_end_irq(unsigned int irq)
+static void mpic_shutdown_irq(unsigned int irq)
 {
-       struct mpic *mpic = mpic_from_irq(irq);
-
-#ifdef DEBUG_IRQ
-       DBG("%s: end_irq: %d\n", mpic->name, irq);
-#endif
-       /* We always EOI on end_irq() even for edge interrupts since that
-        * should only lower the priority, the MPIC should have properly
-        * latched another edge interrupt coming in anyway
-        */
-
-       mpic_eoi(mpic);
-}
-
 #ifdef CONFIG_MPIC_BROKEN_U3
-
-static void mpic_unmask_ht_irq(unsigned int irq)
-{
-       struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
-
-       mpic_unmask_irq(irq);
-
-       if (irq_desc[irq].status & IRQ_LEVEL)
-               mpic_ht_end_irq(mpic, src);
-}
-
-static unsigned int mpic_startup_ht_irq(unsigned int irq)
-{
        struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
-
-       mpic_unmask_irq(irq);
-       mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+       unsigned int src = irq - mpic->irq_offset;
 
-       return 0;
-}
+       if (mpic_is_ht_interrupt(mpic, src))
+               mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
 
-static void mpic_shutdown_ht_irq(unsigned int irq)
-{
-       struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
 
-       mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
-       mpic_mask_irq(irq);
+       mpic_disable_irq(irq);
 }
 
-static void mpic_end_ht_irq(unsigned int irq)
+static void mpic_end_irq(unsigned int irq)
 {
        struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
 
 #ifdef DEBUG_IRQ
        DBG("%s: end_irq: %d\n", mpic->name, irq);
@@ -603,24 +505,30 @@ static void mpic_end_ht_irq(unsigned int irq)
         * latched another edge interrupt coming in anyway
         */
 
-       if (irq_desc[irq].status & IRQ_LEVEL)
-               mpic_ht_end_irq(mpic, src);
+#ifdef CONFIG_MPIC_BROKEN_U3
+       if (mpic->flags & MPIC_BROKEN_U3) {
+               unsigned int src = irq - mpic->irq_offset;
+               if (mpic_is_ht_interrupt(mpic, src) &&
+                   (irq_desc[irq].status & IRQ_LEVEL))
+                       mpic_ht_end_irq(mpic, src);
+       }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
        mpic_eoi(mpic);
 }
-#endif /* !CONFIG_MPIC_BROKEN_U3 */
 
 #ifdef CONFIG_SMP
 
-static void mpic_unmask_ipi(unsigned int irq)
+static void mpic_enable_ipi(unsigned int irq)
 {
        struct mpic *mpic = mpic_from_ipi(irq);
-       unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0;
+       unsigned int src = irq - mpic->ipi_offset;
 
        DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
        mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
 }
 
-static void mpic_mask_ipi(unsigned int irq)
+static void mpic_disable_ipi(unsigned int irq)
 {
        /* NEVER disable an IPI... that's just plain wrong! */
 }
@@ -633,7 +541,7 @@ static void mpic_end_ipi(unsigned int irq)
         * IPIs are marked IRQ_PER_CPU. This has the side effect of
         * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
         * applying to them. We EOI them late to avoid re-entering.
-        * We mark IPI's with IRQF_DISABLED as they must run with
+        * We mark IPI's with SA_INTERRUPT as they must run with
         * irqs disabled.
         */
        mpic_eoi(mpic);
@@ -644,211 +552,29 @@ static void mpic_end_ipi(unsigned int irq)
 static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
 {
        struct mpic *mpic = mpic_from_irq(irq);
-       unsigned int src = mpic_irq_to_hw(irq);
 
        cpumask_t tmp;
 
        cpus_and(tmp, cpumask, cpu_online_map);
 
-       mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
+       mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION,
                       mpic_physmask(cpus_addr(tmp)[0]));       
 }
 
-static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
-{
-       /* Now convert sense value */
-       switch(type & IRQ_TYPE_SENSE_MASK) {
-       case IRQ_TYPE_EDGE_RISING:
-               return MPIC_INFO(VECPRI_SENSE_EDGE) |
-                      MPIC_INFO(VECPRI_POLARITY_POSITIVE);
-       case IRQ_TYPE_EDGE_FALLING:
-       case IRQ_TYPE_EDGE_BOTH:
-               return MPIC_INFO(VECPRI_SENSE_EDGE) |
-                      MPIC_INFO(VECPRI_POLARITY_NEGATIVE);
-       case IRQ_TYPE_LEVEL_HIGH:
-               return MPIC_INFO(VECPRI_SENSE_LEVEL) |
-                      MPIC_INFO(VECPRI_POLARITY_POSITIVE);
-       case IRQ_TYPE_LEVEL_LOW:
-       default:
-               return MPIC_INFO(VECPRI_SENSE_LEVEL) |
-                      MPIC_INFO(VECPRI_POLARITY_NEGATIVE);
-       }
-}
-
-static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
-{
-       struct mpic *mpic = mpic_from_irq(virq);
-       unsigned int src = mpic_irq_to_hw(virq);
-       struct irq_desc *desc = get_irq_desc(virq);
-       unsigned int vecpri, vold, vnew;
-
-       DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
-           mpic, virq, src, flow_type);
-
-       if (src >= mpic->irq_count)
-               return -EINVAL;
-
-       if (flow_type == IRQ_TYPE_NONE)
-               if (mpic->senses && src < mpic->senses_count)
-                       flow_type = mpic->senses[src];
-       if (flow_type == IRQ_TYPE_NONE)
-               flow_type = IRQ_TYPE_LEVEL_LOW;
-
-       desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
-       desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
-       if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
-               desc->status |= IRQ_LEVEL;
-
-       if (mpic_is_ht_interrupt(mpic, src))
-               vecpri = MPIC_VECPRI_POLARITY_POSITIVE |
-                       MPIC_VECPRI_SENSE_EDGE;
-       else
-               vecpri = mpic_type_to_vecpri(mpic, flow_type);
-
-       vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
-       vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) |
-                       MPIC_INFO(VECPRI_SENSE_MASK));
-       vnew |= vecpri;
-       if (vold != vnew)
-               mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew);
-
-       return 0;
-}
-
-static struct irq_chip mpic_irq_chip = {
-       .mask           = mpic_mask_irq,
-       .unmask         = mpic_unmask_irq,
-       .eoi            = mpic_end_irq,
-       .set_type       = mpic_set_irq_type,
-};
-
-#ifdef CONFIG_SMP
-static struct irq_chip mpic_ipi_chip = {
-       .mask           = mpic_mask_ipi,
-       .unmask         = mpic_unmask_ipi,
-       .eoi            = mpic_end_ipi,
-};
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_MPIC_BROKEN_U3
-static struct irq_chip mpic_irq_ht_chip = {
-       .startup        = mpic_startup_ht_irq,
-       .shutdown       = mpic_shutdown_ht_irq,
-       .mask           = mpic_mask_irq,
-       .unmask         = mpic_unmask_ht_irq,
-       .eoi            = mpic_end_ht_irq,
-       .set_type       = mpic_set_irq_type,
-};
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-
-
-static int mpic_host_match(struct irq_host *h, struct device_node *node)
-{
-       struct mpic *mpic = h->host_data;
-
-       /* Exact match, unless mpic node is NULL */
-       return mpic->of_node == NULL || mpic->of_node == node;
-}
-
-static int mpic_host_map(struct irq_host *h, unsigned int virq,
-                        irq_hw_number_t hw)
-{
-       struct mpic *mpic = h->host_data;
-       struct irq_chip *chip;
-
-       DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
-
-       if (hw == MPIC_VEC_SPURRIOUS)
-               return -EINVAL;
-
-#ifdef CONFIG_SMP
-       else if (hw >= MPIC_VEC_IPI_0) {
-               WARN_ON(!(mpic->flags & MPIC_PRIMARY));
-
-               DBG("mpic: mapping as IPI\n");
-               set_irq_chip_data(virq, mpic);
-               set_irq_chip_and_handler(virq, &mpic->hc_ipi,
-                                        handle_percpu_irq);
-               return 0;
-       }
-#endif /* CONFIG_SMP */
-
-       if (hw >= mpic->irq_count)
-               return -EINVAL;
-
-       /* Default chip */
-       chip = &mpic->hc_irq;
-
-#ifdef CONFIG_MPIC_BROKEN_U3
-       /* Check for HT interrupts, override vecpri */
-       if (mpic_is_ht_interrupt(mpic, hw))
-               chip = &mpic->hc_ht_irq;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
-
-       DBG("mpic: mapping to irq chip @%p\n", chip);
-
-       set_irq_chip_data(virq, mpic);
-       set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
-
-       /* Set default irq type */
-       set_irq_type(virq, IRQ_TYPE_NONE);
-
-       return 0;
-}
-
-static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
-                          u32 *intspec, unsigned int intsize,
-                          irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-
-{
-       static unsigned char map_mpic_senses[4] = {
-               IRQ_TYPE_EDGE_RISING,
-               IRQ_TYPE_LEVEL_LOW,
-               IRQ_TYPE_LEVEL_HIGH,
-               IRQ_TYPE_EDGE_FALLING,
-       };
-
-       *out_hwirq = intspec[0];
-       if (intsize > 1) {
-               u32 mask = 0x3;
-
-               /* Apple invented a new race of encoding on machines with
-                * an HT APIC. They encode, among others, the index within
-                * the HT APIC. We don't care about it here since thankfully,
-                * it appears that they have the APIC already properly
-                * configured, and thus our current fixup code that reads the
-                * APIC config works fine. However, we still need to mask out
-                * bits in the specifier to make sure we only get bit 0 which
-                * is the level/edge bit (the only sense bit exposed by Apple),
-                * as their bit 1 means something else.
-                */
-               if (machine_is(powermac))
-                       mask = 0x1;
-               *out_flags = map_mpic_senses[intspec[1] & mask];
-       } else
-               *out_flags = IRQ_TYPE_NONE;
-
-       DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n",
-           intsize, intspec[0], intspec[1], *out_hwirq, *out_flags);
-
-       return 0;
-}
-
-static struct irq_host_ops mpic_host_ops = {
-       .match = mpic_host_match,
-       .map = mpic_host_map,
-       .xlate = mpic_host_xlate,
-};
 
 /*
  * Exported functions
  */
 
-struct mpic * __init mpic_alloc(struct device_node *node,
-                               unsigned long phys_addr,
+
+struct mpic * __init mpic_alloc(unsigned long phys_addr,
                                unsigned int flags,
                                unsigned int isu_size,
+                               unsigned int irq_offset,
                                unsigned int irq_count,
+                               unsigned int ipi_offset,
+                               unsigned char *senses,
+                               unsigned int senses_count,
                                const char *name)
 {
        struct mpic     *mpic;
@@ -860,55 +586,45 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        if (mpic == NULL)
                return NULL;
        
+
        memset(mpic, 0, sizeof(struct mpic));
        mpic->name = name;
-       mpic->of_node = node ? of_node_get(node) : NULL;
-
-       mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256,
-                                      &mpic_host_ops,
-                                      MPIC_VEC_SPURRIOUS);
-       if (mpic->irqhost == NULL) {
-               of_node_put(node);
-               return NULL;
-       }
 
-       mpic->irqhost->host_data = mpic;
-       mpic->hc_irq = mpic_irq_chip;
        mpic->hc_irq.typename = name;
+       mpic->hc_irq.startup = mpic_startup_irq;
+       mpic->hc_irq.shutdown = mpic_shutdown_irq;
+       mpic->hc_irq.enable = mpic_enable_irq;
+       mpic->hc_irq.disable = mpic_disable_irq;
+       mpic->hc_irq.end = mpic_end_irq;
        if (flags & MPIC_PRIMARY)
                mpic->hc_irq.set_affinity = mpic_set_affinity;
-#ifdef CONFIG_MPIC_BROKEN_U3
-       mpic->hc_ht_irq = mpic_irq_ht_chip;
-       mpic->hc_ht_irq.typename = name;
-       if (flags & MPIC_PRIMARY)
-               mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
 #ifdef CONFIG_SMP
-       mpic->hc_ipi = mpic_ipi_chip;
        mpic->hc_ipi.typename = name;
+       mpic->hc_ipi.enable = mpic_enable_ipi;
+       mpic->hc_ipi.disable = mpic_disable_ipi;
+       mpic->hc_ipi.end = mpic_end_ipi;
 #endif /* CONFIG_SMP */
 
        mpic->flags = flags;
        mpic->isu_size = isu_size;
+       mpic->irq_offset = irq_offset;
        mpic->irq_count = irq_count;
+       mpic->ipi_offset = ipi_offset;
        mpic->num_sources = 0; /* so far */
-
-#ifdef CONFIG_MPIC_WEIRD
-       mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
-#endif
+       mpic->senses = senses;
+       mpic->senses_count = senses_count;
 
        /* Map the global registers */
-       mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000);
-       mpic->tmregs = mpic->gregs +
-                      ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2);
+       mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000);
+       mpic->tmregs = mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE) >> 2);
        BUG_ON(mpic->gregs == NULL);
 
        /* Reset */
        if (flags & MPIC_WANTS_RESET) {
-               mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
-                          mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
+               mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+                          mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
                           | MPIC_GREG_GCONF_RESET);
-               while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
+               while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
                       & MPIC_GREG_GCONF_RESET)
                        mb();
        }
@@ -917,7 +633,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
         * MPICs, num sources as well. On ISU MPICs, sources are counted
         * as ISUs are added
         */
-       reg = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
+       reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0);
        mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
                          >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
        if (isu_size == 0)
@@ -926,16 +642,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
 
        /* Map the per-CPU registers */
        for (i = 0; i < mpic->num_cpus; i++) {
-               mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) +
-                                          i * MPIC_INFO(CPU_STRIDE), 0x1000);
+               mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE +
+                                          i * MPIC_CPU_STRIDE, 0x1000);
                BUG_ON(mpic->cpuregs[i] == NULL);
        }
 
        /* Initialize main ISU if none provided */
        if (mpic->isu_size == 0) {
                mpic->isu_size = mpic->num_sources;
-               mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE),
-                                       MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+               mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE,
+                                       MPIC_IRQ_STRIDE * mpic->isu_size);
                BUG_ON(mpic->isus[0] == NULL);
        }
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
@@ -964,10 +680,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->next = mpics;
        mpics = mpic;
 
-       if (flags & MPIC_PRIMARY) {
+       if (flags & MPIC_PRIMARY)
                mpic_primary = mpic;
-               irq_set_default_host(mpic->irqhost);
-       }
 
        return mpic;
 }
@@ -979,16 +693,31 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
 
        BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-       mpic->isus[isu_num] = ioremap(phys_addr,
-                                     MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+       mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size);
        if ((isu_first + mpic->isu_size) > mpic->num_sources)
                mpic->num_sources = isu_first + mpic->isu_size;
 }
 
-void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count)
+void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler,
+                              void *data)
 {
-       mpic->senses = senses;
-       mpic->senses_count = count;
+       struct mpic *mpic = mpic_find(irq, NULL);
+       unsigned long flags;
+
+       /* Synchronization here is a bit dodgy, so don't try to replace cascade
+        * interrupts on the fly too often ... but normally it's set up at boot.
+        */
+       spin_lock_irqsave(&mpic_lock, flags);
+       if (mpic->cascade)             
+               mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset);
+       mpic->cascade = NULL;
+       wmb();
+       mpic->cascade_vec = irq - mpic->irq_offset;
+       mpic->cascade_data = data;
+       wmb();
+       mpic->cascade = handler;
+       mpic_enable_irq(irq);
+       spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 void __init mpic_init(struct mpic *mpic)
@@ -996,25 +725,18 @@ void __init mpic_init(struct mpic *mpic)
        int i;
 
        BUG_ON(mpic->num_sources == 0);
-       WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0);
-
-       /* Sanitize source count */
-       if (mpic->num_sources > MPIC_VEC_IPI_0)
-               mpic->num_sources = MPIC_VEC_IPI_0;
 
        printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);
 
        /* Set current processor priority to max */
-       mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
 
        /* Initialize timers: just disable them all */
        for (i = 0; i < 4; i++) {
                mpic_write(mpic->tmregs,
-                          i * MPIC_INFO(TIMER_STRIDE) +
-                          MPIC_INFO(TIMER_DESTINATION), 0);
+                          i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0);
                mpic_write(mpic->tmregs,
-                          i * MPIC_INFO(TIMER_STRIDE) +
-                          MPIC_INFO(TIMER_VECTOR_PRI),
+                          i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI,
                           MPIC_VECPRI_MASK |
                           (MPIC_VEC_TIMER_0 + i));
        }
@@ -1026,84 +748,106 @@ void __init mpic_init(struct mpic *mpic)
                               MPIC_VECPRI_MASK |
                               (10 << MPIC_VECPRI_PRIORITY_SHIFT) |
                               (MPIC_VEC_IPI_0 + i));
+#ifdef CONFIG_SMP
+               if (!(mpic->flags & MPIC_PRIMARY))
+                       continue;
+               irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
+               irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi;
+#endif /* CONFIG_SMP */
        }
 
        /* Initialize interrupt sources */
        if (mpic->irq_count == 0)
                mpic->irq_count = mpic->num_sources;
 
+#ifdef CONFIG_MPIC_BROKEN_U3
        /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
        if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
-               mpic_scan_ht_pics(mpic);
+               mpic_scan_ht_pics(mpic);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
 
        for (i = 0; i < mpic->num_sources; i++) {
                /* start with vector = source number, and masked */
-               u32 vecpri = MPIC_VECPRI_MASK | i |
-                       (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+               u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+               int level = 0;
                
+               /* if it's an IPI, we skip it */
+               if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) &&
+                   (mpic->irq_offset + i) <  (mpic->ipi_offset + i + 4))
+                       continue;
+
+               /* do senses munging */
+               if (mpic->senses && i < mpic->senses_count) {
+                       if (mpic->senses[i] & IRQ_SENSE_LEVEL)
+                               vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+                       if (mpic->senses[i] & IRQ_POLARITY_POSITIVE)
+                               vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+               } else
+                       vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+
+               /* remember if it was a level interrupts */
+               level = (vecpri & MPIC_VECPRI_SENSE_LEVEL);
+
+               /* deal with broken U3 */
+               if (mpic->flags & MPIC_BROKEN_U3) {
+#ifdef CONFIG_MPIC_BROKEN_U3
+                       if (mpic_is_ht_interrupt(mpic, i)) {
+                               vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
+                                           MPIC_VECPRI_POLARITY_MASK);
+                               vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+                       }
+#else
+                       printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n");
+#endif
+               }
+
+               DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri,
+                   (level != 0));
+
                /* init hw */
-               mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
-               mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+               mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
+               mpic_irq_write(i, MPIC_IRQ_DESTINATION,
                               1 << hard_smp_processor_id());
+
+               /* init linux descriptors */
+               if (i < mpic->irq_count) {
+                       irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0;
+                       irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq;
+               }
        }
        
        /* Init spurrious vector */
-       mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS);
+       mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS);
 
-       /* Disable 8259 passthrough, if supported */
-       if (!(mpic->flags & MPIC_NO_PTHROU_DIS))
-               mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
-                          mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
-                          | MPIC_GREG_GCONF_8259_PTHROU_DIS);
+       /* Disable 8259 passthrough */
+       mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+                  mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+                  | MPIC_GREG_GCONF_8259_PTHROU_DIS);
 
        /* Set current processor priority to 0 */
-       mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
 }
 
-void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
-{
-       u32 v;
 
-       v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
-       v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK;
-       v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio);
-       mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
-}
-
-void __init mpic_set_serial_int(struct mpic *mpic, int enable)
-{
-       unsigned long flags;
-       u32 v;
-
-       spin_lock_irqsave(&mpic_lock, flags);
-       v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
-       if (enable)
-               v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
-       else
-               v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
-       mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
-       spin_unlock_irqrestore(&mpic_lock, flags);
-}
 
 void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
 {
        int is_ipi;
        struct mpic *mpic = mpic_find(irq, &is_ipi);
-       unsigned int src = mpic_irq_to_hw(irq);
        unsigned long flags;
        u32 reg;
 
        spin_lock_irqsave(&mpic_lock, flags);
        if (is_ipi) {
-               reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) &
+               reg = mpic_ipi_read(irq - mpic->ipi_offset) &
                        ~MPIC_VECPRI_PRIORITY_MASK;
-               mpic_ipi_write(src - MPIC_VEC_IPI_0,
+               mpic_ipi_write(irq - mpic->ipi_offset,
                               reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
        } else {
-               reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
+               reg = mpic_irq_read(irq - mpic->irq_offset,MPIC_IRQ_VECTOR_PRI)
                        & ~MPIC_VECPRI_PRIORITY_MASK;
-               mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
+               mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI,
                               reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
        }
        spin_unlock_irqrestore(&mpic_lock, flags);
@@ -1113,15 +857,14 @@ unsigned int mpic_irq_get_priority(unsigned int irq)
 {
        int is_ipi;
        struct mpic *mpic = mpic_find(irq, &is_ipi);
-       unsigned int src = mpic_irq_to_hw(irq);
        unsigned long flags;
        u32 reg;
 
        spin_lock_irqsave(&mpic_lock, flags);
        if (is_ipi)
-               reg = mpic_ipi_read(src = MPIC_VEC_IPI_0);
+               reg = mpic_ipi_read(irq - mpic->ipi_offset);
        else
-               reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+               reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI);
        spin_unlock_irqrestore(&mpic_lock, flags);
        return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
 }
@@ -1143,16 +886,16 @@ void mpic_setup_this_cpu(void)
        /* let the mpic know we want intrs. default affinity is 0xffffffff
         * until changed via /proc. That's how it's done on x86. If we want
         * it differently, then we should make sure we also change the default
-        * values of irq_desc[].affinity in irq.c.
+        * values of irq_affinity in irq.c.
         */
        if (distribute_irqs) {
                for (i = 0; i < mpic->num_sources ; i++)
-                       mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
-                               mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk);
+                       mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+                               mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk);
        }
 
        /* Set current processor priority to 0 */
-       mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
 
        spin_unlock_irqrestore(&mpic_lock, flags);
 #endif /* CONFIG_SMP */
@@ -1162,7 +905,7 @@ int mpic_cpu_get_priority(void)
 {
        struct mpic *mpic = mpic_primary;
 
-       return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI));
+       return mpic_cpu_read(MPIC_CPU_CURRENT_TASK_PRI);
 }
 
 void mpic_cpu_set_priority(int prio)
@@ -1170,7 +913,7 @@ void mpic_cpu_set_priority(int prio)
        struct mpic *mpic = mpic_primary;
 
        prio &= MPIC_CPU_TASKPRI_MASK;
-       mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio);
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, prio);
 }
 
 /*
@@ -1192,11 +935,11 @@ void mpic_teardown_this_cpu(int secondary)
 
        /* let the mpic know we don't want intrs.  */
        for (i = 0; i < mpic->num_sources ; i++)
-               mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
-                       mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk);
+               mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+                       mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
 
        /* Set current processor priority to max */
-       mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
 
        spin_unlock_irqrestore(&mpic_lock, flags);
 }
@@ -1212,25 +955,41 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
        DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
 #endif
 
-       mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
-                      ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
+       mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
                       mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
 }
 
-unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
+int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
 {
-       u32 src;
+       u32 irq;
 
-       src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK);
+       irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
 #ifdef DEBUG_LOW
-       DBG("%s: get_one_irq(): %d\n", mpic->name, src);
+       DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
 #endif
-       if (unlikely(src == MPIC_VEC_SPURRIOUS))
-               return NO_IRQ;
-       return irq_linear_revmap(mpic->irqhost, src);
+       if (mpic->cascade && irq == mpic->cascade_vec) {
+#ifdef DEBUG_LOW
+               DBG("%s: cascading ...\n", mpic->name);
+#endif
+               irq = mpic->cascade(regs, mpic->cascade_data);
+               mpic_eoi(mpic);
+               return irq;
+       }
+       if (unlikely(irq == MPIC_VEC_SPURRIOUS))
+               return -1;
+       if (irq < MPIC_VEC_IPI_0) {
+#ifdef DEBUG_IRQ
+               DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
+#endif
+               return irq + mpic->irq_offset;
+       }
+#ifdef DEBUG_IPI
+               DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+#endif
+       return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
 }
 
-unsigned int mpic_get_irq(struct pt_regs *regs)
+int mpic_get_irq(struct pt_regs *regs)
 {
        struct mpic *mpic = mpic_primary;
 
@@ -1244,27 +1003,22 @@ unsigned int mpic_get_irq(struct pt_regs *regs)
 void mpic_request_ipis(void)
 {
        struct mpic *mpic = mpic_primary;
-       int i;
-       static char *ipi_names[] = {
-               "IPI0 (call function)",
-               "IPI1 (reschedule)",
-               "IPI2 (unused)",
-               "IPI3 (debugger break)",
-       };
-       BUG_ON(mpic == NULL);
-
-       printk(KERN_INFO "mpic: requesting IPIs ... \n");
 
-       for (i = 0; i < 4; i++) {
-               unsigned int vipi = irq_create_mapping(mpic->irqhost,
-                                                      MPIC_VEC_IPI_0 + i);
-               if (vipi == NO_IRQ) {
-                       printk(KERN_ERR "Failed to map IPI %d\n", i);
-                       break;
-               }
-               request_irq(vipi, mpic_ipi_action, IRQF_DISABLED,
-                           ipi_names[i], mpic);
-       }
+       BUG_ON(mpic == NULL);
+       
+       printk("requesting IPIs ... \n");
+
+       /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
+       request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT,
+                   "IPI0 (call function)", mpic);
+       request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI1 (reschedule)", mpic);
+       request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI2 (unused)", mpic);
+       request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI3 (debugger break)", mpic);
+
+       printk("IPIs requested... \n");
 }
 
 void smp_mpic_message_pass(int target, int msg)