diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:41 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:55 -0400 |
commit | 047c8fdb8718890e3340073b178d0859d0c7f91f (patch) | |
tree | 12386f7d380da5212d720d7a2d7e9ca1c64473bb /arch/x86/kernel/io_apic_32.c | |
parent | aa45f97b1bb40adae1288669e73350907ffae85e (diff) |
x86: make io_apic_64.c and io_apic_32.c the same
all the same except INTR_REMAPPING related and ioapic io resource.
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/io_apic_32.c')
-rw-r--r-- | arch/x86/kernel/io_apic_32.c | 213 |
1 files changed, 199 insertions, 14 deletions
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index 48184e126f2..3ed36041c81 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
@@ -123,7 +123,6 @@ struct irq_cfg { | |||
123 | u8 move_in_progress : 1; | 123 | u8 move_in_progress : 1; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | |||
127 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ | 126 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ |
128 | static struct irq_cfg irq_cfg_legacy[] __initdata = { | 127 | static struct irq_cfg irq_cfg_legacy[] __initdata = { |
129 | [0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, | 128 | [0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, |
@@ -391,6 +390,38 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned | |||
391 | writel(value, &io_apic->data); | 390 | writel(value, &io_apic->data); |
392 | } | 391 | } |
393 | 392 | ||
393 | #ifdef CONFIG_X86_64 | ||
394 | static bool io_apic_level_ack_pending(unsigned int irq) | ||
395 | { | ||
396 | struct irq_pin_list *entry; | ||
397 | unsigned long flags; | ||
398 | struct irq_cfg *cfg = irq_cfg(irq); | ||
399 | |||
400 | spin_lock_irqsave(&ioapic_lock, flags); | ||
401 | entry = cfg->irq_2_pin; | ||
402 | for (;;) { | ||
403 | unsigned int reg; | ||
404 | int pin; | ||
405 | |||
406 | if (!entry) | ||
407 | break; | ||
408 | pin = entry->pin; | ||
409 | reg = io_apic_read(entry->apic, 0x10 + pin*2); | ||
410 | /* Is the remote IRR bit set? */ | ||
411 | if (reg & IO_APIC_REDIR_REMOTE_IRR) { | ||
412 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
413 | return true; | ||
414 | } | ||
415 | if (!entry->next) | ||
416 | break; | ||
417 | entry = entry->next; | ||
418 | } | ||
419 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
420 | |||
421 | return false; | ||
422 | } | ||
423 | #endif | ||
424 | |||
394 | union entry_union { | 425 | union entry_union { |
395 | struct { u32 w1, w2; }; | 426 | struct { u32 w1, w2; }; |
396 | struct IO_APIC_route_entry entry; | 427 | struct IO_APIC_route_entry entry; |
@@ -483,17 +514,15 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | |||
483 | unsigned int dest; | 514 | unsigned int dest; |
484 | cpumask_t tmp; | 515 | cpumask_t tmp; |
485 | 516 | ||
486 | cfg = irq_cfg(irq); | ||
487 | |||
488 | cpus_and(tmp, mask, cpu_online_map); | 517 | cpus_and(tmp, mask, cpu_online_map); |
489 | if (cpus_empty(tmp)) | 518 | if (cpus_empty(tmp)) |
490 | return; | 519 | return; |
491 | 520 | ||
521 | cfg = irq_cfg(irq); | ||
492 | if (assign_irq_vector(irq, mask)) | 522 | if (assign_irq_vector(irq, mask)) |
493 | return; | 523 | return; |
494 | 524 | ||
495 | cpus_and(tmp, cfg->domain, mask); | 525 | cpus_and(tmp, cfg->domain, mask); |
496 | |||
497 | dest = cpu_mask_to_apicid(tmp); | 526 | dest = cpu_mask_to_apicid(tmp); |
498 | /* | 527 | /* |
499 | * Only the high 8 bits are valid. | 528 | * Only the high 8 bits are valid. |
@@ -572,6 +601,54 @@ static void __init replace_pin_at_irq(unsigned int irq, | |||
572 | add_pin_to_irq(irq, newapic, newpin); | 601 | add_pin_to_irq(irq, newapic, newpin); |
573 | } | 602 | } |
574 | 603 | ||
604 | #ifdef CONFIG_X86_64 | ||
605 | /* | ||
606 | * Synchronize the IO-APIC and the CPU by doing | ||
607 | * a dummy read from the IO-APIC | ||
608 | */ | ||
609 | static inline void io_apic_sync(unsigned int apic) | ||
610 | { | ||
611 | struct io_apic __iomem *io_apic = io_apic_base(apic); | ||
612 | readl(&io_apic->data); | ||
613 | } | ||
614 | |||
615 | #define __DO_ACTION(R, ACTION, FINAL) \ | ||
616 | \ | ||
617 | { \ | ||
618 | int pin; \ | ||
619 | struct irq_cfg *cfg; \ | ||
620 | struct irq_pin_list *entry; \ | ||
621 | \ | ||
622 | cfg = irq_cfg(irq); \ | ||
623 | entry = cfg->irq_2_pin; \ | ||
624 | for (;;) { \ | ||
625 | unsigned int reg; \ | ||
626 | if (!entry) \ | ||
627 | break; \ | ||
628 | pin = entry->pin; \ | ||
629 | reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ | ||
630 | reg ACTION; \ | ||
631 | io_apic_modify(entry->apic, 0x10 + R + pin*2, reg); \ | ||
632 | FINAL; \ | ||
633 | if (!entry->next) \ | ||
634 | break; \ | ||
635 | entry = entry->next; \ | ||
636 | } \ | ||
637 | } | ||
638 | |||
639 | #define DO_ACTION(name,R,ACTION, FINAL) \ | ||
640 | \ | ||
641 | static void name##_IO_APIC_irq (unsigned int irq) \ | ||
642 | __DO_ACTION(R, ACTION, FINAL) | ||
643 | |||
644 | /* mask = 1 */ | ||
645 | DO_ACTION(__mask, 0, |= IO_APIC_REDIR_MASKED, io_apic_sync(entry->apic)) | ||
646 | |||
647 | /* mask = 0 */ | ||
648 | DO_ACTION(__unmask, 0, &= ~IO_APIC_REDIR_MASKED, ) | ||
649 | |||
650 | #else | ||
651 | |||
575 | static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable) | 652 | static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable) |
576 | { | 653 | { |
577 | struct irq_cfg *cfg; | 654 | struct irq_cfg *cfg; |
@@ -620,6 +697,8 @@ static void __unmask_and_level_IO_APIC_irq(unsigned int irq) | |||
620 | IO_APIC_REDIR_MASKED); | 697 | IO_APIC_REDIR_MASKED); |
621 | } | 698 | } |
622 | 699 | ||
700 | #endif | ||
701 | |||
623 | static void mask_IO_APIC_irq(unsigned int irq) | 702 | static void mask_IO_APIC_irq(unsigned int irq) |
624 | { | 703 | { |
625 | unsigned long flags; | 704 | unsigned long flags; |
@@ -1055,6 +1134,17 @@ void unlock_vector_lock(void) | |||
1055 | 1134 | ||
1056 | static int __assign_irq_vector(int irq, cpumask_t mask) | 1135 | static int __assign_irq_vector(int irq, cpumask_t mask) |
1057 | { | 1136 | { |
1137 | /* | ||
1138 | * NOTE! The local APIC isn't very good at handling | ||
1139 | * multiple interrupts at the same interrupt level. | ||
1140 | * As the interrupt level is determined by taking the | ||
1141 | * vector number and shifting that right by 4, we | ||
1142 | * want to spread these out a bit so that they don't | ||
1143 | * all fall in the same interrupt level. | ||
1144 | * | ||
1145 | * Also, we've got to be careful not to trash gate | ||
1146 | * 0x80, because int 0x80 is hm, kind of importantish. ;) | ||
1147 | */ | ||
1058 | static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0; | 1148 | static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0; |
1059 | unsigned int old_vector; | 1149 | unsigned int old_vector; |
1060 | int cpu; | 1150 | int cpu; |
@@ -1095,9 +1185,13 @@ next: | |||
1095 | } | 1185 | } |
1096 | if (unlikely(current_vector == vector)) | 1186 | if (unlikely(current_vector == vector)) |
1097 | continue; | 1187 | continue; |
1098 | if (vector == SYSCALL_VECTOR) | 1188 | #ifdef CONFIG_X86_64 |
1189 | if (vector == IA32_SYSCALL_VECTOR) | ||
1099 | goto next; | 1190 | goto next; |
1100 | 1191 | #else | |
1192 | if (vector == SYSCALL_VECTOR) | ||
1193 | goto next; | ||
1194 | #endif | ||
1101 | for_each_cpu_mask_nr(new_cpu, new_mask) | 1195 | for_each_cpu_mask_nr(new_cpu, new_mask) |
1102 | if (per_cpu(vector_irq, new_cpu)[vector] != -1) | 1196 | if (per_cpu(vector_irq, new_cpu)[vector] != -1) |
1103 | goto next; | 1197 | goto next; |
@@ -1184,6 +1278,7 @@ static struct irq_chip ioapic_chip; | |||
1184 | #define IOAPIC_EDGE 0 | 1278 | #define IOAPIC_EDGE 0 |
1185 | #define IOAPIC_LEVEL 1 | 1279 | #define IOAPIC_LEVEL 1 |
1186 | 1280 | ||
1281 | #ifdef CONFIG_X86_32 | ||
1187 | static inline int IO_APIC_irq_trigger(int irq) | 1282 | static inline int IO_APIC_irq_trigger(int irq) |
1188 | { | 1283 | { |
1189 | int apic, idx, pin; | 1284 | int apic, idx, pin; |
@@ -1200,6 +1295,12 @@ static inline int IO_APIC_irq_trigger(int irq) | |||
1200 | */ | 1295 | */ |
1201 | return 0; | 1296 | return 0; |
1202 | } | 1297 | } |
1298 | #else | ||
1299 | static inline int IO_APIC_irq_trigger(int irq) | ||
1300 | { | ||
1301 | return 1; | ||
1302 | } | ||
1303 | #endif | ||
1203 | 1304 | ||
1204 | static void ioapic_register_intr(int irq, unsigned long trigger) | 1305 | static void ioapic_register_intr(int irq, unsigned long trigger) |
1205 | { | 1306 | { |
@@ -1212,15 +1313,18 @@ static void ioapic_register_intr(int irq, unsigned long trigger) | |||
1212 | desc = irq_to_desc_alloc(irq); | 1313 | desc = irq_to_desc_alloc(irq); |
1213 | 1314 | ||
1214 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || | 1315 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || |
1215 | trigger == IOAPIC_LEVEL) { | 1316 | trigger == IOAPIC_LEVEL) |
1216 | desc->status |= IRQ_LEVEL; | 1317 | desc->status |= IRQ_LEVEL; |
1318 | else | ||
1319 | desc->status &= ~IRQ_LEVEL; | ||
1320 | |||
1321 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || | ||
1322 | trigger == IOAPIC_LEVEL) | ||
1217 | set_irq_chip_and_handler_name(irq, &ioapic_chip, | 1323 | set_irq_chip_and_handler_name(irq, &ioapic_chip, |
1218 | handle_fasteoi_irq, "fasteoi"); | 1324 | handle_fasteoi_irq, "fasteoi"); |
1219 | } else { | 1325 | else |
1220 | desc->status &= ~IRQ_LEVEL; | ||
1221 | set_irq_chip_and_handler_name(irq, &ioapic_chip, | 1326 | set_irq_chip_and_handler_name(irq, &ioapic_chip, |
1222 | handle_edge_irq, "edge"); | 1327 | handle_edge_irq, "edge"); |
1223 | } | ||
1224 | } | 1328 | } |
1225 | 1329 | ||
1226 | static int setup_ioapic_entry(int apic, int irq, | 1330 | static int setup_ioapic_entry(int apic, int irq, |
@@ -1662,7 +1766,6 @@ static void __init enable_IO_APIC(void) | |||
1662 | struct IO_APIC_route_entry entry; | 1766 | struct IO_APIC_route_entry entry; |
1663 | entry = ioapic_read_entry(apic, pin); | 1767 | entry = ioapic_read_entry(apic, pin); |
1664 | 1768 | ||
1665 | |||
1666 | /* If the interrupt line is enabled and in ExtInt mode | 1769 | /* If the interrupt line is enabled and in ExtInt mode |
1667 | * I have found the pin where the i8259 is connected. | 1770 | * I have found the pin where the i8259 is connected. |
1668 | */ | 1771 | */ |
@@ -2012,6 +2115,60 @@ static void ack_apic_edge(unsigned int irq) | |||
2012 | ack_APIC_irq(); | 2115 | ack_APIC_irq(); |
2013 | } | 2116 | } |
2014 | 2117 | ||
2118 | #ifdef CONFIG_X86_64 | ||
2119 | static void ack_apic_level(unsigned int irq) | ||
2120 | { | ||
2121 | int do_unmask_irq = 0; | ||
2122 | |||
2123 | irq_complete_move(irq); | ||
2124 | #ifdef CONFIG_GENERIC_PENDING_IRQ | ||
2125 | /* If we are moving the irq we need to mask it */ | ||
2126 | if (unlikely(desc->status & IRQ_MOVE_PENDING)) { | ||
2127 | do_unmask_irq = 1; | ||
2128 | mask_IO_APIC_irq(irq); | ||
2129 | } | ||
2130 | #endif | ||
2131 | |||
2132 | /* | ||
2133 | * We must acknowledge the irq before we move it or the acknowledge will | ||
2134 | * not propagate properly. | ||
2135 | */ | ||
2136 | ack_APIC_irq(); | ||
2137 | |||
2138 | /* Now we can move and renable the irq */ | ||
2139 | if (unlikely(do_unmask_irq)) { | ||
2140 | /* Only migrate the irq if the ack has been received. | ||
2141 | * | ||
2142 | * On rare occasions the broadcast level triggered ack gets | ||
2143 | * delayed going to ioapics, and if we reprogram the | ||
2144 | * vector while Remote IRR is still set the irq will never | ||
2145 | * fire again. | ||
2146 | * | ||
2147 | * To prevent this scenario we read the Remote IRR bit | ||
2148 | * of the ioapic. This has two effects. | ||
2149 | * - On any sane system the read of the ioapic will | ||
2150 | * flush writes (and acks) going to the ioapic from | ||
2151 | * this cpu. | ||
2152 | * - We get to see if the ACK has actually been delivered. | ||
2153 | * | ||
2154 | * Based on failed experiments of reprogramming the | ||
2155 | * ioapic entry from outside of irq context starting | ||
2156 | * with masking the ioapic entry and then polling until | ||
2157 | * Remote IRR was clear before reprogramming the | ||
2158 | * ioapic I don't trust the Remote IRR bit to be | ||
2159 | * completey accurate. | ||
2160 | * | ||
2161 | * However there appears to be no other way to plug | ||
2162 | * this race, so if the Remote IRR bit is not | ||
2163 | * accurate and is causing problems then it is a hardware bug | ||
2164 | * and you can go talk to the chipset vendor about it. | ||
2165 | */ | ||
2166 | if (!io_apic_level_ack_pending(irq)) | ||
2167 | move_masked_irq(irq, desc); | ||
2168 | unmask_IO_APIC_irq(irq); | ||
2169 | } | ||
2170 | } | ||
2171 | #else | ||
2015 | atomic_t irq_mis_count; | 2172 | atomic_t irq_mis_count; |
2016 | static void ack_apic_level(unsigned int irq) | 2173 | static void ack_apic_level(unsigned int irq) |
2017 | { | 2174 | { |
@@ -2053,6 +2210,7 @@ static void ack_apic_level(unsigned int irq) | |||
2053 | spin_unlock(&ioapic_lock); | 2210 | spin_unlock(&ioapic_lock); |
2054 | } | 2211 | } |
2055 | } | 2212 | } |
2213 | #endif | ||
2056 | 2214 | ||
2057 | static struct irq_chip ioapic_chip __read_mostly = { | 2215 | static struct irq_chip ioapic_chip __read_mostly = { |
2058 | .name = "IO-APIC", | 2216 | .name = "IO-APIC", |
@@ -2224,7 +2382,7 @@ static inline void __init unlock_ExtINT_logic(void) | |||
2224 | } | 2382 | } |
2225 | 2383 | ||
2226 | static int disable_timer_pin_1 __initdata; | 2384 | static int disable_timer_pin_1 __initdata; |
2227 | 2385 | /* Actually the next is obsolete, but keep it for paranoid reasons -AK */ | |
2228 | static int __init parse_disable_timer_pin_1(char *arg) | 2386 | static int __init parse_disable_timer_pin_1(char *arg) |
2229 | { | 2387 | { |
2230 | disable_timer_pin_1 = 1; | 2388 | disable_timer_pin_1 = 1; |
@@ -2244,9 +2402,9 @@ static inline void __init check_timer(void) | |||
2244 | { | 2402 | { |
2245 | struct irq_cfg *cfg = irq_cfg(0); | 2403 | struct irq_cfg *cfg = irq_cfg(0); |
2246 | int apic1, pin1, apic2, pin2; | 2404 | int apic1, pin1, apic2, pin2; |
2247 | int no_pin1 = 0; | ||
2248 | unsigned int ver; | ||
2249 | unsigned long flags; | 2405 | unsigned long flags; |
2406 | unsigned int ver; | ||
2407 | int no_pin1 = 0; | ||
2250 | 2408 | ||
2251 | local_irq_save(flags); | 2409 | local_irq_save(flags); |
2252 | 2410 | ||
@@ -2550,6 +2708,7 @@ unsigned int create_irq_nr(unsigned int irq_want) | |||
2550 | cfg_new = irq_cfg(new); | 2708 | cfg_new = irq_cfg(new); |
2551 | if (cfg_new && cfg_new->vector != 0) | 2709 | if (cfg_new && cfg_new->vector != 0) |
2552 | continue; | 2710 | continue; |
2711 | /* check if need to create one */ | ||
2553 | if (!cfg_new) | 2712 | if (!cfg_new) |
2554 | cfg_new = irq_cfg_alloc(new); | 2713 | cfg_new = irq_cfg_alloc(new); |
2555 | if (__assign_irq_vector(new, TARGET_CPUS) == 0) | 2714 | if (__assign_irq_vector(new, TARGET_CPUS) == 0) |
@@ -2720,6 +2879,32 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | |||
2720 | return 0; | 2879 | return 0; |
2721 | } | 2880 | } |
2722 | 2881 | ||
2882 | int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
2883 | { | ||
2884 | unsigned int irq; | ||
2885 | int ret, sub_handle; | ||
2886 | struct msi_desc *desc; | ||
2887 | unsigned int irq_want; | ||
2888 | |||
2889 | irq_want = build_irq_for_pci_dev(dev) + 0x100; | ||
2890 | sub_handle = 0; | ||
2891 | list_for_each_entry(desc, &dev->msi_list, list) { | ||
2892 | irq = create_irq_nr(irq_want--); | ||
2893 | if (irq == 0) | ||
2894 | return -1; | ||
2895 | ret = setup_msi_irq(dev, desc, irq); | ||
2896 | if (ret < 0) | ||
2897 | goto error; | ||
2898 | sub_handle++; | ||
2899 | } | ||
2900 | return 0; | ||
2901 | |||
2902 | error: | ||
2903 | destroy_irq(irq); | ||
2904 | return ret; | ||
2905 | } | ||
2906 | |||
2907 | |||
2723 | void arch_teardown_msi_irq(unsigned int irq) | 2908 | void arch_teardown_msi_irq(unsigned int irq) |
2724 | { | 2909 | { |
2725 | destroy_irq(irq); | 2910 | destroy_irq(irq); |