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/x86_64 | |
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/x86_64')
-rw-r--r-- | arch/x86_64/Kconfig | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 102 |
2 files changed, 69 insertions, 38 deletions
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 | ||