diff options
Diffstat (limited to 'drivers/irqchip/irq-orion.c')
| -rw-r--r-- | drivers/irqchip/irq-orion.c | 28 | 
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index e51d4003188..34d18b48bb7 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -30,7 +30,7 @@  static struct irq_domain *orion_irq_domain; -static asmlinkage void +static void  __exception_irq_entry orion_handle_irq(struct pt_regs *regs)  {  	struct irq_domain_chip_generic *dgc = orion_irq_domain->gc; @@ -42,7 +42,7 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)  		u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &  			gc->mask_cache;  		while (stat) { -			u32 hwirq = ffs(stat) - 1; +			u32 hwirq = __fls(stat);  			u32 irq = irq_find_mapping(orion_irq_domain,  						   gc->irq_base + hwirq);  			handle_IRQ(irq, regs); @@ -111,18 +111,32 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);  static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)  {  	struct irq_domain *d = irq_get_handler_data(irq); -	struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq); + +	struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);  	u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &  		   gc->mask_cache;  	while (stat) { -		u32 hwirq = ffs(stat) - 1; +		u32 hwirq = __fls(stat);  		generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));  		stat &= ~(1 << hwirq);  	}  } +/* + * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register. + * To avoid interrupt events on stale irqs, we clear them before unmask. + */ +static unsigned int orion_bridge_irq_startup(struct irq_data *d) +{ +	struct irq_chip_type *ct = irq_data_get_chip_type(d); + +	ct->chip.irq_ack(d); +	ct->chip.irq_unmask(d); +	return 0; +} +  static int __init orion_bridge_irq_init(struct device_node *np,  					struct device_node *parent)  { @@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np,  	}  	ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, -			     handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); +			     handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);  	if (ret) {  		pr_err("%s: unable to alloc irq domain gc\n", np->name);  		return ret; @@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np,  	gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;  	gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK; +	gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup;  	gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;  	gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;  	gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; -	/* mask all interrupts */ +	/* mask and clear all interrupts */  	writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); +	writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);  	irq_set_handler_data(irq, domain);  	irq_set_chained_handler(irq, orion_bridge_irq_handler);  | 
