irqchip/dw-apb-ictl: Fix generic domain chip wreckage
The num_ct argument of irq_alloc_domain_generic_chips() tells the core code how many chip types (for different control flows, e.g. edge/level) should be allocated. It does not control how many generic chip instances are created because that's determined from the irq domain size and the number of interrupts per chip. The dw-apb init abuses the num_ct argument for allocating one or two chip types depending on the number of interrupts. That's completely wrong because the alternate type is never used. This code was obviously never tested on a system which has more than 32 interrupts as that would have never worked due to the unitialized second generic chip instance. Hand in the proper num_ct=1 and fixup the chip initialization along with the interrupt handler. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Jisheng Zhang <jszhang@marvell.com> Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Jason Cooper <jason@lakedaemon.net> Link: http://lkml.kernel.org/r/20150706101543.373582262@linutronix.de
This commit is contained in:
parent
d6ac4ffc61
commit
b66231183a
|
@ -25,24 +25,25 @@
|
|||
#define APB_INT_MASK_H 0x0c
|
||||
#define APB_INT_FINALSTATUS_L 0x30
|
||||
#define APB_INT_FINALSTATUS_H 0x34
|
||||
#define APB_INT_BASE_OFFSET 0x04
|
||||
|
||||
static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *chip = irq_get_chip(irq);
|
||||
struct irq_chip_generic *gc = irq_get_handler_data(irq);
|
||||
struct irq_domain *d = gc->private;
|
||||
u32 stat;
|
||||
struct irq_domain *d = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
int n;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
for (n = 0; n < gc->num_ct; n++) {
|
||||
stat = readl_relaxed(gc->reg_base +
|
||||
APB_INT_FINALSTATUS_L + 4 * n);
|
||||
for (n = 0; n < d->revmap_size; n += 32) {
|
||||
struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n);
|
||||
u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L);
|
||||
|
||||
while (stat) {
|
||||
u32 hwirq = ffs(stat) - 1;
|
||||
generic_handle_irq(irq_find_mapping(d,
|
||||
gc->irq_base + hwirq + 32 * n));
|
||||
u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
|
||||
|
||||
generic_handle_irq(virq);
|
||||
stat &= ~(1 << hwirq);
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
|
|||
struct irq_domain *domain;
|
||||
struct irq_chip_generic *gc;
|
||||
void __iomem *iobase;
|
||||
int ret, nrirqs, irq;
|
||||
int ret, nrirqs, irq, i;
|
||||
u32 reg;
|
||||
|
||||
/* Map the parent interrupt for the chained handler */
|
||||
|
@ -128,35 +129,25 @@ static int __init dw_apb_ictl_init(struct device_node *np,
|
|||
goto err_unmap;
|
||||
}
|
||||
|
||||
ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1,
|
||||
np->name, handle_level_irq, clr, 0,
|
||||
IRQ_GC_MASK_CACHE_PER_TYPE |
|
||||
ret = irq_alloc_domain_generic_chips(domain, 32, 1, np->name,
|
||||
handle_level_irq, clr, 0,
|
||||
IRQ_GC_INIT_MASK_CACHE);
|
||||
if (ret) {
|
||||
pr_err("%s: unable to alloc irq domain gc\n", np->full_name);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
gc = irq_get_domain_generic_chip(domain, 0);
|
||||
gc->private = domain;
|
||||
gc->reg_base = iobase;
|
||||
|
||||
gc->chip_types[0].regs.mask = APB_INT_MASK_L;
|
||||
gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
|
||||
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
|
||||
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||
gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
|
||||
|
||||
if (nrirqs > 32) {
|
||||
gc->chip_types[1].regs.mask = APB_INT_MASK_H;
|
||||
gc->chip_types[1].regs.enable = APB_INT_ENABLE_H;
|
||||
gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit;
|
||||
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||
gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume;
|
||||
for (i = 0; i < DIV_ROUND_UP(nrirqs, 32); i++) {
|
||||
gc = irq_get_domain_generic_chip(domain, i * 32);
|
||||
gc->reg_base = iobase + i * APB_INT_BASE_OFFSET;
|
||||
gc->chip_types[0].regs.mask = APB_INT_MASK_L;
|
||||
gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
|
||||
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
|
||||
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||
gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
|
||||
}
|
||||
|
||||
irq_set_handler_data(irq, gc);
|
||||
irq_set_chained_handler(irq, dw_apb_ictl_handler);
|
||||
irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue