diff options
Diffstat (limited to 'arch/x86_64/kernel/io_apic.c')
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 116 |
1 files changed, 71 insertions, 45 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index d206d7e49cf5..40e0aca088fb 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -70,7 +70,7 @@ static struct irq_pin_list { | |||
70 | short apic, pin, next; | 70 | short apic, pin, next; |
71 | } irq_2_pin[PIN_MAP_SIZE]; | 71 | } irq_2_pin[PIN_MAP_SIZE]; |
72 | 72 | ||
73 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 73 | int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; |
74 | #ifdef CONFIG_PCI_MSI | 74 | #ifdef CONFIG_PCI_MSI |
75 | #define vector_to_irq(vector) \ | 75 | #define vector_to_irq(vector) \ |
76 | (platform_legacy_irq(vector) ? vector : vector_irq[vector]) | 76 | (platform_legacy_irq(vector) ? vector : vector_irq[vector]) |
@@ -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 | \ |
@@ -655,7 +683,7 @@ static inline int IO_APIC_irq_trigger(int irq) | |||
655 | } | 683 | } |
656 | 684 | ||
657 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ | 685 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ |
658 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | 686 | u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; |
659 | 687 | ||
660 | int assign_irq_vector(int irq) | 688 | int assign_irq_vector(int irq) |
661 | { | 689 | { |
@@ -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, |
@@ -1424,7 +1443,7 @@ static void set_ioapic_affinity_vector (unsigned int vector, | |||
1424 | * races. | 1443 | * races. |
1425 | */ | 1444 | */ |
1426 | 1445 | ||
1427 | static struct hw_interrupt_type ioapic_edge_type = { | 1446 | static struct hw_interrupt_type ioapic_edge_type __read_mostly = { |
1428 | .typename = "IO-APIC-edge", | 1447 | .typename = "IO-APIC-edge", |
1429 | .startup = startup_edge_ioapic, | 1448 | .startup = startup_edge_ioapic, |
1430 | .shutdown = shutdown_edge_ioapic, | 1449 | .shutdown = shutdown_edge_ioapic, |
@@ -1432,10 +1451,12 @@ 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 __read_mostly = { |
1439 | .typename = "IO-APIC-level", | 1460 | .typename = "IO-APIC-level", |
1440 | .startup = startup_level_ioapic, | 1461 | .startup = startup_level_ioapic, |
1441 | .shutdown = shutdown_level_ioapic, | 1462 | .shutdown = shutdown_level_ioapic, |
@@ -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) |
@@ -1506,7 +1529,7 @@ static void ack_lapic_irq (unsigned int irq) | |||
1506 | 1529 | ||
1507 | static void end_lapic_irq (unsigned int i) { /* nothing */ } | 1530 | static void end_lapic_irq (unsigned int i) { /* nothing */ } |
1508 | 1531 | ||
1509 | static struct hw_interrupt_type lapic_irq_type = { | 1532 | static struct hw_interrupt_type lapic_irq_type __read_mostly = { |
1510 | .typename = "local-APIC-edge", | 1533 | .typename = "local-APIC-edge", |
1511 | .startup = NULL, /* startup_irq() not used for IRQ0 */ | 1534 | .startup = NULL, /* startup_irq() not used for IRQ0 */ |
1512 | .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ | 1535 | .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ |
@@ -1841,7 +1864,7 @@ device_initcall(ioapic_init_sysfs); | |||
1841 | ACPI-based IOAPIC Configuration | 1864 | ACPI-based IOAPIC Configuration |
1842 | -------------------------------------------------------------------------- */ | 1865 | -------------------------------------------------------------------------- */ |
1843 | 1866 | ||
1844 | #ifdef CONFIG_ACPI_BOOT | 1867 | #ifdef CONFIG_ACPI |
1845 | 1868 | ||
1846 | #define IO_APIC_MAX_ID 0xFE | 1869 | #define IO_APIC_MAX_ID 0xFE |
1847 | 1870 | ||
@@ -1918,12 +1941,13 @@ 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; |
1924 | } | 1948 | } |
1925 | 1949 | ||
1926 | #endif /*CONFIG_ACPI_BOOT*/ | 1950 | #endif /* CONFIG_ACPI */ |
1927 | 1951 | ||
1928 | 1952 | ||
1929 | /* | 1953 | /* |
@@ -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 | ||