diff options
author | Ashok Raj <ashok.raj@intel.com> | 2005-09-06 18:16:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:15 -0400 |
commit | 54d5d42404e7705cf3804593189e963350d470e5 (patch) | |
tree | 7cf8a7fce163b19672193d8cf4ef6a7f6c131d9e /arch | |
parent | f63ed39c578a2a2d067356a85ce7c28a7c795d8a (diff) |
[PATCH] x86/x86_64: deferred handling of writes to /proc/irqxx/smp_affinity
When handling writes to /proc/irq, current code is re-programming rte
entries directly. This is not recommended and could potentially cause
chipset's to lockup, or cause missing interrupts.
CONFIG_IRQ_BALANCE does this correctly, where it re-programs only when the
interrupt is pending. The same needs to be done for /proc/irq handling as well.
Otherwise user space irq balancers are really not doing the right thing.
- Changed pending_irq_balance_cpumask to pending_irq_migrate_cpumask for
lack of a generic name.
- added move_irq out of IRQ_BALANCE, and added this same to X86_64
- Added new proc handler for write, so we can do deferred write at irq
handling time.
- Display of /proc/irq/XX/smp_affinity used to display CPU_MASKALL, instead
it now shows only active cpu masks, or exactly what was set.
- Provided a common move_irq implementation, instead of duplicating
when using generic irq framework.
Tested on i386/x86_64 and ia64 with CONFIG_PCI_MSI turned on and off.
Tested UP builds as well.
MSI testing: tbd: I have cards, need to look for a x-over cable, although I
did test an earlier version of this patch. Will test in a couple days.
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Acked-by: Zwane Mwaikambo <zwane@holomorphy.com>
Grudgingly-acked-by: Andi Kleen <ak@muc.de>
Signed-off-by: Coywolf Qi Hunt <coywolf@lovecn.org>
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/Kconfig | 5 | ||||
-rw-r--r-- | arch/i386/kernel/io_apic.c | 55 | ||||
-rw-r--r-- | arch/ia64/Kconfig | 5 | ||||
-rw-r--r-- | arch/ia64/kernel/irq.c | 39 | ||||
-rw-r--r-- | arch/x86_64/Kconfig | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 102 |
6 files changed, 109 insertions, 102 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 3b3b017e1c15..4b7de3e1e57b 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
@@ -1318,6 +1318,11 @@ config GENERIC_IRQ_PROBE | |||
1318 | bool | 1318 | bool |
1319 | default y | 1319 | default y |
1320 | 1320 | ||
1321 | config GENERIC_PENDING_IRQ | ||
1322 | bool | ||
1323 | depends on GENERIC_HARDIRQS && SMP | ||
1324 | default y | ||
1325 | |||
1321 | config X86_SMP | 1326 | config X86_SMP |
1322 | bool | 1327 | bool |
1323 | depends on SMP && !X86_VOYAGER | 1328 | depends on SMP && !X86_VOYAGER |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 6578f40bd501..4a5940431579 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/acpi.h> | 33 | #include <linux/acpi.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/sysdev.h> | 35 | #include <linux/sysdev.h> |
36 | |||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
37 | #include <asm/smp.h> | 38 | #include <asm/smp.h> |
38 | #include <asm/desc.h> | 39 | #include <asm/desc.h> |
@@ -222,13 +223,21 @@ static void clear_IO_APIC (void) | |||
222 | clear_IO_APIC_pin(apic, pin); | 223 | clear_IO_APIC_pin(apic, pin); |
223 | } | 224 | } |
224 | 225 | ||
226 | #ifdef CONFIG_SMP | ||
225 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | 227 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) |
226 | { | 228 | { |
227 | unsigned long flags; | 229 | unsigned long flags; |
228 | int pin; | 230 | int pin; |
229 | struct irq_pin_list *entry = irq_2_pin + irq; | 231 | struct irq_pin_list *entry = irq_2_pin + irq; |
230 | unsigned int apicid_value; | 232 | unsigned int apicid_value; |
233 | cpumask_t tmp; | ||
231 | 234 | ||
235 | cpus_and(tmp, cpumask, cpu_online_map); | ||
236 | if (cpus_empty(tmp)) | ||
237 | tmp = TARGET_CPUS; | ||
238 | |||
239 | cpus_and(cpumask, tmp, CPU_MASK_ALL); | ||
240 | |||
232 | apicid_value = cpu_mask_to_apicid(cpumask); | 241 | apicid_value = cpu_mask_to_apicid(cpumask); |
233 | /* Prepare to do the io_apic_write */ | 242 | /* Prepare to do the io_apic_write */ |
234 | apicid_value = apicid_value << 24; | 243 | apicid_value = apicid_value << 24; |
@@ -242,6 +251,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | |||
242 | break; | 251 | break; |
243 | entry = irq_2_pin + entry->next; | 252 | entry = irq_2_pin + entry->next; |
244 | } | 253 | } |
254 | set_irq_info(irq, cpumask); | ||
245 | spin_unlock_irqrestore(&ioapic_lock, flags); | 255 | spin_unlock_irqrestore(&ioapic_lock, flags); |
246 | } | 256 | } |
247 | 257 | ||
@@ -259,7 +269,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | |||
259 | # define Dprintk(x...) | 269 | # define Dprintk(x...) |
260 | # endif | 270 | # endif |
261 | 271 | ||
262 | cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; | ||
263 | 272 | ||
264 | #define IRQBALANCE_CHECK_ARCH -999 | 273 | #define IRQBALANCE_CHECK_ARCH -999 |
265 | static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; | 274 | static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; |
@@ -328,12 +337,7 @@ static inline void balance_irq(int cpu, int irq) | |||
328 | cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); | 337 | cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); |
329 | new_cpu = move(cpu, allowed_mask, now, 1); | 338 | new_cpu = move(cpu, allowed_mask, now, 1); |
330 | if (cpu != new_cpu) { | 339 | if (cpu != new_cpu) { |
331 | irq_desc_t *desc = irq_desc + irq; | 340 | set_pending_irq(irq, cpumask_of_cpu(new_cpu)); |
332 | unsigned long flags; | ||
333 | |||
334 | spin_lock_irqsave(&desc->lock, flags); | ||
335 | pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu); | ||
336 | spin_unlock_irqrestore(&desc->lock, flags); | ||
337 | } | 341 | } |
338 | } | 342 | } |
339 | 343 | ||
@@ -528,16 +532,12 @@ tryanotherirq: | |||
528 | cpus_and(tmp, target_cpu_mask, allowed_mask); | 532 | cpus_and(tmp, target_cpu_mask, allowed_mask); |
529 | 533 | ||
530 | if (!cpus_empty(tmp)) { | 534 | if (!cpus_empty(tmp)) { |
531 | irq_desc_t *desc = irq_desc + selected_irq; | ||
532 | unsigned long flags; | ||
533 | 535 | ||
534 | Dprintk("irq = %d moved to cpu = %d\n", | 536 | Dprintk("irq = %d moved to cpu = %d\n", |
535 | selected_irq, min_loaded); | 537 | selected_irq, min_loaded); |
536 | /* mark for change destination */ | 538 | /* mark for change destination */ |
537 | spin_lock_irqsave(&desc->lock, flags); | 539 | set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded)); |
538 | pending_irq_balance_cpumask[selected_irq] = | 540 | |
539 | cpumask_of_cpu(min_loaded); | ||
540 | spin_unlock_irqrestore(&desc->lock, flags); | ||
541 | /* Since we made a change, come back sooner to | 541 | /* Since we made a change, come back sooner to |
542 | * check for more variation. | 542 | * check for more variation. |
543 | */ | 543 | */ |
@@ -568,7 +568,8 @@ static int balanced_irq(void *unused) | |||
568 | 568 | ||
569 | /* push everything to CPU 0 to give us a starting point. */ | 569 | /* push everything to CPU 0 to give us a starting point. */ |
570 | for (i = 0 ; i < NR_IRQS ; i++) { | 570 | for (i = 0 ; i < NR_IRQS ; i++) { |
571 | pending_irq_balance_cpumask[i] = cpumask_of_cpu(0); | 571 | pending_irq_cpumask[i] = cpumask_of_cpu(0); |
572 | set_pending_irq(i, cpumask_of_cpu(0)); | ||
572 | } | 573 | } |
573 | 574 | ||
574 | for ( ; ; ) { | 575 | for ( ; ; ) { |
@@ -647,20 +648,9 @@ int __init irqbalance_disable(char *str) | |||
647 | 648 | ||
648 | __setup("noirqbalance", irqbalance_disable); | 649 | __setup("noirqbalance", irqbalance_disable); |
649 | 650 | ||
650 | static inline void move_irq(int irq) | ||
651 | { | ||
652 | /* note - we hold the desc->lock */ | ||
653 | if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { | ||
654 | set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]); | ||
655 | cpus_clear(pending_irq_balance_cpumask[irq]); | ||
656 | } | ||
657 | } | ||
658 | |||
659 | late_initcall(balanced_irq_init); | 651 | late_initcall(balanced_irq_init); |
660 | |||
661 | #else /* !CONFIG_IRQBALANCE */ | ||
662 | static inline void move_irq(int irq) { } | ||
663 | #endif /* CONFIG_IRQBALANCE */ | 652 | #endif /* CONFIG_IRQBALANCE */ |
653 | #endif /* CONFIG_SMP */ | ||
664 | 654 | ||
665 | #ifndef CONFIG_SMP | 655 | #ifndef CONFIG_SMP |
666 | void fastcall send_IPI_self(int vector) | 656 | void fastcall send_IPI_self(int vector) |
@@ -820,6 +810,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); | |||
820 | * we need to reprogram the ioredtbls to cater for the cpus which have come online | 810 | * we need to reprogram the ioredtbls to cater for the cpus which have come online |
821 | * so mask in all cases should simply be TARGET_CPUS | 811 | * so mask in all cases should simply be TARGET_CPUS |
822 | */ | 812 | */ |
813 | #ifdef CONFIG_SMP | ||
823 | void __init setup_ioapic_dest(void) | 814 | void __init setup_ioapic_dest(void) |
824 | { | 815 | { |
825 | int pin, ioapic, irq, irq_entry; | 816 | int pin, ioapic, irq, irq_entry; |
@@ -838,6 +829,7 @@ void __init setup_ioapic_dest(void) | |||
838 | 829 | ||
839 | } | 830 | } |
840 | } | 831 | } |
832 | #endif | ||
841 | 833 | ||
842 | /* | 834 | /* |
843 | * EISA Edge/Level control register, ELCR | 835 | * EISA Edge/Level control register, ELCR |
@@ -1249,6 +1241,7 @@ static void __init setup_IO_APIC_irqs(void) | |||
1249 | spin_lock_irqsave(&ioapic_lock, flags); | 1241 | spin_lock_irqsave(&ioapic_lock, flags); |
1250 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); | 1242 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); |
1251 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); | 1243 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); |
1244 | set_native_irq_info(irq, TARGET_CPUS); | ||
1252 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1245 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1253 | } | 1246 | } |
1254 | } | 1247 | } |
@@ -1944,6 +1937,7 @@ static void ack_edge_ioapic_vector(unsigned int vector) | |||
1944 | { | 1937 | { |
1945 | int irq = vector_to_irq(vector); | 1938 | int irq = vector_to_irq(vector); |
1946 | 1939 | ||
1940 | move_irq(vector); | ||
1947 | ack_edge_ioapic_irq(irq); | 1941 | ack_edge_ioapic_irq(irq); |
1948 | } | 1942 | } |
1949 | 1943 | ||
@@ -1958,6 +1952,7 @@ static void end_level_ioapic_vector (unsigned int vector) | |||
1958 | { | 1952 | { |
1959 | int irq = vector_to_irq(vector); | 1953 | int irq = vector_to_irq(vector); |
1960 | 1954 | ||
1955 | move_irq(vector); | ||
1961 | end_level_ioapic_irq(irq); | 1956 | end_level_ioapic_irq(irq); |
1962 | } | 1957 | } |
1963 | 1958 | ||
@@ -1975,14 +1970,17 @@ static void unmask_IO_APIC_vector (unsigned int vector) | |||
1975 | unmask_IO_APIC_irq(irq); | 1970 | unmask_IO_APIC_irq(irq); |
1976 | } | 1971 | } |
1977 | 1972 | ||
1973 | #ifdef CONFIG_SMP | ||
1978 | static void set_ioapic_affinity_vector (unsigned int vector, | 1974 | static void set_ioapic_affinity_vector (unsigned int vector, |
1979 | cpumask_t cpu_mask) | 1975 | cpumask_t cpu_mask) |
1980 | { | 1976 | { |
1981 | int irq = vector_to_irq(vector); | 1977 | int irq = vector_to_irq(vector); |
1982 | 1978 | ||
1979 | set_native_irq_info(vector, cpu_mask); | ||
1983 | set_ioapic_affinity_irq(irq, cpu_mask); | 1980 | set_ioapic_affinity_irq(irq, cpu_mask); |
1984 | } | 1981 | } |
1985 | #endif | 1982 | #endif |
1983 | #endif | ||
1986 | 1984 | ||
1987 | /* | 1985 | /* |
1988 | * Level and edge triggered IO-APIC interrupts need different handling, | 1986 | * Level and edge triggered IO-APIC interrupts need different handling, |
@@ -2000,7 +1998,9 @@ static struct hw_interrupt_type ioapic_edge_type = { | |||
2000 | .disable = disable_edge_ioapic, | 1998 | .disable = disable_edge_ioapic, |
2001 | .ack = ack_edge_ioapic, | 1999 | .ack = ack_edge_ioapic, |
2002 | .end = end_edge_ioapic, | 2000 | .end = end_edge_ioapic, |
2001 | #ifdef CONFIG_SMP | ||
2003 | .set_affinity = set_ioapic_affinity, | 2002 | .set_affinity = set_ioapic_affinity, |
2003 | #endif | ||
2004 | }; | 2004 | }; |
2005 | 2005 | ||
2006 | static struct hw_interrupt_type ioapic_level_type = { | 2006 | static struct hw_interrupt_type ioapic_level_type = { |
@@ -2011,7 +2011,9 @@ static struct hw_interrupt_type ioapic_level_type = { | |||
2011 | .disable = disable_level_ioapic, | 2011 | .disable = disable_level_ioapic, |
2012 | .ack = mask_and_ack_level_ioapic, | 2012 | .ack = mask_and_ack_level_ioapic, |
2013 | .end = end_level_ioapic, | 2013 | .end = end_level_ioapic, |
2014 | #ifdef CONFIG_SMP | ||
2014 | .set_affinity = set_ioapic_affinity, | 2015 | .set_affinity = set_ioapic_affinity, |
2016 | #endif | ||
2015 | }; | 2017 | }; |
2016 | 2018 | ||
2017 | static inline void init_IO_APIC_traps(void) | 2019 | static inline void init_IO_APIC_traps(void) |
@@ -2569,6 +2571,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a | |||
2569 | spin_lock_irqsave(&ioapic_lock, flags); | 2571 | spin_lock_irqsave(&ioapic_lock, flags); |
2570 | io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); | 2572 | io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); |
2571 | io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); | 2573 | io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); |
2574 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); | ||
2572 | spin_unlock_irqrestore(&ioapic_lock, flags); | 2575 | spin_unlock_irqrestore(&ioapic_lock, flags); |
2573 | 2576 | ||
2574 | return 0; | 2577 | return 0; |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3deced637f07..17b5dbf8c311 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -434,6 +434,11 @@ config GENERIC_IRQ_PROBE | |||
434 | bool | 434 | bool |
435 | default y | 435 | default y |
436 | 436 | ||
437 | config GENERIC_PENDING_IRQ | ||
438 | bool | ||
439 | depends on GENERIC_HARDIRQS && SMP | ||
440 | default y | ||
441 | |||
437 | source "arch/ia64/hp/sim/Kconfig" | 442 | source "arch/ia64/hp/sim/Kconfig" |
438 | 443 | ||
439 | source "arch/ia64/oprofile/Kconfig" | 444 | source "arch/ia64/oprofile/Kconfig" |
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 28f2aadc38d0..205d98028261 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c | |||
@@ -91,23 +91,8 @@ skip: | |||
91 | } | 91 | } |
92 | 92 | ||
93 | #ifdef CONFIG_SMP | 93 | #ifdef CONFIG_SMP |
94 | /* | ||
95 | * This is updated when the user sets irq affinity via /proc | ||
96 | */ | ||
97 | static cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; | ||
98 | static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)]; | ||
99 | |||
100 | static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; | 94 | static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; |
101 | 95 | ||
102 | /* | ||
103 | * Arch specific routine for deferred write to iosapic rte to reprogram | ||
104 | * intr destination. | ||
105 | */ | ||
106 | void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) | ||
107 | { | ||
108 | pending_irq_cpumask[irq] = mask_val; | ||
109 | } | ||
110 | |||
111 | void set_irq_affinity_info (unsigned int irq, int hwid, int redir) | 96 | void set_irq_affinity_info (unsigned int irq, int hwid, int redir) |
112 | { | 97 | { |
113 | cpumask_t mask = CPU_MASK_NONE; | 98 | cpumask_t mask = CPU_MASK_NONE; |
@@ -116,32 +101,10 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir) | |||
116 | 101 | ||
117 | if (irq < NR_IRQS) { | 102 | if (irq < NR_IRQS) { |
118 | irq_affinity[irq] = mask; | 103 | irq_affinity[irq] = mask; |
104 | set_irq_info(irq, mask); | ||
119 | irq_redir[irq] = (char) (redir & 0xff); | 105 | irq_redir[irq] = (char) (redir & 0xff); |
120 | } | 106 | } |
121 | } | 107 | } |
122 | |||
123 | |||
124 | void move_irq(int irq) | ||
125 | { | ||
126 | /* note - we hold desc->lock */ | ||
127 | cpumask_t tmp; | ||
128 | irq_desc_t *desc = irq_descp(irq); | ||
129 | int redir = test_bit(irq, pending_irq_redir); | ||
130 | |||
131 | if (unlikely(!desc->handler->set_affinity)) | ||
132 | return; | ||
133 | |||
134 | if (!cpus_empty(pending_irq_cpumask[irq])) { | ||
135 | cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); | ||
136 | if (unlikely(!cpus_empty(tmp))) { | ||
137 | desc->handler->set_affinity(irq | (redir ? IA64_IRQ_REDIRECTED : 0), | ||
138 | pending_irq_cpumask[irq]); | ||
139 | } | ||
140 | cpus_clear(pending_irq_cpumask[irq]); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | #endif /* CONFIG_SMP */ | 108 | #endif /* CONFIG_SMP */ |
146 | 109 | ||
147 | #ifdef CONFIG_HOTPLUG_CPU | 110 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 75e52c57f19c..251ce7cf1a38 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
@@ -441,6 +441,11 @@ config ISA_DMA_API | |||
441 | bool | 441 | bool |
442 | default y | 442 | default y |
443 | 443 | ||
444 | config GENERIC_PENDING_IRQ | ||
445 | bool | ||
446 | depends on GENERIC_HARDIRQS && SMP | ||
447 | default y | ||
448 | |||
444 | menu "Power management options" | 449 | menu "Power management options" |
445 | 450 | ||
446 | source kernel/power/Kconfig | 451 | source kernel/power/Kconfig |
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index d206d7e49cf5..76bcc4e6979d 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -78,6 +78,54 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | |||
78 | #define vector_to_irq(vector) (vector) | 78 | #define vector_to_irq(vector) (vector) |
79 | #endif | 79 | #endif |
80 | 80 | ||
81 | #define __DO_ACTION(R, ACTION, FINAL) \ | ||
82 | \ | ||
83 | { \ | ||
84 | int pin; \ | ||
85 | struct irq_pin_list *entry = irq_2_pin + irq; \ | ||
86 | \ | ||
87 | for (;;) { \ | ||
88 | unsigned int reg; \ | ||
89 | pin = entry->pin; \ | ||
90 | if (pin == -1) \ | ||
91 | break; \ | ||
92 | reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ | ||
93 | reg ACTION; \ | ||
94 | io_apic_modify(entry->apic, reg); \ | ||
95 | if (!entry->next) \ | ||
96 | break; \ | ||
97 | entry = irq_2_pin + entry->next; \ | ||
98 | } \ | ||
99 | FINAL; \ | ||
100 | } | ||
101 | |||
102 | #ifdef CONFIG_SMP | ||
103 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | unsigned int dest; | ||
107 | cpumask_t tmp; | ||
108 | |||
109 | cpus_and(tmp, mask, cpu_online_map); | ||
110 | if (cpus_empty(tmp)) | ||
111 | tmp = TARGET_CPUS; | ||
112 | |||
113 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
114 | |||
115 | dest = cpu_mask_to_apicid(mask); | ||
116 | |||
117 | /* | ||
118 | * Only the high 8 bits are valid. | ||
119 | */ | ||
120 | dest = SET_APIC_LOGICAL_ID(dest); | ||
121 | |||
122 | spin_lock_irqsave(&ioapic_lock, flags); | ||
123 | __DO_ACTION(1, = dest, ) | ||
124 | set_irq_info(irq, mask); | ||
125 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
126 | } | ||
127 | #endif | ||
128 | |||
81 | /* | 129 | /* |
82 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are | 130 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are |
83 | * shared ISA-space IRQs, so we have to support them. We are super | 131 | * shared ISA-space IRQs, so we have to support them. We are super |
@@ -101,26 +149,6 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) | |||
101 | entry->pin = pin; | 149 | entry->pin = pin; |
102 | } | 150 | } |
103 | 151 | ||
104 | #define __DO_ACTION(R, ACTION, FINAL) \ | ||
105 | \ | ||
106 | { \ | ||
107 | int pin; \ | ||
108 | struct irq_pin_list *entry = irq_2_pin + irq; \ | ||
109 | \ | ||
110 | for (;;) { \ | ||
111 | unsigned int reg; \ | ||
112 | pin = entry->pin; \ | ||
113 | if (pin == -1) \ | ||
114 | break; \ | ||
115 | reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ | ||
116 | reg ACTION; \ | ||
117 | io_apic_modify(entry->apic, reg); \ | ||
118 | if (!entry->next) \ | ||
119 | break; \ | ||
120 | entry = irq_2_pin + entry->next; \ | ||
121 | } \ | ||
122 | FINAL; \ | ||
123 | } | ||
124 | 152 | ||
125 | #define DO_ACTION(name,R,ACTION, FINAL) \ | 153 | #define DO_ACTION(name,R,ACTION, FINAL) \ |
126 | \ | 154 | \ |
@@ -767,6 +795,7 @@ static void __init setup_IO_APIC_irqs(void) | |||
767 | spin_lock_irqsave(&ioapic_lock, flags); | 795 | spin_lock_irqsave(&ioapic_lock, flags); |
768 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); | 796 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); |
769 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); | 797 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); |
798 | set_native_irq_info(irq, TARGET_CPUS); | ||
770 | spin_unlock_irqrestore(&ioapic_lock, flags); | 799 | spin_unlock_irqrestore(&ioapic_lock, flags); |
771 | } | 800 | } |
772 | } | 801 | } |
@@ -1314,6 +1343,7 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) | |||
1314 | */ | 1343 | */ |
1315 | static void ack_edge_ioapic_irq(unsigned int irq) | 1344 | static void ack_edge_ioapic_irq(unsigned int irq) |
1316 | { | 1345 | { |
1346 | move_irq(irq); | ||
1317 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) | 1347 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) |
1318 | == (IRQ_PENDING | IRQ_DISABLED)) | 1348 | == (IRQ_PENDING | IRQ_DISABLED)) |
1319 | mask_IO_APIC_irq(irq); | 1349 | mask_IO_APIC_irq(irq); |
@@ -1343,26 +1373,10 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) | |||
1343 | 1373 | ||
1344 | static void end_level_ioapic_irq (unsigned int irq) | 1374 | static void end_level_ioapic_irq (unsigned int irq) |
1345 | { | 1375 | { |
1376 | move_irq(irq); | ||
1346 | ack_APIC_irq(); | 1377 | ack_APIC_irq(); |
1347 | } | 1378 | } |
1348 | 1379 | ||
1349 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | ||
1350 | { | ||
1351 | unsigned long flags; | ||
1352 | unsigned int dest; | ||
1353 | |||
1354 | dest = cpu_mask_to_apicid(mask); | ||
1355 | |||
1356 | /* | ||
1357 | * Only the high 8 bits are valid. | ||
1358 | */ | ||
1359 | dest = SET_APIC_LOGICAL_ID(dest); | ||
1360 | |||
1361 | spin_lock_irqsave(&ioapic_lock, flags); | ||
1362 | __DO_ACTION(1, = dest, ) | ||
1363 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1364 | } | ||
1365 | |||
1366 | #ifdef CONFIG_PCI_MSI | 1380 | #ifdef CONFIG_PCI_MSI |
1367 | static unsigned int startup_edge_ioapic_vector(unsigned int vector) | 1381 | static unsigned int startup_edge_ioapic_vector(unsigned int vector) |
1368 | { | 1382 | { |
@@ -1375,6 +1389,7 @@ static void ack_edge_ioapic_vector(unsigned int vector) | |||
1375 | { | 1389 | { |
1376 | int irq = vector_to_irq(vector); | 1390 | int irq = vector_to_irq(vector); |
1377 | 1391 | ||
1392 | move_native_irq(vector); | ||
1378 | ack_edge_ioapic_irq(irq); | 1393 | ack_edge_ioapic_irq(irq); |
1379 | } | 1394 | } |
1380 | 1395 | ||
@@ -1389,6 +1404,7 @@ static void end_level_ioapic_vector (unsigned int vector) | |||
1389 | { | 1404 | { |
1390 | int irq = vector_to_irq(vector); | 1405 | int irq = vector_to_irq(vector); |
1391 | 1406 | ||
1407 | move_native_irq(vector); | ||
1392 | end_level_ioapic_irq(irq); | 1408 | end_level_ioapic_irq(irq); |
1393 | } | 1409 | } |
1394 | 1410 | ||
@@ -1406,14 +1422,17 @@ static void unmask_IO_APIC_vector (unsigned int vector) | |||
1406 | unmask_IO_APIC_irq(irq); | 1422 | unmask_IO_APIC_irq(irq); |
1407 | } | 1423 | } |
1408 | 1424 | ||
1425 | #ifdef CONFIG_SMP | ||
1409 | static void set_ioapic_affinity_vector (unsigned int vector, | 1426 | static void set_ioapic_affinity_vector (unsigned int vector, |
1410 | cpumask_t cpu_mask) | 1427 | cpumask_t cpu_mask) |
1411 | { | 1428 | { |
1412 | int irq = vector_to_irq(vector); | 1429 | int irq = vector_to_irq(vector); |
1413 | 1430 | ||
1431 | set_native_irq_info(vector, cpu_mask); | ||
1414 | set_ioapic_affinity_irq(irq, cpu_mask); | 1432 | set_ioapic_affinity_irq(irq, cpu_mask); |
1415 | } | 1433 | } |
1416 | #endif | 1434 | #endif // CONFIG_SMP |
1435 | #endif // CONFIG_PCI_MSI | ||
1417 | 1436 | ||
1418 | /* | 1437 | /* |
1419 | * Level and edge triggered IO-APIC interrupts need different handling, | 1438 | * Level and edge triggered IO-APIC interrupts need different handling, |
@@ -1432,7 +1451,9 @@ static struct hw_interrupt_type ioapic_edge_type = { | |||
1432 | .disable = disable_edge_ioapic, | 1451 | .disable = disable_edge_ioapic, |
1433 | .ack = ack_edge_ioapic, | 1452 | .ack = ack_edge_ioapic, |
1434 | .end = end_edge_ioapic, | 1453 | .end = end_edge_ioapic, |
1454 | #ifdef CONFIG_SMP | ||
1435 | .set_affinity = set_ioapic_affinity, | 1455 | .set_affinity = set_ioapic_affinity, |
1456 | #endif | ||
1436 | }; | 1457 | }; |
1437 | 1458 | ||
1438 | static struct hw_interrupt_type ioapic_level_type = { | 1459 | static struct hw_interrupt_type ioapic_level_type = { |
@@ -1443,7 +1464,9 @@ static struct hw_interrupt_type ioapic_level_type = { | |||
1443 | .disable = disable_level_ioapic, | 1464 | .disable = disable_level_ioapic, |
1444 | .ack = mask_and_ack_level_ioapic, | 1465 | .ack = mask_and_ack_level_ioapic, |
1445 | .end = end_level_ioapic, | 1466 | .end = end_level_ioapic, |
1467 | #ifdef CONFIG_SMP | ||
1446 | .set_affinity = set_ioapic_affinity, | 1468 | .set_affinity = set_ioapic_affinity, |
1469 | #endif | ||
1447 | }; | 1470 | }; |
1448 | 1471 | ||
1449 | static inline void init_IO_APIC_traps(void) | 1472 | static inline void init_IO_APIC_traps(void) |
@@ -1918,6 +1941,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a | |||
1918 | spin_lock_irqsave(&ioapic_lock, flags); | 1941 | spin_lock_irqsave(&ioapic_lock, flags); |
1919 | io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); | 1942 | io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); |
1920 | io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); | 1943 | io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); |
1944 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); | ||
1921 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1945 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1922 | 1946 | ||
1923 | return 0; | 1947 | return 0; |
@@ -1931,6 +1955,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a | |||
1931 | * we need to reprogram the ioredtbls to cater for the cpus which have come online | 1955 | * we need to reprogram the ioredtbls to cater for the cpus which have come online |
1932 | * so mask in all cases should simply be TARGET_CPUS | 1956 | * so mask in all cases should simply be TARGET_CPUS |
1933 | */ | 1957 | */ |
1958 | #ifdef CONFIG_SMP | ||
1934 | void __init setup_ioapic_dest(void) | 1959 | void __init setup_ioapic_dest(void) |
1935 | { | 1960 | { |
1936 | int pin, ioapic, irq, irq_entry; | 1961 | int pin, ioapic, irq, irq_entry; |
@@ -1949,3 +1974,4 @@ void __init setup_ioapic_dest(void) | |||
1949 | 1974 | ||
1950 | } | 1975 | } |
1951 | } | 1976 | } |
1977 | #endif | ||