Commit 984d115b authored by Kevin Hilman's avatar Kevin Hilman Committed by Russell King

[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: default avatarKevin Hilman <khilman@mvista.com>
Signed-off-by: default avatarDeepak Saxena <dsaxena@mvista.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 8f7f9435
...@@ -86,7 +86,8 @@ enum ixp4xx_irq_type { ...@@ -86,7 +86,8 @@ enum ixp4xx_irq_type {
IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE 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 * IRQ -> GPIO mapping table
...@@ -135,7 +136,11 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) ...@@ -135,7 +136,11 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
default: default:
return -EINVAL; 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 */ if (line >= 8) { /* pins 8-15 */
line -= 8; line -= 8;
...@@ -167,14 +172,6 @@ static void ixp4xx_irq_mask(unsigned int irq) ...@@ -167,14 +172,6 @@ static void ixp4xx_irq_mask(unsigned int irq)
*IXP4XX_ICMR &= ~(1 << 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) static void ixp4xx_irq_ack(unsigned int irq)
{ {
int line = (irq < 32) ? irq2gpio[irq] : -1; int line = (irq < 32) ? irq2gpio[irq] : -1;
...@@ -187,41 +184,25 @@ static void ixp4xx_irq_ack(unsigned int irq) ...@@ -187,41 +184,25 @@ static void ixp4xx_irq_ack(unsigned int irq)
* Level triggered interrupts on GPIO lines can only be cleared when the * Level triggered interrupts on GPIO lines can only be cleared when the
* interrupt condition disappears. * interrupt condition disappears.
*/ */
static void ixp4xx_irq_level_unmask(unsigned int irq) static void ixp4xx_irq_unmask(unsigned int irq)
{ {
ixp4xx_irq_ack(irq); if (!(ixp4xx_irq_edge & (1 << irq)))
ixp4xx_irq_unmask(irq); ixp4xx_irq_ack(irq);
}
static struct irqchip ixp4xx_irq_level_chip = { if (cpu_is_ixp46x() && irq >= 32)
.ack = ixp4xx_irq_mask, *IXP4XX_ICMR2 |= (1 << (irq - 32));
.mask = ixp4xx_irq_mask, else
.unmask = ixp4xx_irq_level_unmask, *IXP4XX_ICMR |= (1 << irq);
.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, .ack = ixp4xx_irq_ack,
.mask = ixp4xx_irq_mask, .mask = ixp4xx_irq_mask,
.unmask = ixp4xx_irq_unmask, .unmask = ixp4xx_irq_unmask,
.set_type = ixp4xx_set_irq_type, .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) void __init ixp4xx_init_irq(void)
{ {
int i = 0; int i = 0;
...@@ -241,8 +222,11 @@ void __init ixp4xx_init_irq(void) ...@@ -241,8 +222,11 @@ void __init ixp4xx_init_irq(void)
} }
/* Default to all level triggered */ /* Default to all level triggered */
for(i = 0; i < NR_IRQS; i++) for(i = 0; i < NR_IRQS; i++) {
ixp4xx_config_irq(i, IXP4XX_IRQ_LEVEL); set_irq_chip(i, &ixp4xx_irq_chip);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID);
}
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment