diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-10-04 05:16:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:25 -0400 |
commit | f29bd1ba68c8c6a0f50bd678bbd5a26674018f7c (patch) | |
tree | 5a2f6086397b94e9094fa065a344bcb7e6a05ac0 | |
parent | 0271eb947db2704a0ff8be68d72915ab021d1ead (diff) |
[PATCH] genirq: convert the x86_64 architecture to irq-chips
This patch converts all the x86_64 PIC controllers layers to the new and
simpler irq-chip interrupt handling layer.
[mingo@elte.hu: The patch also enables the fasteoi handler for x86_64]
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>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/x86_64/kernel/i8259.c | 50 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 130 | ||||
-rw-r--r-- | arch/x86_64/kernel/irq.c | 5 | ||||
-rw-r--r-- | include/asm-x86_64/hw_irq.h | 2 |
4 files changed, 44 insertions, 143 deletions
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 2dd51f364ea2..ae1101cd5252 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c | |||
@@ -121,42 +121,15 @@ void (*interrupt[NR_IRQS])(void) = { | |||
121 | * moves to arch independent land | 121 | * moves to arch independent land |
122 | */ | 122 | */ |
123 | 123 | ||
124 | DEFINE_SPINLOCK(i8259A_lock); | ||
125 | |||
126 | static int i8259A_auto_eoi; | 124 | static int i8259A_auto_eoi; |
127 | 125 | DEFINE_SPINLOCK(i8259A_lock); | |
128 | static void end_8259A_irq (unsigned int irq) | ||
129 | { | ||
130 | if (irq > 256) { | ||
131 | char var; | ||
132 | printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current)); | ||
133 | |||
134 | BUG(); | ||
135 | } | ||
136 | |||
137 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && | ||
138 | irq_desc[irq].action) | ||
139 | enable_8259A_irq(irq); | ||
140 | } | ||
141 | |||
142 | #define shutdown_8259A_irq disable_8259A_irq | ||
143 | |||
144 | static void mask_and_ack_8259A(unsigned int); | 126 | static void mask_and_ack_8259A(unsigned int); |
145 | 127 | ||
146 | static unsigned int startup_8259A_irq(unsigned int irq) | 128 | static struct irq_chip i8259A_chip = { |
147 | { | 129 | .name = "XT-PIC", |
148 | enable_8259A_irq(irq); | 130 | .mask = disable_8259A_irq, |
149 | return 0; /* never anything pending */ | 131 | .unmask = enable_8259A_irq, |
150 | } | 132 | .mask_ack = mask_and_ack_8259A, |
151 | |||
152 | static struct hw_interrupt_type i8259A_irq_type = { | ||
153 | .typename = "XT-PIC", | ||
154 | .startup = startup_8259A_irq, | ||
155 | .shutdown = shutdown_8259A_irq, | ||
156 | .enable = enable_8259A_irq, | ||
157 | .disable = disable_8259A_irq, | ||
158 | .ack = mask_and_ack_8259A, | ||
159 | .end = end_8259A_irq, | ||
160 | }; | 133 | }; |
161 | 134 | ||
162 | /* | 135 | /* |
@@ -231,7 +204,7 @@ void make_8259A_irq(unsigned int irq) | |||
231 | { | 204 | { |
232 | disable_irq_nosync(irq); | 205 | disable_irq_nosync(irq); |
233 | io_apic_irqs &= ~(1<<irq); | 206 | io_apic_irqs &= ~(1<<irq); |
234 | irq_desc[irq].chip = &i8259A_irq_type; | 207 | set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); |
235 | enable_irq(irq); | 208 | enable_irq(irq); |
236 | } | 209 | } |
237 | 210 | ||
@@ -367,9 +340,9 @@ void init_8259A(int auto_eoi) | |||
367 | * in AEOI mode we just have to mask the interrupt | 340 | * in AEOI mode we just have to mask the interrupt |
368 | * when acking. | 341 | * when acking. |
369 | */ | 342 | */ |
370 | i8259A_irq_type.ack = disable_8259A_irq; | 343 | i8259A_chip.mask_ack = disable_8259A_irq; |
371 | else | 344 | else |
372 | i8259A_irq_type.ack = mask_and_ack_8259A; | 345 | i8259A_chip.mask_ack = mask_and_ack_8259A; |
373 | 346 | ||
374 | udelay(100); /* wait for 8259A to initialize */ | 347 | udelay(100); /* wait for 8259A to initialize */ |
375 | 348 | ||
@@ -464,12 +437,13 @@ void __init init_ISA_irqs (void) | |||
464 | /* | 437 | /* |
465 | * 16 old-style INTA-cycle interrupts: | 438 | * 16 old-style INTA-cycle interrupts: |
466 | */ | 439 | */ |
467 | irq_desc[i].chip = &i8259A_irq_type; | 440 | set_irq_chip_and_handler(i, &i8259A_chip, |
441 | handle_level_irq); | ||
468 | } else { | 442 | } else { |
469 | /* | 443 | /* |
470 | * 'high' PCI IRQs filled in on demand | 444 | * 'high' PCI IRQs filled in on demand |
471 | */ | 445 | */ |
472 | irq_desc[i].chip = &no_irq_type; | 446 | irq_desc[i].chip = &no_irq_chip; |
473 | } | 447 | } |
474 | } | 448 | } |
475 | } | 449 | } |
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 0491019d4c8d..e1d1b4217cb2 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -633,8 +633,8 @@ next: | |||
633 | } | 633 | } |
634 | 634 | ||
635 | extern void (*interrupt[NR_IRQS])(void); | 635 | extern void (*interrupt[NR_IRQS])(void); |
636 | static struct hw_interrupt_type ioapic_level_type; | 636 | |
637 | static struct hw_interrupt_type ioapic_edge_type; | 637 | static struct irq_chip ioapic_chip; |
638 | 638 | ||
639 | #define IOAPIC_AUTO -1 | 639 | #define IOAPIC_AUTO -1 |
640 | #define IOAPIC_EDGE 0 | 640 | #define IOAPIC_EDGE 0 |
@@ -648,9 +648,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger) | |||
648 | 648 | ||
649 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || | 649 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || |
650 | trigger == IOAPIC_LEVEL) | 650 | trigger == IOAPIC_LEVEL) |
651 | irq_desc[idx].chip = &ioapic_level_type; | 651 | set_irq_chip_and_handler(idx, &ioapic_chip, |
652 | handle_fasteoi_irq); | ||
652 | else | 653 | else |
653 | irq_desc[idx].chip = &ioapic_edge_type; | 654 | set_irq_chip_and_handler(idx, &ioapic_chip, |
655 | handle_edge_irq); | ||
654 | set_intr_gate(vector, interrupt[idx]); | 656 | set_intr_gate(vector, interrupt[idx]); |
655 | } | 657 | } |
656 | 658 | ||
@@ -752,7 +754,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in | |||
752 | * The timer IRQ doesn't have to know that behind the | 754 | * The timer IRQ doesn't have to know that behind the |
753 | * scene we have a 8259A-master in AEOI mode ... | 755 | * scene we have a 8259A-master in AEOI mode ... |
754 | */ | 756 | */ |
755 | irq_desc[0].chip = &ioapic_edge_type; | 757 | set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq); |
756 | 758 | ||
757 | /* | 759 | /* |
758 | * Add it to the IO-APIC irq-routing table: | 760 | * Add it to the IO-APIC irq-routing table: |
@@ -1185,7 +1187,7 @@ static int __init timer_irq_works(void) | |||
1185 | * an edge even if it isn't on the 8259A... | 1187 | * an edge even if it isn't on the 8259A... |
1186 | */ | 1188 | */ |
1187 | 1189 | ||
1188 | static unsigned int startup_edge_ioapic_irq(unsigned int irq) | 1190 | static unsigned int startup_ioapic_irq(unsigned int irq) |
1189 | { | 1191 | { |
1190 | int was_pending = 0; | 1192 | int was_pending = 0; |
1191 | unsigned long flags; | 1193 | unsigned long flags; |
@@ -1202,86 +1204,21 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) | |||
1202 | return was_pending; | 1204 | return was_pending; |
1203 | } | 1205 | } |
1204 | 1206 | ||
1205 | /* | 1207 | static unsigned int startup_ioapic_vector(unsigned int vector) |
1206 | * Once we have recorded IRQ_PENDING already, we can mask the | ||
1207 | * interrupt for real. This prevents IRQ storms from unhandled | ||
1208 | * devices. | ||
1209 | */ | ||
1210 | static void ack_edge_ioapic_irq(unsigned int irq) | ||
1211 | { | ||
1212 | move_irq(irq); | ||
1213 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) | ||
1214 | == (IRQ_PENDING | IRQ_DISABLED)) | ||
1215 | mask_IO_APIC_irq(irq); | ||
1216 | ack_APIC_irq(); | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1220 | * Level triggered interrupts can just be masked, | ||
1221 | * and shutting down and starting up the interrupt | ||
1222 | * is the same as enabling and disabling them -- except | ||
1223 | * with a startup need to return a "was pending" value. | ||
1224 | * | ||
1225 | * Level triggered interrupts are special because we | ||
1226 | * do not touch any IO-APIC register while handling | ||
1227 | * them. We ack the APIC in the end-IRQ handler, not | ||
1228 | * in the start-IRQ-handler. Protection against reentrance | ||
1229 | * from the same interrupt is still provided, both by the | ||
1230 | * generic IRQ layer and by the fact that an unacked local | ||
1231 | * APIC does not accept IRQs. | ||
1232 | */ | ||
1233 | static unsigned int startup_level_ioapic_irq (unsigned int irq) | ||
1234 | { | ||
1235 | unmask_IO_APIC_irq(irq); | ||
1236 | |||
1237 | return 0; /* don't check for pending */ | ||
1238 | } | ||
1239 | |||
1240 | static void end_level_ioapic_irq (unsigned int irq) | ||
1241 | { | ||
1242 | move_irq(irq); | ||
1243 | ack_APIC_irq(); | ||
1244 | } | ||
1245 | |||
1246 | #ifdef CONFIG_PCI_MSI | ||
1247 | static unsigned int startup_edge_ioapic_vector(unsigned int vector) | ||
1248 | { | 1208 | { |
1249 | int irq = vector_to_irq(vector); | 1209 | int irq = vector_to_irq(vector); |
1250 | 1210 | ||
1251 | return startup_edge_ioapic_irq(irq); | 1211 | return startup_ioapic_irq(irq); |
1252 | } | 1212 | } |
1253 | 1213 | ||
1254 | static void ack_edge_ioapic_vector(unsigned int vector) | 1214 | static void mask_ioapic_vector (unsigned int vector) |
1255 | { | ||
1256 | int irq = vector_to_irq(vector); | ||
1257 | |||
1258 | move_native_irq(vector); | ||
1259 | ack_edge_ioapic_irq(irq); | ||
1260 | } | ||
1261 | |||
1262 | static unsigned int startup_level_ioapic_vector (unsigned int vector) | ||
1263 | { | ||
1264 | int irq = vector_to_irq(vector); | ||
1265 | |||
1266 | return startup_level_ioapic_irq (irq); | ||
1267 | } | ||
1268 | |||
1269 | static void end_level_ioapic_vector (unsigned int vector) | ||
1270 | { | ||
1271 | int irq = vector_to_irq(vector); | ||
1272 | |||
1273 | move_native_irq(vector); | ||
1274 | end_level_ioapic_irq(irq); | ||
1275 | } | ||
1276 | |||
1277 | static void mask_IO_APIC_vector (unsigned int vector) | ||
1278 | { | 1215 | { |
1279 | int irq = vector_to_irq(vector); | 1216 | int irq = vector_to_irq(vector); |
1280 | 1217 | ||
1281 | mask_IO_APIC_irq(irq); | 1218 | mask_IO_APIC_irq(irq); |
1282 | } | 1219 | } |
1283 | 1220 | ||
1284 | static void unmask_IO_APIC_vector (unsigned int vector) | 1221 | static void unmask_ioapic_vector (unsigned int vector) |
1285 | { | 1222 | { |
1286 | int irq = vector_to_irq(vector); | 1223 | int irq = vector_to_irq(vector); |
1287 | 1224 | ||
@@ -1298,10 +1235,11 @@ static void set_ioapic_affinity_vector (unsigned int vector, | |||
1298 | set_ioapic_affinity_irq(irq, cpu_mask); | 1235 | set_ioapic_affinity_irq(irq, cpu_mask); |
1299 | } | 1236 | } |
1300 | #endif // CONFIG_SMP | 1237 | #endif // CONFIG_SMP |
1301 | #endif // CONFIG_PCI_MSI | ||
1302 | 1238 | ||
1303 | static int ioapic_retrigger(unsigned int irq) | 1239 | static int ioapic_retrigger_vector(unsigned int vector) |
1304 | { | 1240 | { |
1241 | int irq = vector_to_irq(vector); | ||
1242 | |||
1305 | send_IPI_self(IO_APIC_VECTOR(irq)); | 1243 | send_IPI_self(IO_APIC_VECTOR(irq)); |
1306 | 1244 | ||
1307 | return 1; | 1245 | return 1; |
@@ -1316,32 +1254,22 @@ static int ioapic_retrigger(unsigned int irq) | |||
1316 | * races. | 1254 | * races. |
1317 | */ | 1255 | */ |
1318 | 1256 | ||
1319 | static struct hw_interrupt_type ioapic_edge_type __read_mostly = { | 1257 | static void ack_apic(unsigned int vector) |
1320 | .typename = "IO-APIC-edge", | 1258 | { |
1321 | .startup = startup_edge_ioapic, | 1259 | ack_APIC_irq(); |
1322 | .shutdown = shutdown_edge_ioapic, | 1260 | } |
1323 | .enable = enable_edge_ioapic, | ||
1324 | .disable = disable_edge_ioapic, | ||
1325 | .ack = ack_edge_ioapic, | ||
1326 | .end = end_edge_ioapic, | ||
1327 | #ifdef CONFIG_SMP | ||
1328 | .set_affinity = set_ioapic_affinity, | ||
1329 | #endif | ||
1330 | .retrigger = ioapic_retrigger, | ||
1331 | }; | ||
1332 | 1261 | ||
1333 | static struct hw_interrupt_type ioapic_level_type __read_mostly = { | 1262 | static struct irq_chip ioapic_chip __read_mostly = { |
1334 | .typename = "IO-APIC-level", | 1263 | .name = "IO-APIC", |
1335 | .startup = startup_level_ioapic, | 1264 | .startup = startup_ioapic_vector, |
1336 | .shutdown = shutdown_level_ioapic, | 1265 | .mask = mask_ioapic_vector, |
1337 | .enable = enable_level_ioapic, | 1266 | .unmask = unmask_ioapic_vector, |
1338 | .disable = disable_level_ioapic, | 1267 | .ack = ack_apic, |
1339 | .ack = mask_and_ack_level_ioapic, | 1268 | .eoi = ack_apic, |
1340 | .end = end_level_ioapic, | ||
1341 | #ifdef CONFIG_SMP | 1269 | #ifdef CONFIG_SMP |
1342 | .set_affinity = set_ioapic_affinity, | 1270 | .set_affinity = set_ioapic_affinity_vector, |
1343 | #endif | 1271 | #endif |
1344 | .retrigger = ioapic_retrigger, | 1272 | .retrigger = ioapic_retrigger_vector, |
1345 | }; | 1273 | }; |
1346 | 1274 | ||
1347 | static inline void init_IO_APIC_traps(void) | 1275 | static inline void init_IO_APIC_traps(void) |
@@ -1376,7 +1304,7 @@ static inline void init_IO_APIC_traps(void) | |||
1376 | make_8259A_irq(irq); | 1304 | make_8259A_irq(irq); |
1377 | else | 1305 | else |
1378 | /* Strange. Oh, well.. */ | 1306 | /* Strange. Oh, well.. */ |
1379 | irq_desc[irq].chip = &no_irq_type; | 1307 | irq_desc[irq].chip = &no_irq_chip; |
1380 | } | 1308 | } |
1381 | } | 1309 | } |
1382 | } | 1310 | } |
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index b3677e6ccc6e..609f97153b88 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c | |||
@@ -74,7 +74,8 @@ int show_interrupts(struct seq_file *p, void *v) | |||
74 | for_each_online_cpu(j) | 74 | for_each_online_cpu(j) |
75 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 75 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
76 | #endif | 76 | #endif |
77 | seq_printf(p, " %14s", irq_desc[i].chip->typename); | 77 | seq_printf(p, " %8s", irq_desc[i].chip->name); |
78 | seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); | ||
78 | 79 | ||
79 | seq_printf(p, " %s", action->name); | 80 | seq_printf(p, " %s", action->name); |
80 | for (action=action->next; action; action = action->next) | 81 | for (action=action->next; action; action = action->next) |
@@ -117,7 +118,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) | |||
117 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 118 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
118 | stack_overflow_check(regs); | 119 | stack_overflow_check(regs); |
119 | #endif | 120 | #endif |
120 | __do_IRQ(irq, regs); | 121 | generic_handle_irq(irq, regs); |
121 | irq_exit(); | 122 | irq_exit(); |
122 | 123 | ||
123 | return 1; | 124 | return 1; |
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 48a4a5364e85..f5da94af9c41 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h | |||
@@ -19,8 +19,6 @@ | |||
19 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
20 | #include <linux/profile.h> | 20 | #include <linux/profile.h> |
21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
22 | |||
23 | struct hw_interrupt_type; | ||
24 | #endif | 22 | #endif |
25 | 23 | ||
26 | #define NMI_VECTOR 0x02 | 24 | #define NMI_VECTOR 0x02 |