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

Commit f5b9ed7a authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds
Browse files

[PATCH] genirq: convert the i386 architecture to irq-chips



This patch converts all the i386 PIC controllers (except VisWS and Voyager,
which I could not test - but which should still work as old-style IRQ layers)
to the new and simpler irq-chip interrupt handling layer.

[akpm@osdl.org: build fix]
[mingo@elte.hu: enable fasteoi handler for i386 level-triggered IO-APIC irqs]
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Roland Dreier <rolandd@cisco.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f29bd1ba
Loading
Loading
Loading
Loading
+13 −32
Original line number Diff line number Diff line
@@ -34,35 +34,15 @@
 * moves to arch independent land
 */

DEFINE_SPINLOCK(i8259A_lock);

static void end_8259A_irq (unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
							irq_desc[irq].action)
		enable_8259A_irq(irq);
}

#define shutdown_8259A_irq	disable_8259A_irq

static int i8259A_auto_eoi;

DEFINE_SPINLOCK(i8259A_lock);
static void mask_and_ack_8259A(unsigned int);

unsigned int startup_8259A_irq(unsigned int irq)
{ 
	enable_8259A_irq(irq);
	return 0; /* never anything pending */
}

static struct hw_interrupt_type i8259A_irq_type = {
	.typename = "XT-PIC",
	.startup = startup_8259A_irq,
	.shutdown = shutdown_8259A_irq,
	.enable = enable_8259A_irq,
	.disable = disable_8259A_irq,
	.ack = mask_and_ack_8259A,
	.end = end_8259A_irq,
static struct irq_chip i8259A_chip = {
	.name		= "XT-PIC",
	.mask		= disable_8259A_irq,
	.unmask		= enable_8259A_irq,
	.mask_ack	= mask_and_ack_8259A,
};

/*
@@ -133,7 +113,7 @@ void make_8259A_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	io_apic_irqs &= ~(1<<irq);
	irq_desc[irq].chip = &i8259A_irq_type;
	set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
	enable_irq(irq);
}

@@ -327,12 +307,12 @@ void init_8259A(int auto_eoi)
	outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
	if (auto_eoi)
		/*
		 * in AEOI mode we just have to mask the interrupt
		 * In AEOI mode we just have to mask the interrupt
		 * when acking.
		 */
		i8259A_irq_type.ack = disable_8259A_irq;
		i8259A_chip.mask_ack = disable_8259A_irq;
	else
		i8259A_irq_type.ack = mask_and_ack_8259A;
		i8259A_chip.mask_ack = mask_and_ack_8259A;

	udelay(100);		/* wait for 8259A to initialize */

@@ -389,12 +369,13 @@ void __init init_ISA_irqs (void)
			/*
			 * 16 old-style INTA-cycle interrupts:
			 */
			irq_desc[i].chip = &i8259A_irq_type;
			set_irq_chip_and_handler(i, &i8259A_chip,
						 handle_level_irq);
		} else {
			/*
			 * 'high' PCI IRQs filled in on demand
			 */
			irq_desc[i].chip = &no_irq_type;
			irq_desc[i].chip = &no_irq_chip;
		}
	}
}
+56 −104
Original line number Diff line number Diff line
@@ -1219,8 +1219,7 @@ int assign_irq_vector(int irq)
	return vector;
}

static struct hw_interrupt_type ioapic_level_type;
static struct hw_interrupt_type ioapic_edge_type;
static struct irq_chip ioapic_chip;

#define IOAPIC_AUTO	-1
#define IOAPIC_EDGE	0
@@ -1234,9 +1233,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)

	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
			trigger == IOAPIC_LEVEL)
		irq_desc[idx].chip = &ioapic_level_type;
		set_irq_chip_and_handler(idx, &ioapic_chip,
					 handle_fasteoi_irq);
	else
		irq_desc[idx].chip = &ioapic_edge_type;
		set_irq_chip_and_handler(idx, &ioapic_chip,
					 handle_edge_irq);
	set_intr_gate(vector, interrupt[idx]);
}

@@ -1346,7 +1347,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
	 * The timer IRQ doesn't have to know that behind the
	 * scene we have a 8259A-master in AEOI mode ...
	 */
	irq_desc[0].chip = &ioapic_edge_type;
	irq_desc[0].chip = &ioapic_chip;
	set_irq_handler(0, handle_edge_irq);

	/*
	 * Add it to the IO-APIC irq-routing table:
@@ -1918,6 +1920,8 @@ static int __init timer_irq_works(void)
 */

/*
 * Startup quirk:
 *
 * Starting up a edge-triggered IO-APIC interrupt is
 * nasty - we need to make sure that we get the edge.
 * If it is already asserted for some reason, we need
@@ -1925,8 +1929,10 @@ static int __init timer_irq_works(void)
 *
 * This is not complete - we should be able to fake
 * an edge even if it isn't on the 8259A...
 *
 * (We do this for level-triggered IRQs too - it cannot hurt.)
 */
static unsigned int startup_edge_ioapic_irq(unsigned int irq)
static unsigned int startup_ioapic_irq(unsigned int irq)
{
	int was_pending = 0;
	unsigned long flags;
@@ -1943,42 +1949,13 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
	return was_pending;
}

/*
 * Once we have recorded IRQ_PENDING already, we can mask the
 * interrupt for real. This prevents IRQ storms from unhandled
 * devices.
 */
static void ack_edge_ioapic_irq(unsigned int irq)
static void ack_ioapic_irq(unsigned int irq)
{
	move_irq(irq);
	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
					== (IRQ_PENDING | IRQ_DISABLED))
		mask_IO_APIC_irq(irq);
	ack_APIC_irq();
}

/*
 * Level triggered interrupts can just be masked,
 * and shutting down and starting up the interrupt
 * is the same as enabling and disabling them -- except
 * with a startup need to return a "was pending" value.
 *
 * Level triggered interrupts are special because we
 * do not touch any IO-APIC register while handling
 * them. We ack the APIC in the end-IRQ handler, not
 * in the start-IRQ-handler. Protection against reentrance
 * from the same interrupt is still provided, both by the
 * generic IRQ layer and by the fact that an unacked local
 * APIC does not accept IRQs.
 */
static unsigned int startup_level_ioapic_irq (unsigned int irq)
{
	unmask_IO_APIC_irq(irq);

	return 0; /* don't check for pending */
}

static void end_level_ioapic_irq (unsigned int irq)
static void ack_ioapic_quirk_irq(unsigned int irq)
{
	unsigned long v;
	int i;
@@ -2018,35 +1995,27 @@ static void end_level_ioapic_irq (unsigned int irq)
	}
}

#ifdef CONFIG_PCI_MSI
static unsigned int startup_edge_ioapic_vector(unsigned int vector)
static unsigned int startup_ioapic_vector(unsigned int vector)
{
	int irq = vector_to_irq(vector);

	return startup_edge_ioapic_irq(irq);
	return startup_ioapic_irq(irq);
}

static void ack_edge_ioapic_vector(unsigned int vector)
static void ack_ioapic_vector(unsigned int vector)
{
	int irq = vector_to_irq(vector);

	move_native_irq(vector);
	ack_edge_ioapic_irq(irq);
	ack_ioapic_irq(irq);
}

static unsigned int startup_level_ioapic_vector (unsigned int vector)
{
	int irq = vector_to_irq(vector);

	return startup_level_ioapic_irq (irq);
}

static void end_level_ioapic_vector (unsigned int vector)
static void ack_ioapic_quirk_vector(unsigned int vector)
{
	int irq = vector_to_irq(vector);

	move_native_irq(vector);
	end_level_ioapic_irq(irq);
	ack_ioapic_quirk_irq(irq);
}

static void mask_IO_APIC_vector (unsigned int vector)
@@ -2063,7 +2032,12 @@ static void unmask_IO_APIC_vector (unsigned int vector)
	unmask_IO_APIC_irq(irq);
}

#ifdef CONFIG_SMP
/*
 * Oh just glorious.  If CONFIG_PCI_MSI we've done
 * #define set_ioapic_affinity set_ioapic_affinity_vector
 */
#if defined (CONFIG_SMP) && defined(CONFIG_X86_IO_APIC) && \
		defined(CONFIG_PCI_MSI)
static void set_ioapic_affinity_vector (unsigned int vector,
					cpumask_t cpu_mask)
{
@@ -2073,50 +2047,29 @@ static void set_ioapic_affinity_vector (unsigned int vector,
	set_ioapic_affinity_irq(irq, cpu_mask);
}
#endif
#endif

static int ioapic_retrigger(unsigned int irq)
static int ioapic_retrigger_vector(unsigned int vector)
{
	int irq = vector_to_irq(vector);

	send_IPI_self(IO_APIC_VECTOR(irq));

	return 1;
}

/*
 * Level and edge triggered IO-APIC interrupts need different handling,
 * so we use two separate IRQ descriptors. Edge triggered IRQs can be
 * handled with the level-triggered descriptor, but that one has slightly
 * more overhead. Level-triggered interrupts cannot be handled with the
 * edge-triggered handler, without risking IRQ storms and other ugly
 * races.
 */
static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
	.typename 	= "IO-APIC-edge",
	.startup 	= startup_edge_ioapic,
	.shutdown 	= shutdown_edge_ioapic,
	.enable 	= enable_edge_ioapic,
	.disable 	= disable_edge_ioapic,
	.ack 		= ack_edge_ioapic,
	.end 		= end_edge_ioapic,
static struct irq_chip ioapic_chip __read_mostly = {
	.name 		= "IO-APIC",
	.startup 	= startup_ioapic_vector,
	.mask	 	= mask_IO_APIC_vector,
	.unmask	 	= unmask_IO_APIC_vector,
	.ack 		= ack_ioapic_vector,
	.eoi 		= ack_ioapic_quirk_vector,
#ifdef CONFIG_SMP
	.set_affinity 	= set_ioapic_affinity,
#endif
	.retrigger	= ioapic_retrigger,
	.retrigger	= ioapic_retrigger_vector,
};

static struct hw_interrupt_type ioapic_level_type __read_mostly = {
	.typename 	= "IO-APIC-level",
	.startup 	= startup_level_ioapic,
	.shutdown 	= shutdown_level_ioapic,
	.enable 	= enable_level_ioapic,
	.disable 	= disable_level_ioapic,
	.ack 		= mask_and_ack_level_ioapic,
	.end 		= end_level_ioapic,
#ifdef CONFIG_SMP
	.set_affinity 	= set_ioapic_affinity,
#endif
	.retrigger	= ioapic_retrigger,
};

static inline void init_IO_APIC_traps(void)
{
@@ -2150,20 +2103,21 @@ static inline void init_IO_APIC_traps(void)
				make_8259A_irq(irq);
			else
				/* Strange. Oh, well.. */
				irq_desc[irq].chip = &no_irq_type;
				irq_desc[irq].chip = &no_irq_chip;
		}
	}
}

static void enable_lapic_irq (unsigned int irq)
{
	unsigned long v;
/*
 * The local APIC irq-chip implementation:
 */

	v = apic_read(APIC_LVT0);
	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
static void ack_apic(unsigned int irq)
{
	ack_APIC_irq();
}

static void disable_lapic_irq (unsigned int irq)
static void mask_lapic_irq (unsigned int irq)
{
	unsigned long v;

@@ -2171,21 +2125,19 @@ static void disable_lapic_irq (unsigned int irq)
	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
}

static void ack_lapic_irq (unsigned int irq)
static void unmask_lapic_irq (unsigned int irq)
{
	ack_APIC_irq();
}
	unsigned long v;

static void end_lapic_irq (unsigned int i) { /* nothing */ }
	v = apic_read(APIC_LVT0);
	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
}

static struct hw_interrupt_type lapic_irq_type __read_mostly = {
	.typename 	= "local-APIC-edge",
	.startup 	= NULL, /* startup_irq() not used for IRQ0 */
	.shutdown 	= NULL, /* shutdown_irq() not used for IRQ0 */
	.enable 	= enable_lapic_irq,
	.disable 	= disable_lapic_irq,
	.ack 		= ack_lapic_irq,
	.end 		= end_lapic_irq
static struct irq_chip lapic_chip __read_mostly = {
	.name		= "local-APIC-edge",
	.mask		= mask_lapic_irq,
	.unmask		= unmask_lapic_irq,
	.eoi		= ack_apic,
};

static void setup_nmi (void)
@@ -2356,7 +2308,7 @@ static inline void check_timer(void)
	printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");

	disable_8259A_irq(0);
	irq_desc[0].chip = &lapic_irq_type;
	set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
	apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);	/* Fixed mode */
	enable_8259A_irq(0);

+11 −8
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
{	
	/* high bit used in ret_from_ code */
	int irq = ~regs->orig_eax;
	struct irq_desc *desc = irq_desc + irq;
#ifdef CONFIG_4KSTACKS
	union irq_ctx *curctx, *irqctx;
	u32 *isp;
@@ -94,7 +95,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
	 * current stack (which is the irq stack already after all)
	 */
	if (curctx != irqctx) {
		int arg1, arg2, ebx;
		int arg1, arg2, arg3, ebx;

		/* build the stack frame on the IRQ stack */
		isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -111,15 +112,16 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)

		asm volatile(
			"       xchgl  %%ebx,%%esp      \n"
			"       call    __do_IRQ         \n"
			"       call   *%%edi           \n"
			"       movl   %%ebx,%%esp      \n"
			: "=a" (arg1), "=d" (arg2), "=b" (ebx)
			:  "0" (irq),   "1" (regs),  "2" (isp)
			: "memory", "cc", "ecx"
			: "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
			:  "0" (irq),   "1" (desc),  "2" (regs),  "3" (isp),
			   "D" (desc->handle_irq)
			: "memory", "cc"
		);
	} else
#endif
		__do_IRQ(irq, regs);
		desc->handle_irq(irq, desc, regs);

	irq_exit();

@@ -253,7 +255,8 @@ int show_interrupts(struct seq_file *p, void *v)
		for_each_online_cpu(j)
			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
		seq_printf(p, " %14s", irq_desc[i].chip->typename);
		seq_printf(p, " %8s", irq_desc[i].chip->name);
		seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
		seq_printf(p, "  %s", action->name);

		for (action=action->next; action; action = action->next)
+0 −2
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@
#include <asm/irq.h>
#include <asm/sections.h>

struct hw_interrupt_type;

#define NMI_VECTOR		0x02

/*