#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);