[ARM] 3918/1: ixp4xx irq-chip rework
This is a rework of the ixp4xx irq_chip implementation. The use of two irq_chip structures and potentially switching between them is a violation of the intended use of the IRQ framework. The current implementation does not work with current in-kernel spinlock debugging or lockdep due to lock recursion problems caused by calling set_irq_chip/handler from within the chip's set_irq_type(). This patch goes back to using one irq_chip structure and handling the differences between edge/level, normal/GPIO interrupts inside the ack/mask/unmask routines themselves. Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Deepak Saxena <dsaxena@mvista.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
8f7f9435e6
commit
984d115bbf
|
@ -86,7 +86,8 @@ enum ixp4xx_irq_type {
|
|||
IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
|
||||
};
|
||||
|
||||
static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
|
||||
/* Each bit represents an IRQ: 1: edge-triggered, 0: level triggered */
|
||||
static unsigned long long ixp4xx_irq_edge = 0;
|
||||
|
||||
/*
|
||||
* IRQ -> GPIO mapping table
|
||||
|
@ -135,7 +136,11 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ixp4xx_config_irq(irq, irq_type);
|
||||
|
||||
if (irq_type == IXP4XX_IRQ_EDGE)
|
||||
ixp4xx_irq_edge |= (1 << irq);
|
||||
else
|
||||
ixp4xx_irq_edge &= ~(1 << irq);
|
||||
|
||||
if (line >= 8) { /* pins 8-15 */
|
||||
line -= 8;
|
||||
|
@ -167,14 +172,6 @@ static void ixp4xx_irq_mask(unsigned int irq)
|
|||
*IXP4XX_ICMR &= ~(1 << irq);
|
||||
}
|
||||
|
||||
static void ixp4xx_irq_unmask(unsigned int irq)
|
||||
{
|
||||
if (cpu_is_ixp46x() && irq >= 32)
|
||||
*IXP4XX_ICMR2 |= (1 << (irq - 32));
|
||||
else
|
||||
*IXP4XX_ICMR |= (1 << irq);
|
||||
}
|
||||
|
||||
static void ixp4xx_irq_ack(unsigned int irq)
|
||||
{
|
||||
int line = (irq < 32) ? irq2gpio[irq] : -1;
|
||||
|
@ -187,41 +184,25 @@ static void ixp4xx_irq_ack(unsigned int irq)
|
|||
* Level triggered interrupts on GPIO lines can only be cleared when the
|
||||
* interrupt condition disappears.
|
||||
*/
|
||||
static void ixp4xx_irq_level_unmask(unsigned int irq)
|
||||
static void ixp4xx_irq_unmask(unsigned int irq)
|
||||
{
|
||||
ixp4xx_irq_ack(irq);
|
||||
ixp4xx_irq_unmask(irq);
|
||||
if (!(ixp4xx_irq_edge & (1 << irq)))
|
||||
ixp4xx_irq_ack(irq);
|
||||
|
||||
if (cpu_is_ixp46x() && irq >= 32)
|
||||
*IXP4XX_ICMR2 |= (1 << (irq - 32));
|
||||
else
|
||||
*IXP4XX_ICMR |= (1 << irq);
|
||||
}
|
||||
|
||||
static struct irqchip ixp4xx_irq_level_chip = {
|
||||
.ack = ixp4xx_irq_mask,
|
||||
.mask = ixp4xx_irq_mask,
|
||||
.unmask = ixp4xx_irq_level_unmask,
|
||||
.set_type = ixp4xx_set_irq_type,
|
||||
};
|
||||
|
||||
static struct irqchip ixp4xx_irq_edge_chip = {
|
||||
static struct irqchip ixp4xx_irq_chip = {
|
||||
.name = "IXP4xx",
|
||||
.ack = ixp4xx_irq_ack,
|
||||
.mask = ixp4xx_irq_mask,
|
||||
.unmask = ixp4xx_irq_unmask,
|
||||
.set_type = ixp4xx_set_irq_type,
|
||||
};
|
||||
|
||||
static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case IXP4XX_IRQ_LEVEL:
|
||||
set_irq_chip(irq, &ixp4xx_irq_level_chip);
|
||||
set_irq_handler(irq, do_level_IRQ);
|
||||
break;
|
||||
case IXP4XX_IRQ_EDGE:
|
||||
set_irq_chip(irq, &ixp4xx_irq_edge_chip);
|
||||
set_irq_handler(irq, do_edge_IRQ);
|
||||
break;
|
||||
}
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
void __init ixp4xx_init_irq(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -241,8 +222,11 @@ void __init ixp4xx_init_irq(void)
|
|||
}
|
||||
|
||||
/* Default to all level triggered */
|
||||
for(i = 0; i < NR_IRQS; i++)
|
||||
ixp4xx_config_irq(i, IXP4XX_IRQ_LEVEL);
|
||||
for(i = 0; i < NR_IRQS; i++) {
|
||||
set_irq_chip(i, &ixp4xx_irq_chip);
|
||||
set_irq_handler(i, do_level_IRQ);
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue