[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:
Родитель
8f7f9435e6
Коммит
984d115bbf
|
@ -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)
|
||||||
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)
|
||||||
*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)
|
||||||
* 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);
|
||||||
|
|
||||||
|
if (cpu_is_ixp46x() && irq >= 32)
|
||||||
|
*IXP4XX_ICMR2 |= (1 << (irq - 32));
|
||||||
|
else
|
||||||
|
*IXP4XX_ICMR |= (1 << irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irqchip ixp4xx_irq_level_chip = {
|
static struct irqchip ixp4xx_irq_chip = {
|
||||||
.ack = ixp4xx_irq_mask,
|
.name = "IXP4xx",
|
||||||
.mask = ixp4xx_irq_mask,
|
|
||||||
.unmask = ixp4xx_irq_level_unmask,
|
|
||||||
.set_type = ixp4xx_set_irq_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct irqchip ixp4xx_irq_edge_chip = {
|
|
||||||
.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче