Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+22 −38
Original line number Diff line number Diff line
@@ -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)
{
	if (!(ixp4xx_irq_edge & (1 << irq)))
		ixp4xx_irq_ack(irq);
	ixp4xx_irq_unmask(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);
	}
}