diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-10-04 05:16:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:25 -0400 |
commit | f5b9ed7acdcfea4bf73a70dececa7483787503ed (patch) | |
tree | d2d1510d8a4dd8a5a00310dd07ab791c2ab0612f /arch/i386/kernel/io_apic.c | |
parent | f29bd1ba68c8c6a0f50bd678bbd5a26674018f7c (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>
Diffstat (limited to 'arch/i386/kernel/io_apic.c')
-rw-r--r-- | arch/i386/kernel/io_apic.c | 160 |
1 files changed, 56 insertions, 104 deletions
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 | ||
1222 | static struct hw_interrupt_type ioapic_level_type; | 1222 | static struct irq_chip ioapic_chip; |
1223 | static 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 | */ |
1929 | static unsigned int startup_edge_ioapic_irq(unsigned int irq) | 1935 | static 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 | /* | 1952 | static 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 | */ | ||
1951 | static 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 | /* | 1958 | static 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 | */ | ||
1974 | static 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 | |||
1981 | static 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 | 1998 | static unsigned int startup_ioapic_vector(unsigned int vector) |
2022 | static 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 | ||
2029 | static void ack_edge_ioapic_vector(unsigned int vector) | 2005 | static 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 | ||
2037 | static unsigned int startup_level_ioapic_vector (unsigned int vector) | 2013 | static 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 | |||
2044 | static 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 | ||
2052 | static void mask_IO_APIC_vector (unsigned int vector) | 2021 | static 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) | ||
2067 | static void set_ioapic_affinity_vector (unsigned int vector, | 2041 | static 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 | ||
2078 | static int ioapic_retrigger(unsigned int irq) | 2051 | static 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 | /* | 2060 | static 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 | */ | ||
2093 | static 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 | ||
2107 | static 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 | ||
2121 | static inline void init_IO_APIC_traps(void) | 2074 | static 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 | ||
2158 | static 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); | 2115 | static 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 | ||
2166 | static void disable_lapic_irq (unsigned int irq) | 2120 | static 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 | ||
2174 | static void ack_lapic_irq (unsigned int irq) | 2128 | static void unmask_lapic_irq (unsigned int irq) |
2175 | { | 2129 | { |
2176 | ack_APIC_irq(); | 2130 | unsigned long v; |
2177 | } | ||
2178 | 2131 | ||
2179 | static 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 | ||
2181 | static struct hw_interrupt_type lapic_irq_type __read_mostly = { | 2136 | static 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 | ||
2191 | static void setup_nmi (void) | 2143 | static 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 | ||