diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-01 13:02:50 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-01 13:02:50 -0400 |
commit | 4420471f14b79f2a42e4603be7794ea49b68bca4 (patch) | |
tree | d391d25458bc0aa86dcf2823fd6c1464883b0533 /arch/x86/kernel/apic/io_apic.c | |
parent | 15e957d08dd4a841359cfec59ecb74041e0097aa (diff) | |
parent | e0e42142bab96404de535cceb85d6533d5ad7942 (diff) |
Merge branch 'x86/apic' into irq/numa
Conflicts:
arch/x86/kernel/apic/io_apic.c
Merge reason: non-trivial interaction between ongoing work in io_apic.c
and the NUMA migration feature in the irq tree.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 341 |
1 files changed, 150 insertions, 191 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e583291fe6c3..21c30e1121ee 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -489,121 +489,6 @@ static void ioapic_mask_entry(int apic, int pin) | |||
489 | spin_unlock_irqrestore(&ioapic_lock, flags); | 489 | spin_unlock_irqrestore(&ioapic_lock, flags); |
490 | } | 490 | } |
491 | 491 | ||
492 | #ifdef CONFIG_SMP | ||
493 | static void send_cleanup_vector(struct irq_cfg *cfg) | ||
494 | { | ||
495 | cpumask_var_t cleanup_mask; | ||
496 | |||
497 | if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { | ||
498 | unsigned int i; | ||
499 | cfg->move_cleanup_count = 0; | ||
500 | for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) | ||
501 | cfg->move_cleanup_count++; | ||
502 | for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) | ||
503 | apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR); | ||
504 | } else { | ||
505 | cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask); | ||
506 | cfg->move_cleanup_count = cpumask_weight(cleanup_mask); | ||
507 | apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); | ||
508 | free_cpumask_var(cleanup_mask); | ||
509 | } | ||
510 | cfg->move_in_progress = 0; | ||
511 | } | ||
512 | |||
513 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) | ||
514 | { | ||
515 | int apic, pin; | ||
516 | struct irq_pin_list *entry; | ||
517 | u8 vector = cfg->vector; | ||
518 | |||
519 | entry = cfg->irq_2_pin; | ||
520 | for (;;) { | ||
521 | unsigned int reg; | ||
522 | |||
523 | if (!entry) | ||
524 | break; | ||
525 | |||
526 | apic = entry->apic; | ||
527 | pin = entry->pin; | ||
528 | /* | ||
529 | * With interrupt-remapping, destination information comes | ||
530 | * from interrupt-remapping table entry. | ||
531 | */ | ||
532 | if (!irq_remapped(irq)) | ||
533 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
534 | reg = io_apic_read(apic, 0x10 + pin*2); | ||
535 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; | ||
536 | reg |= vector; | ||
537 | io_apic_modify(apic, 0x10 + pin*2, reg); | ||
538 | if (!entry->next) | ||
539 | break; | ||
540 | entry = entry->next; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | static int | ||
545 | assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask); | ||
546 | |||
547 | /* | ||
548 | * Either sets desc->affinity to a valid value, and returns | ||
549 | * ->cpu_mask_to_apicid of that, or returns BAD_APICID and | ||
550 | * leaves desc->affinity untouched. | ||
551 | */ | ||
552 | static unsigned int | ||
553 | set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask) | ||
554 | { | ||
555 | struct irq_cfg *cfg; | ||
556 | unsigned int irq; | ||
557 | |||
558 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
559 | return BAD_APICID; | ||
560 | |||
561 | irq = desc->irq; | ||
562 | cfg = desc->chip_data; | ||
563 | if (assign_irq_vector(irq, cfg, mask)) | ||
564 | return BAD_APICID; | ||
565 | |||
566 | cpumask_copy(desc->affinity, mask); | ||
567 | |||
568 | return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain); | ||
569 | } | ||
570 | |||
571 | static int | ||
572 | set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) | ||
573 | { | ||
574 | struct irq_cfg *cfg; | ||
575 | unsigned long flags; | ||
576 | unsigned int dest; | ||
577 | unsigned int irq; | ||
578 | int ret = -1; | ||
579 | |||
580 | irq = desc->irq; | ||
581 | cfg = desc->chip_data; | ||
582 | |||
583 | spin_lock_irqsave(&ioapic_lock, flags); | ||
584 | dest = set_desc_affinity(desc, mask); | ||
585 | if (dest != BAD_APICID) { | ||
586 | /* Only the high 8 bits are valid. */ | ||
587 | dest = SET_APIC_LOGICAL_ID(dest); | ||
588 | __target_IO_APIC_irq(irq, dest, cfg); | ||
589 | ret = 0; | ||
590 | } | ||
591 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
592 | |||
593 | return ret; | ||
594 | } | ||
595 | |||
596 | static int | ||
597 | set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask) | ||
598 | { | ||
599 | struct irq_desc *desc; | ||
600 | |||
601 | desc = irq_to_desc(irq); | ||
602 | |||
603 | return set_ioapic_affinity_irq_desc(desc, mask); | ||
604 | } | ||
605 | #endif /* CONFIG_SMP */ | ||
606 | |||
607 | /* | 492 | /* |
608 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are | 493 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are |
609 | * shared ISA-space IRQs, so we have to support them. We are super | 494 | * shared ISA-space IRQs, so we have to support them. We are super |
@@ -822,7 +707,6 @@ static int __init ioapic_pirq_setup(char *str) | |||
822 | __setup("pirq=", ioapic_pirq_setup); | 707 | __setup("pirq=", ioapic_pirq_setup); |
823 | #endif /* CONFIG_X86_32 */ | 708 | #endif /* CONFIG_X86_32 */ |
824 | 709 | ||
825 | #ifdef CONFIG_INTR_REMAP | ||
826 | struct IO_APIC_route_entry **alloc_ioapic_entries(void) | 710 | struct IO_APIC_route_entry **alloc_ioapic_entries(void) |
827 | { | 711 | { |
828 | int apic; | 712 | int apic; |
@@ -920,20 +804,6 @@ int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries) | |||
920 | return 0; | 804 | return 0; |
921 | } | 805 | } |
922 | 806 | ||
923 | void reinit_intr_remapped_IO_APIC(int intr_remapping, | ||
924 | struct IO_APIC_route_entry **ioapic_entries) | ||
925 | |||
926 | { | ||
927 | /* | ||
928 | * for now plain restore of previous settings. | ||
929 | * TBD: In the case of OS enabling interrupt-remapping, | ||
930 | * IO-APIC RTE's need to be setup to point to interrupt-remapping | ||
931 | * table entries. for now, do a plain restore, and wait for | ||
932 | * the setup_IO_APIC_irqs() to do proper initialization. | ||
933 | */ | ||
934 | restore_IO_APIC_setup(ioapic_entries); | ||
935 | } | ||
936 | |||
937 | void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries) | 807 | void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries) |
938 | { | 808 | { |
939 | int apic; | 809 | int apic; |
@@ -943,7 +813,6 @@ void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries) | |||
943 | 813 | ||
944 | kfree(ioapic_entries); | 814 | kfree(ioapic_entries); |
945 | } | 815 | } |
946 | #endif | ||
947 | 816 | ||
948 | /* | 817 | /* |
949 | * Find the IRQ entry number of a certain pin. | 818 | * Find the IRQ entry number of a certain pin. |
@@ -2332,6 +2201,118 @@ static int ioapic_retrigger_irq(unsigned int irq) | |||
2332 | */ | 2201 | */ |
2333 | 2202 | ||
2334 | #ifdef CONFIG_SMP | 2203 | #ifdef CONFIG_SMP |
2204 | static void send_cleanup_vector(struct irq_cfg *cfg) | ||
2205 | { | ||
2206 | cpumask_var_t cleanup_mask; | ||
2207 | |||
2208 | if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { | ||
2209 | unsigned int i; | ||
2210 | cfg->move_cleanup_count = 0; | ||
2211 | for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) | ||
2212 | cfg->move_cleanup_count++; | ||
2213 | for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) | ||
2214 | apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR); | ||
2215 | } else { | ||
2216 | cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask); | ||
2217 | cfg->move_cleanup_count = cpumask_weight(cleanup_mask); | ||
2218 | apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); | ||
2219 | free_cpumask_var(cleanup_mask); | ||
2220 | } | ||
2221 | cfg->move_in_progress = 0; | ||
2222 | } | ||
2223 | |||
2224 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) | ||
2225 | { | ||
2226 | int apic, pin; | ||
2227 | struct irq_pin_list *entry; | ||
2228 | u8 vector = cfg->vector; | ||
2229 | |||
2230 | entry = cfg->irq_2_pin; | ||
2231 | for (;;) { | ||
2232 | unsigned int reg; | ||
2233 | |||
2234 | if (!entry) | ||
2235 | break; | ||
2236 | |||
2237 | apic = entry->apic; | ||
2238 | pin = entry->pin; | ||
2239 | /* | ||
2240 | * With interrupt-remapping, destination information comes | ||
2241 | * from interrupt-remapping table entry. | ||
2242 | */ | ||
2243 | if (!irq_remapped(irq)) | ||
2244 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
2245 | reg = io_apic_read(apic, 0x10 + pin*2); | ||
2246 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; | ||
2247 | reg |= vector; | ||
2248 | io_apic_modify(apic, 0x10 + pin*2, reg); | ||
2249 | if (!entry->next) | ||
2250 | break; | ||
2251 | entry = entry->next; | ||
2252 | } | ||
2253 | } | ||
2254 | |||
2255 | static int | ||
2256 | assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask); | ||
2257 | |||
2258 | /* | ||
2259 | * Either sets desc->affinity to a valid value, and returns | ||
2260 | * ->cpu_mask_to_apicid of that, or returns BAD_APICID and | ||
2261 | * leaves desc->affinity untouched. | ||
2262 | */ | ||
2263 | static unsigned int | ||
2264 | set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask) | ||
2265 | { | ||
2266 | struct irq_cfg *cfg; | ||
2267 | unsigned int irq; | ||
2268 | |||
2269 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
2270 | return BAD_APICID; | ||
2271 | |||
2272 | irq = desc->irq; | ||
2273 | cfg = desc->chip_data; | ||
2274 | if (assign_irq_vector(irq, cfg, mask)) | ||
2275 | return BAD_APICID; | ||
2276 | |||
2277 | cpumask_copy(desc->affinity, mask); | ||
2278 | |||
2279 | return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain); | ||
2280 | } | ||
2281 | |||
2282 | static int | ||
2283 | set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) | ||
2284 | { | ||
2285 | struct irq_cfg *cfg; | ||
2286 | unsigned long flags; | ||
2287 | unsigned int dest; | ||
2288 | unsigned int irq; | ||
2289 | int ret = -1; | ||
2290 | |||
2291 | irq = desc->irq; | ||
2292 | cfg = desc->chip_data; | ||
2293 | |||
2294 | spin_lock_irqsave(&ioapic_lock, flags); | ||
2295 | dest = set_desc_affinity(desc, mask); | ||
2296 | if (dest != BAD_APICID) { | ||
2297 | /* Only the high 8 bits are valid. */ | ||
2298 | dest = SET_APIC_LOGICAL_ID(dest); | ||
2299 | __target_IO_APIC_irq(irq, dest, cfg); | ||
2300 | ret = 0; | ||
2301 | } | ||
2302 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2303 | |||
2304 | return ret; | ||
2305 | } | ||
2306 | |||
2307 | static int | ||
2308 | set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask) | ||
2309 | { | ||
2310 | struct irq_desc *desc; | ||
2311 | |||
2312 | desc = irq_to_desc(irq); | ||
2313 | |||
2314 | return set_ioapic_affinity_irq_desc(desc, mask); | ||
2315 | } | ||
2335 | 2316 | ||
2336 | #ifdef CONFIG_INTR_REMAP | 2317 | #ifdef CONFIG_INTR_REMAP |
2337 | 2318 | ||
@@ -2478,53 +2459,6 @@ static void irq_complete_move(struct irq_desc **descp) | |||
2478 | static inline void irq_complete_move(struct irq_desc **descp) {} | 2459 | static inline void irq_complete_move(struct irq_desc **descp) {} |
2479 | #endif | 2460 | #endif |
2480 | 2461 | ||
2481 | static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) | ||
2482 | { | ||
2483 | int apic, pin; | ||
2484 | struct irq_pin_list *entry; | ||
2485 | |||
2486 | entry = cfg->irq_2_pin; | ||
2487 | for (;;) { | ||
2488 | |||
2489 | if (!entry) | ||
2490 | break; | ||
2491 | |||
2492 | apic = entry->apic; | ||
2493 | pin = entry->pin; | ||
2494 | io_apic_eoi(apic, pin); | ||
2495 | entry = entry->next; | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2499 | static void | ||
2500 | eoi_ioapic_irq(struct irq_desc *desc) | ||
2501 | { | ||
2502 | struct irq_cfg *cfg; | ||
2503 | unsigned long flags; | ||
2504 | unsigned int irq; | ||
2505 | |||
2506 | irq = desc->irq; | ||
2507 | cfg = desc->chip_data; | ||
2508 | |||
2509 | spin_lock_irqsave(&ioapic_lock, flags); | ||
2510 | __eoi_ioapic_irq(irq, cfg); | ||
2511 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2512 | } | ||
2513 | |||
2514 | #ifdef CONFIG_X86_X2APIC | ||
2515 | static void ack_x2apic_level(unsigned int irq) | ||
2516 | { | ||
2517 | struct irq_desc *desc = irq_to_desc(irq); | ||
2518 | ack_x2APIC_irq(); | ||
2519 | eoi_ioapic_irq(desc); | ||
2520 | } | ||
2521 | |||
2522 | static void ack_x2apic_edge(unsigned int irq) | ||
2523 | { | ||
2524 | ack_x2APIC_irq(); | ||
2525 | } | ||
2526 | #endif | ||
2527 | |||
2528 | static void ack_apic_edge(unsigned int irq) | 2462 | static void ack_apic_edge(unsigned int irq) |
2529 | { | 2463 | { |
2530 | struct irq_desc *desc = irq_to_desc(irq); | 2464 | struct irq_desc *desc = irq_to_desc(irq); |
@@ -2588,9 +2522,6 @@ static void ack_apic_level(unsigned int irq) | |||
2588 | */ | 2522 | */ |
2589 | ack_APIC_irq(); | 2523 | ack_APIC_irq(); |
2590 | 2524 | ||
2591 | if (irq_remapped(irq)) | ||
2592 | eoi_ioapic_irq(desc); | ||
2593 | |||
2594 | /* Now we can move and renable the irq */ | 2525 | /* Now we can move and renable the irq */ |
2595 | if (unlikely(do_unmask_irq)) { | 2526 | if (unlikely(do_unmask_irq)) { |
2596 | /* Only migrate the irq if the ack has been received. | 2527 | /* Only migrate the irq if the ack has been received. |
@@ -2637,22 +2568,50 @@ static void ack_apic_level(unsigned int irq) | |||
2637 | } | 2568 | } |
2638 | 2569 | ||
2639 | #ifdef CONFIG_INTR_REMAP | 2570 | #ifdef CONFIG_INTR_REMAP |
2571 | static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) | ||
2572 | { | ||
2573 | int apic, pin; | ||
2574 | struct irq_pin_list *entry; | ||
2575 | |||
2576 | entry = cfg->irq_2_pin; | ||
2577 | for (;;) { | ||
2578 | |||
2579 | if (!entry) | ||
2580 | break; | ||
2581 | |||
2582 | apic = entry->apic; | ||
2583 | pin = entry->pin; | ||
2584 | io_apic_eoi(apic, pin); | ||
2585 | entry = entry->next; | ||
2586 | } | ||
2587 | } | ||
2588 | |||
2589 | static void | ||
2590 | eoi_ioapic_irq(struct irq_desc *desc) | ||
2591 | { | ||
2592 | struct irq_cfg *cfg; | ||
2593 | unsigned long flags; | ||
2594 | unsigned int irq; | ||
2595 | |||
2596 | irq = desc->irq; | ||
2597 | cfg = desc->chip_data; | ||
2598 | |||
2599 | spin_lock_irqsave(&ioapic_lock, flags); | ||
2600 | __eoi_ioapic_irq(irq, cfg); | ||
2601 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2602 | } | ||
2603 | |||
2640 | static void ir_ack_apic_edge(unsigned int irq) | 2604 | static void ir_ack_apic_edge(unsigned int irq) |
2641 | { | 2605 | { |
2642 | #ifdef CONFIG_X86_X2APIC | 2606 | ack_APIC_irq(); |
2643 | if (x2apic_enabled()) | ||
2644 | return ack_x2apic_edge(irq); | ||
2645 | #endif | ||
2646 | return ack_apic_edge(irq); | ||
2647 | } | 2607 | } |
2648 | 2608 | ||
2649 | static void ir_ack_apic_level(unsigned int irq) | 2609 | static void ir_ack_apic_level(unsigned int irq) |
2650 | { | 2610 | { |
2651 | #ifdef CONFIG_X86_X2APIC | 2611 | struct irq_desc *desc = irq_to_desc(irq); |
2652 | if (x2apic_enabled()) | 2612 | |
2653 | return ack_x2apic_level(irq); | 2613 | ack_APIC_irq(); |
2654 | #endif | 2614 | eoi_ioapic_irq(desc); |
2655 | return ack_apic_level(irq); | ||
2656 | } | 2615 | } |
2657 | #endif /* CONFIG_INTR_REMAP */ | 2616 | #endif /* CONFIG_INTR_REMAP */ |
2658 | 2617 | ||