#include "ipic.h"
 
 static struct ipic * primary_ipic;
+static struct irq_chip ipic_level_irq_chip, ipic_edge_irq_chip;
 static DEFINE_SPINLOCK(ipic_lock);
 
 static struct ipic_info ipic_info[] = {
        [1] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_C,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 0,
        },
        [2] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_C,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 1,
        },
        [4] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_C,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 3,
        },
        [9] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 0,
        },
        [10] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 1,
        },
        [11] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 2,
        },
        [12] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 3,
        },
        [13] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 4,
        },
        [14] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 5,
        },
        [15] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 6,
        },
        [16] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_D,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 7,
        },
        [17] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
                .prio_mask = 5,
        },
        [18] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
                .prio_mask = 6,
        },
        [19] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
                .prio_mask = 7,
        },
        [20] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
                .prio_mask = 4,
        },
        [21] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
                .prio_mask = 5,
        },
        [22] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
                .prio_mask = 6,
        },
        [23] = {
-               .pend   = IPIC_SEPNR,
+               .ack    = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SEFCR,
                .prio_mask = 7,
        },
        [32] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 0,
        },
        [33] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 1,
        },
        [34] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 2,
        },
        [35] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 3,
        },
        [36] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 4,
        },
        [37] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 5,
        },
        [38] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 6,
        },
        [39] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_A,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 7,
        },
        [42] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_B,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 2,
        },
        [44] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_B,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 4,
        },
        [45] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_B,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 5,
        },
        [46] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_B,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 6,
        },
        [47] = {
-               .pend   = IPIC_SIPNR_H,
                .mask   = IPIC_SIMSR_H,
                .prio   = IPIC_SIPRR_B,
                .force  = IPIC_SIFCR_H,
                .prio_mask = 7,
        },
        [48] = {
-               .pend   = IPIC_SEPNR,
                .mask   = IPIC_SEMSR,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SEFCR,
                .prio_mask = 4,
        },
        [64] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 0,
        },
        [65] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 1,
        },
        [66] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 2,
        },
        [67] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_A,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 3,
        },
        [68] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 0,
        },
        [69] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 1,
        },
        [70] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 2,
        },
        [71] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = IPIC_SMPRR_B,
                .force  = IPIC_SIFCR_L,
                .prio_mask = 3,
        },
        [72] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 8,
        },
        [73] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 9,
        },
        [74] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 10,
        },
        [75] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 11,
        },
        [76] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 12,
        },
        [77] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 13,
        },
        [78] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 14,
        },
        [79] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 15,
        },
        [80] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 16,
        },
        [81] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 17,
        },
        [82] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 18,
        },
        [84] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 20,
        },
        [85] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 21,
        },
        [86] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 22,
        },
        [87] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 23,
        },
        [88] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 24,
        },
        [89] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 25,
        },
        [90] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
                .bit    = 26,
        },
        [91] = {
-               .pend   = IPIC_SIPNR_L,
                .mask   = IPIC_SIMSR_L,
                .prio   = 0,
                .force  = IPIC_SIFCR_L,
        temp &= ~(1 << (31 - ipic_info[src].bit));
        ipic_write(ipic->regs, ipic_info[src].mask, temp);
 
+       /* mb() can't guarantee that masking is finished.  But it does finish
+        * for nearly all cases. */
+       mb();
+
        spin_unlock_irqrestore(&ipic_lock, flags);
 }
 
 
        spin_lock_irqsave(&ipic_lock, flags);
 
-       temp = ipic_read(ipic->regs, ipic_info[src].pend);
+       temp = ipic_read(ipic->regs, ipic_info[src].ack);
        temp |= (1 << (31 - ipic_info[src].bit));
-       ipic_write(ipic->regs, ipic_info[src].pend, temp);
+       ipic_write(ipic->regs, ipic_info[src].ack, temp);
+
+       /* mb() can't guarantee that ack is finished.  But it does finish
+        * for nearly all cases. */
+       mb();
 
        spin_unlock_irqrestore(&ipic_lock, flags);
 }
        temp &= ~(1 << (31 - ipic_info[src].bit));
        ipic_write(ipic->regs, ipic_info[src].mask, temp);
 
-       temp = ipic_read(ipic->regs, ipic_info[src].pend);
+       temp = ipic_read(ipic->regs, ipic_info[src].ack);
        temp |= (1 << (31 - ipic_info[src].bit));
-       ipic_write(ipic->regs, ipic_info[src].pend, temp);
+       ipic_write(ipic->regs, ipic_info[src].ack, temp);
+
+       /* mb() can't guarantee that ack is finished.  But it does finish
+        * for nearly all cases. */
+       mb();
 
        spin_unlock_irqrestore(&ipic_lock, flags);
 }
                        flow_type);
                return -EINVAL;
        }
+       /* ipic supports only edge mode on external interrupts */
+       if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !ipic_info[src].ack) {
+               printk(KERN_ERR "ipic: edge sense not supported on internal "
+                               "interrupts\n");
+               return -EINVAL;
+       }
 
        desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
        desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
        if (flow_type & IRQ_TYPE_LEVEL_LOW)  {
                desc->status |= IRQ_LEVEL;
                desc->handle_irq = handle_level_irq;
+               desc->chip = &ipic_level_irq_chip;
        } else {
                desc->handle_irq = handle_edge_irq;
+               desc->chip = &ipic_edge_irq_chip;
        }
 
        /* only EXT IRQ senses are programmable on ipic
        return 0;
 }
 
-static struct irq_chip ipic_irq_chip = {
+/* level interrupts and edge interrupts have different ack operations */
+static struct irq_chip ipic_level_irq_chip = {
+       .typename       = " IPIC  ",
+       .unmask         = ipic_unmask_irq,
+       .mask           = ipic_mask_irq,
+       .mask_ack       = ipic_mask_irq,
+       .set_type       = ipic_set_irq_type,
+};
+
+static struct irq_chip ipic_edge_irq_chip = {
        .typename       = " IPIC  ",
        .unmask         = ipic_unmask_irq,
        .mask           = ipic_mask_irq,
                         irq_hw_number_t hw)
 {
        struct ipic *ipic = h->host_data;
-       struct irq_chip *chip;
-
-       /* Default chip */
-       chip = &ipic->hc_irq;
 
        set_irq_chip_data(virq, ipic);
-       set_irq_chip_and_handler(virq, chip, handle_level_irq);
+       set_irq_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq);
 
        /* Set default irq type */
        set_irq_type(virq, IRQ_TYPE_NONE);
        ipic->regs = ioremap(res.start, res.end - res.start + 1);
 
        ipic->irqhost->host_data = ipic;
-       ipic->hc_irq = ipic_irq_chip;
 
        /* init hw */
        ipic_write(ipic->regs, IPIC_SICNR, 0x0);