aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2006-10-04 05:16:26 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:25 -0400
commitf5b9ed7acdcfea4bf73a70dececa7483787503ed (patch)
treed2d1510d8a4dd8a5a00310dd07ab791c2ab0612f
parentf29bd1ba68c8c6a0f50bd678bbd5a26674018f7c (diff)
[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: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/i386/kernel/i8259.c45
-rw-r--r--arch/i386/kernel/io_apic.c160
-rw-r--r--arch/i386/kernel/irq.c19
-rw-r--r--include/asm-i386/hw_irq.h2
4 files changed, 80 insertions, 146 deletions
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index ea5f4e7958d8..d07ed31f11e3 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -34,35 +34,15 @@
34 * moves to arch independent land 34 * moves to arch independent land
35 */ 35 */
36 36
37DEFINE_SPINLOCK(i8259A_lock);
38
39static void end_8259A_irq (unsigned int irq)
40{
41 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
42 irq_desc[irq].action)
43 enable_8259A_irq(irq);
44}
45
46#define shutdown_8259A_irq disable_8259A_irq
47
48static int i8259A_auto_eoi; 37static int i8259A_auto_eoi;
49 38DEFINE_SPINLOCK(i8259A_lock);
50static void mask_and_ack_8259A(unsigned int); 39static void mask_and_ack_8259A(unsigned int);
51 40
52unsigned int startup_8259A_irq(unsigned int irq) 41static struct irq_chip i8259A_chip = {
53{ 42 .name = "XT-PIC",
54 enable_8259A_irq(irq); 43 .mask = disable_8259A_irq,
55 return 0; /* never anything pending */ 44 .unmask = enable_8259A_irq,
56} 45 .mask_ack = mask_and_ack_8259A,
57
58static struct hw_interrupt_type i8259A_irq_type = {
59 .typename = "XT-PIC",
60 .startup = startup_8259A_irq,
61 .shutdown = shutdown_8259A_irq,
62 .enable = enable_8259A_irq,
63 .disable = disable_8259A_irq,
64 .ack = mask_and_ack_8259A,
65 .end = end_8259A_irq,
66}; 46};
67 47
68/* 48/*
@@ -133,7 +113,7 @@ void make_8259A_irq(unsigned int irq)
133{ 113{
134 disable_irq_nosync(irq); 114 disable_irq_nosync(irq);
135 io_apic_irqs &= ~(1<<irq); 115 io_apic_irqs &= ~(1<<irq);
136 irq_desc[irq].chip = &i8259A_irq_type; 116 set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
137 enable_irq(irq); 117 enable_irq(irq);
138} 118}
139 119
@@ -327,12 +307,12 @@ void init_8259A(int auto_eoi)
327 outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ 307 outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
328 if (auto_eoi) 308 if (auto_eoi)
329 /* 309 /*
330 * in AEOI mode we just have to mask the interrupt 310 * In AEOI mode we just have to mask the interrupt
331 * when acking. 311 * when acking.
332 */ 312 */
333 i8259A_irq_type.ack = disable_8259A_irq; 313 i8259A_chip.mask_ack = disable_8259A_irq;
334 else 314 else
335 i8259A_irq_type.ack = mask_and_ack_8259A; 315 i8259A_chip.mask_ack = mask_and_ack_8259A;
336 316
337 udelay(100); /* wait for 8259A to initialize */ 317 udelay(100); /* wait for 8259A to initialize */
338 318
@@ -389,12 +369,13 @@ void __init init_ISA_irqs (void)
389 /* 369 /*
390 * 16 old-style INTA-cycle interrupts: 370 * 16 old-style INTA-cycle interrupts:
391 */ 371 */
392 irq_desc[i].chip = &i8259A_irq_type; 372 set_irq_chip_and_handler(i, &i8259A_chip,
373 handle_level_irq);
393 } else { 374 } else {
394 /* 375 /*
395 * 'high' PCI IRQs filled in on demand 376 * 'high' PCI IRQs filled in on demand
396 */ 377 */
397 irq_desc[i].chip = &no_irq_type; 378 irq_desc[i].chip = &no_irq_chip;
398 } 379 }
399 } 380 }
400} 381}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index fd0df75cfbda..b3b01894ca69 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -1219,8 +1219,7 @@ next:
1219 return vector; 1219 return vector;
1220} 1220}
1221 1221
1222static struct hw_interrupt_type ioapic_level_type; 1222static struct irq_chip ioapic_chip;
1223static struct hw_interrupt_type ioapic_edge_type;
1224 1223
1225#define IOAPIC_AUTO -1 1224#define IOAPIC_AUTO -1
1226#define IOAPIC_EDGE 0 1225#define IOAPIC_EDGE 0
@@ -1234,9 +1233,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
1234 1233
1235 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || 1234 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
1236 trigger == IOAPIC_LEVEL) 1235 trigger == IOAPIC_LEVEL)
1237 irq_desc[idx].chip = &ioapic_level_type; 1236 set_irq_chip_and_handler(idx, &ioapic_chip,
1237 handle_fasteoi_irq);
1238 else 1238 else
1239 irq_desc[idx].chip = &ioapic_edge_type; 1239 set_irq_chip_and_handler(idx, &ioapic_chip,
1240 handle_edge_irq);
1240 set_intr_gate(vector, interrupt[idx]); 1241 set_intr_gate(vector, interrupt[idx]);
1241} 1242}
1242 1243
@@ -1346,7 +1347,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
1346 * The timer IRQ doesn't have to know that behind the 1347 * The timer IRQ doesn't have to know that behind the
1347 * scene we have a 8259A-master in AEOI mode ... 1348 * scene we have a 8259A-master in AEOI mode ...
1348 */ 1349 */
1349 irq_desc[0].chip = &ioapic_edge_type; 1350 irq_desc[0].chip = &ioapic_chip;
1351 set_irq_handler(0, handle_edge_irq);
1350 1352
1351 /* 1353 /*
1352 * Add it to the IO-APIC irq-routing table: 1354 * Add it to the IO-APIC irq-routing table:
@@ -1918,6 +1920,8 @@ static int __init timer_irq_works(void)
1918 */ 1920 */
1919 1921
1920/* 1922/*
1923 * Startup quirk:
1924 *
1921 * Starting up a edge-triggered IO-APIC interrupt is 1925 * Starting up a edge-triggered IO-APIC interrupt is
1922 * nasty - we need to make sure that we get the edge. 1926 * nasty - we need to make sure that we get the edge.
1923 * If it is already asserted for some reason, we need 1927 * If it is already asserted for some reason, we need
@@ -1925,8 +1929,10 @@ static int __init timer_irq_works(void)
1925 * 1929 *
1926 * This is not complete - we should be able to fake 1930 * This is not complete - we should be able to fake
1927 * an edge even if it isn't on the 8259A... 1931 * an edge even if it isn't on the 8259A...
1932 *
1933 * (We do this for level-triggered IRQs too - it cannot hurt.)
1928 */ 1934 */
1929static unsigned int startup_edge_ioapic_irq(unsigned int irq) 1935static unsigned int startup_ioapic_irq(unsigned int irq)
1930{ 1936{
1931 int was_pending = 0; 1937 int was_pending = 0;
1932 unsigned long flags; 1938 unsigned long flags;
@@ -1943,42 +1949,13 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
1943 return was_pending; 1949 return was_pending;
1944} 1950}
1945 1951
1946/* 1952static void ack_ioapic_irq(unsigned int irq)
1947 * Once we have recorded IRQ_PENDING already, we can mask the
1948 * interrupt for real. This prevents IRQ storms from unhandled
1949 * devices.
1950 */
1951static void ack_edge_ioapic_irq(unsigned int irq)
1952{ 1953{
1953 move_irq(irq); 1954 move_irq(irq);
1954 if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
1955 == (IRQ_PENDING | IRQ_DISABLED))
1956 mask_IO_APIC_irq(irq);
1957 ack_APIC_irq(); 1955 ack_APIC_irq();
1958} 1956}
1959 1957
1960/* 1958static void ack_ioapic_quirk_irq(unsigned int irq)
1961 * Level triggered interrupts can just be masked,
1962 * and shutting down and starting up the interrupt
1963 * is the same as enabling and disabling them -- except
1964 * with a startup need to return a "was pending" value.
1965 *
1966 * Level triggered interrupts are special because we
1967 * do not touch any IO-APIC register while handling
1968 * them. We ack the APIC in the end-IRQ handler, not
1969 * in the start-IRQ-handler. Protection against reentrance
1970 * from the same interrupt is still provided, both by the
1971 * generic IRQ layer and by the fact that an unacked local
1972 * APIC does not accept IRQs.
1973 */
1974static unsigned int startup_level_ioapic_irq (unsigned int irq)
1975{
1976 unmask_IO_APIC_irq(irq);
1977
1978 return 0; /* don't check for pending */
1979}
1980
1981static void end_level_ioapic_irq (unsigned int irq)
1982{ 1959{
1983 unsigned long v; 1960 unsigned long v;
1984 int i; 1961 int i;
@@ -2018,35 +1995,27 @@ static void end_level_ioapic_irq (unsigned int irq)
2018 } 1995 }
2019} 1996}
2020 1997
2021#ifdef CONFIG_PCI_MSI 1998static unsigned int startup_ioapic_vector(unsigned int vector)
2022static unsigned int startup_edge_ioapic_vector(unsigned int vector)
2023{ 1999{
2024 int irq = vector_to_irq(vector); 2000 int irq = vector_to_irq(vector);
2025 2001
2026 return startup_edge_ioapic_irq(irq); 2002 return startup_ioapic_irq(irq);
2027} 2003}
2028 2004
2029static void ack_edge_ioapic_vector(unsigned int vector) 2005static void ack_ioapic_vector(unsigned int vector)
2030{ 2006{
2031 int irq = vector_to_irq(vector); 2007 int irq = vector_to_irq(vector);
2032 2008
2033 move_native_irq(vector); 2009 move_native_irq(vector);
2034 ack_edge_ioapic_irq(irq); 2010 ack_ioapic_irq(irq);
2035} 2011}
2036 2012
2037static unsigned int startup_level_ioapic_vector (unsigned int vector) 2013static void ack_ioapic_quirk_vector(unsigned int vector)
2038{
2039 int irq = vector_to_irq(vector);
2040
2041 return startup_level_ioapic_irq (irq);
2042}
2043
2044static void end_level_ioapic_vector (unsigned int vector)
2045{ 2014{
2046 int irq = vector_to_irq(vector); 2015 int irq = vector_to_irq(vector);
2047 2016
2048 move_native_irq(vector); 2017 move_native_irq(vector);
2049 end_level_ioapic_irq(irq); 2018 ack_ioapic_quirk_irq(irq);
2050} 2019}
2051 2020
2052static void mask_IO_APIC_vector (unsigned int vector) 2021static void mask_IO_APIC_vector (unsigned int vector)
@@ -2063,7 +2032,12 @@ static void unmask_IO_APIC_vector (unsigned int vector)
2063 unmask_IO_APIC_irq(irq); 2032 unmask_IO_APIC_irq(irq);
2064} 2033}
2065 2034
2066#ifdef CONFIG_SMP 2035/*
2036 * Oh just glorious. If CONFIG_PCI_MSI we've done
2037 * #define set_ioapic_affinity set_ioapic_affinity_vector
2038 */
2039#if defined (CONFIG_SMP) && defined(CONFIG_X86_IO_APIC) && \
2040 defined(CONFIG_PCI_MSI)
2067static void set_ioapic_affinity_vector (unsigned int vector, 2041static void set_ioapic_affinity_vector (unsigned int vector,
2068 cpumask_t cpu_mask) 2042 cpumask_t cpu_mask)
2069{ 2043{
@@ -2073,50 +2047,29 @@ static void set_ioapic_affinity_vector (unsigned int vector,
2073 set_ioapic_affinity_irq(irq, cpu_mask); 2047 set_ioapic_affinity_irq(irq, cpu_mask);
2074} 2048}
2075#endif 2049#endif
2076#endif
2077 2050
2078static int ioapic_retrigger(unsigned int irq) 2051static int ioapic_retrigger_vector(unsigned int vector)
2079{ 2052{
2053 int irq = vector_to_irq(vector);
2054
2080 send_IPI_self(IO_APIC_VECTOR(irq)); 2055 send_IPI_self(IO_APIC_VECTOR(irq));
2081 2056
2082 return 1; 2057 return 1;
2083} 2058}
2084 2059
2085/* 2060static struct irq_chip ioapic_chip __read_mostly = {
2086 * Level and edge triggered IO-APIC interrupts need different handling, 2061 .name = "IO-APIC",
2087 * so we use two separate IRQ descriptors. Edge triggered IRQs can be 2062 .startup = startup_ioapic_vector,
2088 * handled with the level-triggered descriptor, but that one has slightly 2063 .mask = mask_IO_APIC_vector,
2089 * more overhead. Level-triggered interrupts cannot be handled with the 2064 .unmask = unmask_IO_APIC_vector,
2090 * edge-triggered handler, without risking IRQ storms and other ugly 2065 .ack = ack_ioapic_vector,
2091 * races. 2066 .eoi = ack_ioapic_quirk_vector,
2092 */
2093static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
2094 .typename = "IO-APIC-edge",
2095 .startup = startup_edge_ioapic,
2096 .shutdown = shutdown_edge_ioapic,
2097 .enable = enable_edge_ioapic,
2098 .disable = disable_edge_ioapic,
2099 .ack = ack_edge_ioapic,
2100 .end = end_edge_ioapic,
2101#ifdef CONFIG_SMP 2067#ifdef CONFIG_SMP
2102 .set_affinity = set_ioapic_affinity, 2068 .set_affinity = set_ioapic_affinity,
2103#endif 2069#endif
2104 .retrigger = ioapic_retrigger, 2070 .retrigger = ioapic_retrigger_vector,
2105}; 2071};
2106 2072
2107static struct hw_interrupt_type ioapic_level_type __read_mostly = {
2108 .typename = "IO-APIC-level",
2109 .startup = startup_level_ioapic,
2110 .shutdown = shutdown_level_ioapic,
2111 .enable = enable_level_ioapic,
2112 .disable = disable_level_ioapic,
2113 .ack = mask_and_ack_level_ioapic,
2114 .end = end_level_ioapic,
2115#ifdef CONFIG_SMP
2116 .set_affinity = set_ioapic_affinity,
2117#endif
2118 .retrigger = ioapic_retrigger,
2119};
2120 2073
2121static inline void init_IO_APIC_traps(void) 2074static inline void init_IO_APIC_traps(void)
2122{ 2075{
@@ -2150,20 +2103,21 @@ static inline void init_IO_APIC_traps(void)
2150 make_8259A_irq(irq); 2103 make_8259A_irq(irq);
2151 else 2104 else
2152 /* Strange. Oh, well.. */ 2105 /* Strange. Oh, well.. */
2153 irq_desc[irq].chip = &no_irq_type; 2106 irq_desc[irq].chip = &no_irq_chip;
2154 } 2107 }
2155 } 2108 }
2156} 2109}
2157 2110
2158static void enable_lapic_irq (unsigned int irq) 2111/*
2159{ 2112 * The local APIC irq-chip implementation:
2160 unsigned long v; 2113 */
2161 2114
2162 v = apic_read(APIC_LVT0); 2115static void ack_apic(unsigned int irq)
2163 apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); 2116{
2117 ack_APIC_irq();
2164} 2118}
2165 2119
2166static void disable_lapic_irq (unsigned int irq) 2120static void mask_lapic_irq (unsigned int irq)
2167{ 2121{
2168 unsigned long v; 2122 unsigned long v;
2169 2123
@@ -2171,21 +2125,19 @@ static void disable_lapic_irq (unsigned int irq)
2171 apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); 2125 apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
2172} 2126}
2173 2127
2174static void ack_lapic_irq (unsigned int irq) 2128static void unmask_lapic_irq (unsigned int irq)
2175{ 2129{
2176 ack_APIC_irq(); 2130 unsigned long v;
2177}
2178 2131
2179static void end_lapic_irq (unsigned int i) { /* nothing */ } 2132 v = apic_read(APIC_LVT0);
2133 apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
2134}
2180 2135
2181static struct hw_interrupt_type lapic_irq_type __read_mostly = { 2136static struct irq_chip lapic_chip __read_mostly = {
2182 .typename = "local-APIC-edge", 2137 .name = "local-APIC-edge",
2183 .startup = NULL, /* startup_irq() not used for IRQ0 */ 2138 .mask = mask_lapic_irq,
2184 .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ 2139 .unmask = unmask_lapic_irq,
2185 .enable = enable_lapic_irq, 2140 .eoi = ack_apic,
2186 .disable = disable_lapic_irq,
2187 .ack = ack_lapic_irq,
2188 .end = end_lapic_irq
2189}; 2141};
2190 2142
2191static void setup_nmi (void) 2143static void setup_nmi (void)
@@ -2356,7 +2308,7 @@ static inline void check_timer(void)
2356 printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); 2308 printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
2357 2309
2358 disable_8259A_irq(0); 2310 disable_8259A_irq(0);
2359 irq_desc[0].chip = &lapic_irq_type; 2311 set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
2360 apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ 2312 apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
2361 enable_8259A_irq(0); 2313 enable_8259A_irq(0);
2362 2314
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 5fe547cd8f9f..3dd2e180151b 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -55,6 +55,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
55{ 55{
56 /* high bit used in ret_from_ code */ 56 /* high bit used in ret_from_ code */
57 int irq = ~regs->orig_eax; 57 int irq = ~regs->orig_eax;
58 struct irq_desc *desc = irq_desc + irq;
58#ifdef CONFIG_4KSTACKS 59#ifdef CONFIG_4KSTACKS
59 union irq_ctx *curctx, *irqctx; 60 union irq_ctx *curctx, *irqctx;
60 u32 *isp; 61 u32 *isp;
@@ -94,7 +95,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
94 * current stack (which is the irq stack already after all) 95 * current stack (which is the irq stack already after all)
95 */ 96 */
96 if (curctx != irqctx) { 97 if (curctx != irqctx) {
97 int arg1, arg2, ebx; 98 int arg1, arg2, arg3, ebx;
98 99
99 /* build the stack frame on the IRQ stack */ 100 /* build the stack frame on the IRQ stack */
100 isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); 101 isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -110,16 +111,17 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
110 (curctx->tinfo.preempt_count & SOFTIRQ_MASK); 111 (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
111 112
112 asm volatile( 113 asm volatile(
113 " xchgl %%ebx,%%esp \n" 114 " xchgl %%ebx,%%esp \n"
114 " call __do_IRQ \n" 115 " call *%%edi \n"
115 " movl %%ebx,%%esp \n" 116 " movl %%ebx,%%esp \n"
116 : "=a" (arg1), "=d" (arg2), "=b" (ebx) 117 : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
117 : "0" (irq), "1" (regs), "2" (isp) 118 : "0" (irq), "1" (desc), "2" (regs), "3" (isp),
118 : "memory", "cc", "ecx" 119 "D" (desc->handle_irq)
120 : "memory", "cc"
119 ); 121 );
120 } else 122 } else
121#endif 123#endif
122 __do_IRQ(irq, regs); 124 desc->handle_irq(irq, desc, regs);
123 125
124 irq_exit(); 126 irq_exit();
125 127
@@ -253,7 +255,8 @@ int show_interrupts(struct seq_file *p, void *v)
253 for_each_online_cpu(j) 255 for_each_online_cpu(j)
254 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); 256 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
255#endif 257#endif
256 seq_printf(p, " %14s", irq_desc[i].chip->typename); 258 seq_printf(p, " %8s", irq_desc[i].chip->name);
259 seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
257 seq_printf(p, " %s", action->name); 260 seq_printf(p, " %s", action->name);
258 261
259 for (action=action->next; action; action = action->next) 262 for (action=action->next; action; action = action->next)
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 87e5a351d881..8e8fbfaa252a 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -17,8 +17,6 @@
17#include <asm/irq.h> 17#include <asm/irq.h>
18#include <asm/sections.h> 18#include <asm/sections.h>
19 19
20struct hw_interrupt_type;
21
22#define NMI_VECTOR 0x02 20#define NMI_VECTOR 0x02
23 21
24/* 22/*