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/i386 | |
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/i386')
-rw-r--r-- | arch/i386/Kconfig | 5 | ||||
-rw-r--r-- | arch/i386/kernel/io_apic.c | 55 |
2 files changed, 34 insertions, 26 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; |