diff options
author | Kevin Hilman <khilman@com.rmk.(none)> | 2006-11-03 01:47:20 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-11-03 19:52:50 +0000 |
commit | 984d115bbf2d731ed2264031fe49c1378d730db0 (patch) | |
tree | 60159c1d0b21f3214ce0fd530f4a39f2476e3e14 /arch | |
parent | 8f7f9435e6df0985c877d10259393bdfaac3655f (diff) | |
download | kernel_samsung_crespo-984d115bbf2d731ed2264031fe49c1378d730db0.zip kernel_samsung_crespo-984d115bbf2d731ed2264031fe49c1378d730db0.tar.gz kernel_samsung_crespo-984d115bbf2d731ed2264031fe49c1378d730db0.tar.bz2 |
[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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-ixp4xx/common.c | 60 |
1 files changed, 22 insertions, 38 deletions
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index c7513f6..fbe288a 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -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); -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, -}; + if (cpu_is_ixp46x() && irq >= 32) + *IXP4XX_ICMR2 |= (1 << (irq - 32)); + else + *IXP4XX_ICMR |= (1 << irq); +} -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); + } } |