[PATCH] powerpc: fix trigger handling in the new irq code
[linux-2.6.git] / arch / powerpc / sysdev / mpic.c
index 9ceceba..c39c4a0 100644 (file)
@@ -337,6 +337,17 @@ 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 */
 
 
@@ -405,11 +416,9 @@ static void mpic_unmask_irq(unsigned int irq)
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
        unsigned int src = mpic_irq_to_hw(irq);
-       unsigned long flags;
 
        DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
-       spin_lock_irqsave(&mpic_lock, flags);
        mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
                       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
                       ~MPIC_VECPRI_MASK);
@@ -420,7 +429,6 @@ static void mpic_unmask_irq(unsigned int irq)
                        break;
                }
        } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
-       spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 static void mpic_mask_irq(unsigned int irq)
@@ -428,11 +436,9 @@ static void mpic_mask_irq(unsigned int irq)
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq(irq);
        unsigned int src = mpic_irq_to_hw(irq);
-       unsigned long flags;
 
        DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
 
-       spin_lock_irqsave(&mpic_lock, flags);
        mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
                       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
                       MPIC_VECPRI_MASK);
@@ -444,7 +450,6 @@ static void mpic_mask_irq(unsigned int irq)
                        break;
                }
        } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
-       spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
 static void mpic_end_irq(unsigned int irq)
@@ -512,8 +517,7 @@ static void mpic_end_ht_irq(unsigned int irq)
                mpic_ht_end_irq(mpic, src);
        mpic_eoi(mpic);
 }
-
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* !CONFIG_MPIC_BROKEN_U3 */
 
 #ifdef CONFIG_SMP
 
@@ -560,47 +564,74 @@ static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
                       mpic_physmask(cpus_addr(tmp)[0]));       
 }
 
-static unsigned int mpic_flags_to_vecpri(unsigned int flags, int *level)
+static unsigned int mpic_type_to_vecpri(unsigned int type)
 {
-       unsigned int vecpri;
-
        /* Now convert sense value */
-       switch(flags & IRQ_TYPE_SENSE_MASK) {
+       switch(type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_RISING:
-               vecpri = MPIC_VECPRI_SENSE_EDGE |
-                       MPIC_VECPRI_POLARITY_POSITIVE;
-               *level = 0;
-               break;
+               return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_POSITIVE;
        case IRQ_TYPE_EDGE_FALLING:
-               vecpri = MPIC_VECPRI_SENSE_EDGE |
-                       MPIC_VECPRI_POLARITY_NEGATIVE;
-               *level = 0;
-               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_NEGATIVE;
        case IRQ_TYPE_LEVEL_HIGH:
-               vecpri = MPIC_VECPRI_SENSE_LEVEL |
-                       MPIC_VECPRI_POLARITY_POSITIVE;
-               *level = 1;
-               break;
+               return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_POSITIVE;
        case IRQ_TYPE_LEVEL_LOW:
        default:
-               vecpri = MPIC_VECPRI_SENSE_LEVEL |
-                       MPIC_VECPRI_POLARITY_NEGATIVE;
-               *level = 1;
+               return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_NEGATIVE;
        }
-       return vecpri;
+}
+
+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;
+
+       pr_debug("mpic: set_irq_type(mpic:@%p,virq:%d,src:%d,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(flow_type);
+
+       vold = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI);
+       vnew = vold & ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK);
+       vnew |= vecpri;
+       if (vold != vnew)
+               mpic_irq_write(src, MPIC_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,
+       .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,
+       .mask           = mpic_mask_ipi,
+       .unmask         = mpic_unmask_ipi,
+       .eoi            = mpic_end_ipi,
 };
 #endif /* CONFIG_SMP */
 
@@ -611,6 +642,7 @@ static struct irq_chip mpic_irq_ht_chip = {
        .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 */
 
@@ -624,18 +656,12 @@ static int mpic_host_match(struct irq_host *h, struct device_node *node)
 }
 
 static int mpic_host_map(struct irq_host *h, unsigned int virq,
-                        irq_hw_number_t hw, unsigned int flags)
+                        irq_hw_number_t hw)
 {
-       struct irq_desc *desc = get_irq_desc(virq);
-       struct irq_chip *chip;
        struct mpic *mpic = h->host_data;
-       u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
-               MPIC_VECPRI_POLARITY_NEGATIVE;
-       int level;
-       unsigned long iflags;
+       struct irq_chip *chip;
 
-       pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
-                virq, hw, flags);
+       pr_debug("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
 
        if (hw == MPIC_VEC_SPURRIOUS)
                return -EINVAL;
@@ -654,44 +680,23 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
        if (hw >= mpic->irq_count)
                return -EINVAL;
 
-       /* If no sense provided, check default sense array */
-       if (((flags & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) &&
-           mpic->senses && hw < mpic->senses_count)
-               flags |= mpic->senses[hw];
-
-       vecpri = mpic_flags_to_vecpri(flags, &level);
-       if (level)
-               desc->status |= IRQ_LEVEL;
+       /* Default chip */
        chip = &mpic->hc_irq;
 
 #ifdef CONFIG_MPIC_BROKEN_U3
        /* Check for HT interrupts, override vecpri */
-       if (mpic_is_ht_interrupt(mpic, hw)) {
-               vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
-                           MPIC_VECPRI_POLARITY_MASK);
-               vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+       if (mpic_is_ht_interrupt(mpic, hw))
                chip = &mpic->hc_ht_irq;
-       }
-#endif
+#endif /* CONFIG_MPIC_BROKEN_U3 */
 
-       /* Reconfigure irq. We must preserve the mask bit as we can be called
-        * while the interrupt is still active (This may change in the future
-        * but for now, it is the case).
-        */
-       spin_lock_irqsave(&mpic_lock, iflags);
-       v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
-       vecpri = (v &
-               ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
-               vecpri;
-       if (vecpri != v)
-               mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
-       spin_unlock_irqrestore(&mpic_lock, iflags);
-
-       pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
-                vecpri, v);
+       pr_debug("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;
 }
 
@@ -906,41 +911,16 @@ void __init mpic_init(struct mpic *mpic)
        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);
-#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);
-               int level = 1;
+               u32 vecpri = MPIC_VECPRI_MASK | i |
+                       (8 << MPIC_VECPRI_PRIORITY_SHIFT);
                
-               /* do senses munging */
-               if (mpic->senses && i < mpic->senses_count)
-                       vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
-                                                      &level);
-               else
-                       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_IRQ_VECTOR_PRI, vecpri);
                mpic_irq_write(i, MPIC_IRQ_DESTINATION,
@@ -1154,7 +1134,7 @@ void mpic_request_ipis(void)
 
        for (i = 0; i < 4; i++) {
                unsigned int vipi = irq_create_mapping(mpic->irqhost,
-                                                      MPIC_VEC_IPI_0 + i, 0);
+                                                      MPIC_VEC_IPI_0 + i);
                if (vipi == NO_IRQ) {
                        printk(KERN_ERR "Failed to map IPI %d\n", i);
                        break;