diff options
-rw-r--r-- | arch/i386/kernel/io_apic.c | 2 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 144 |
2 files changed, 109 insertions, 37 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 7554f8fd874a..f2dd218d88cb 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -1649,7 +1649,7 @@ static void __init enable_IO_APIC(void) | |||
1649 | for(apic = 0; apic < nr_ioapics; apic++) { | 1649 | for(apic = 0; apic < nr_ioapics; apic++) { |
1650 | int pin; | 1650 | int pin; |
1651 | /* See if any of the pins is in ExtINT mode */ | 1651 | /* See if any of the pins is in ExtINT mode */ |
1652 | for(pin = 0; pin < nr_ioapic_registers[i]; pin++) { | 1652 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { |
1653 | struct IO_APIC_route_entry entry; | 1653 | struct IO_APIC_route_entry entry; |
1654 | spin_lock_irqsave(&ioapic_lock, flags); | 1654 | spin_lock_irqsave(&ioapic_lock, flags); |
1655 | *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); | 1655 | *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); |
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 83ea86e0633a..6c938c60fa3b 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -47,6 +47,9 @@ static int no_timer_check; | |||
47 | 47 | ||
48 | int disable_timer_pin_1 __initdata; | 48 | int disable_timer_pin_1 __initdata; |
49 | 49 | ||
50 | /* Where if anywhere is the i8259 connect in external int mode */ | ||
51 | static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; | ||
52 | |||
50 | static DEFINE_SPINLOCK(ioapic_lock); | 53 | static DEFINE_SPINLOCK(ioapic_lock); |
51 | 54 | ||
52 | /* | 55 | /* |
@@ -361,7 +364,7 @@ static int find_irq_entry(int apic, int pin, int type) | |||
361 | /* | 364 | /* |
362 | * Find the pin to which IRQ[irq] (ISA) is connected | 365 | * Find the pin to which IRQ[irq] (ISA) is connected |
363 | */ | 366 | */ |
364 | static int find_isa_irq_pin(int irq, int type) | 367 | static int __init find_isa_irq_pin(int irq, int type) |
365 | { | 368 | { |
366 | int i; | 369 | int i; |
367 | 370 | ||
@@ -379,6 +382,31 @@ static int find_isa_irq_pin(int irq, int type) | |||
379 | return -1; | 382 | return -1; |
380 | } | 383 | } |
381 | 384 | ||
385 | static int __init find_isa_irq_apic(int irq, int type) | ||
386 | { | ||
387 | int i; | ||
388 | |||
389 | for (i = 0; i < mp_irq_entries; i++) { | ||
390 | int lbus = mp_irqs[i].mpc_srcbus; | ||
391 | |||
392 | if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || | ||
393 | mp_bus_id_to_type[lbus] == MP_BUS_EISA || | ||
394 | mp_bus_id_to_type[lbus] == MP_BUS_MCA) && | ||
395 | (mp_irqs[i].mpc_irqtype == type) && | ||
396 | (mp_irqs[i].mpc_srcbusirq == irq)) | ||
397 | break; | ||
398 | } | ||
399 | if (i < mp_irq_entries) { | ||
400 | int apic; | ||
401 | for(apic = 0; apic < nr_ioapics; apic++) { | ||
402 | if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) | ||
403 | return apic; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | return -1; | ||
408 | } | ||
409 | |||
382 | /* | 410 | /* |
383 | * Find a specific PCI IRQ entry. | 411 | * Find a specific PCI IRQ entry. |
384 | * Not an __init, possibly needed by modules | 412 | * Not an __init, possibly needed by modules |
@@ -872,7 +900,7 @@ static void __init setup_IO_APIC_irqs(void) | |||
872 | * Set up the 8259A-master output pin as broadcast to all | 900 | * Set up the 8259A-master output pin as broadcast to all |
873 | * CPUs. | 901 | * CPUs. |
874 | */ | 902 | */ |
875 | static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) | 903 | static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) |
876 | { | 904 | { |
877 | struct IO_APIC_route_entry entry; | 905 | struct IO_APIC_route_entry entry; |
878 | unsigned long flags; | 906 | unsigned long flags; |
@@ -906,8 +934,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) | |||
906 | * Add it to the IO-APIC irq-routing table: | 934 | * Add it to the IO-APIC irq-routing table: |
907 | */ | 935 | */ |
908 | spin_lock_irqsave(&ioapic_lock, flags); | 936 | spin_lock_irqsave(&ioapic_lock, flags); |
909 | io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); | 937 | io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); |
910 | io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); | 938 | io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); |
911 | spin_unlock_irqrestore(&ioapic_lock, flags); | 939 | spin_unlock_irqrestore(&ioapic_lock, flags); |
912 | 940 | ||
913 | enable_8259A_irq(0); | 941 | enable_8259A_irq(0); |
@@ -1186,7 +1214,8 @@ void __apicdebuginit print_PIC(void) | |||
1186 | static void __init enable_IO_APIC(void) | 1214 | static void __init enable_IO_APIC(void) |
1187 | { | 1215 | { |
1188 | union IO_APIC_reg_01 reg_01; | 1216 | union IO_APIC_reg_01 reg_01; |
1189 | int i; | 1217 | int i8259_apic, i8259_pin; |
1218 | int i, apic; | ||
1190 | unsigned long flags; | 1219 | unsigned long flags; |
1191 | 1220 | ||
1192 | for (i = 0; i < PIN_MAP_SIZE; i++) { | 1221 | for (i = 0; i < PIN_MAP_SIZE; i++) { |
@@ -1200,11 +1229,48 @@ static void __init enable_IO_APIC(void) | |||
1200 | /* | 1229 | /* |
1201 | * The number of IO-APIC IRQ registers (== #pins): | 1230 | * The number of IO-APIC IRQ registers (== #pins): |
1202 | */ | 1231 | */ |
1203 | for (i = 0; i < nr_ioapics; i++) { | 1232 | for (apic = 0; apic < nr_ioapics; apic++) { |
1204 | spin_lock_irqsave(&ioapic_lock, flags); | 1233 | spin_lock_irqsave(&ioapic_lock, flags); |
1205 | reg_01.raw = io_apic_read(i, 1); | 1234 | reg_01.raw = io_apic_read(apic, 1); |
1206 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1235 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1207 | nr_ioapic_registers[i] = reg_01.bits.entries+1; | 1236 | nr_ioapic_registers[apic] = reg_01.bits.entries+1; |
1237 | } | ||
1238 | for(apic = 0; apic < nr_ioapics; apic++) { | ||
1239 | int pin; | ||
1240 | /* See if any of the pins is in ExtINT mode */ | ||
1241 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { | ||
1242 | struct IO_APIC_route_entry entry; | ||
1243 | spin_lock_irqsave(&ioapic_lock, flags); | ||
1244 | *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); | ||
1245 | *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); | ||
1246 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
1247 | |||
1248 | |||
1249 | /* If the interrupt line is enabled and in ExtInt mode | ||
1250 | * I have found the pin where the i8259 is connected. | ||
1251 | */ | ||
1252 | if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) { | ||
1253 | ioapic_i8259.apic = apic; | ||
1254 | ioapic_i8259.pin = pin; | ||
1255 | goto found_i8259; | ||
1256 | } | ||
1257 | } | ||
1258 | } | ||
1259 | found_i8259: | ||
1260 | /* Look to see what if the MP table has reported the ExtINT */ | ||
1261 | i8259_pin = find_isa_irq_pin(0, mp_ExtINT); | ||
1262 | i8259_apic = find_isa_irq_apic(0, mp_ExtINT); | ||
1263 | /* Trust the MP table if nothing is setup in the hardware */ | ||
1264 | if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) { | ||
1265 | printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n"); | ||
1266 | ioapic_i8259.pin = i8259_pin; | ||
1267 | ioapic_i8259.apic = i8259_apic; | ||
1268 | } | ||
1269 | /* Complain if the MP table and the hardware disagree */ | ||
1270 | if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) && | ||
1271 | (i8259_pin >= 0) && (ioapic_i8259.pin >= 0)) | ||
1272 | { | ||
1273 | printk(KERN_WARNING "ExtINT in hardware and MP table differ\n"); | ||
1208 | } | 1274 | } |
1209 | 1275 | ||
1210 | /* | 1276 | /* |
@@ -1218,7 +1284,6 @@ static void __init enable_IO_APIC(void) | |||
1218 | */ | 1284 | */ |
1219 | void disable_IO_APIC(void) | 1285 | void disable_IO_APIC(void) |
1220 | { | 1286 | { |
1221 | int pin; | ||
1222 | /* | 1287 | /* |
1223 | * Clear the IO-APIC before rebooting: | 1288 | * Clear the IO-APIC before rebooting: |
1224 | */ | 1289 | */ |
@@ -1229,8 +1294,7 @@ void disable_IO_APIC(void) | |||
1229 | * Put that IOAPIC in virtual wire mode | 1294 | * Put that IOAPIC in virtual wire mode |
1230 | * so legacy interrupts can be delivered. | 1295 | * so legacy interrupts can be delivered. |
1231 | */ | 1296 | */ |
1232 | pin = find_isa_irq_pin(0, mp_ExtINT); | 1297 | if (ioapic_i8259.pin != -1) { |
1233 | if (pin != -1) { | ||
1234 | struct IO_APIC_route_entry entry; | 1298 | struct IO_APIC_route_entry entry; |
1235 | unsigned long flags; | 1299 | unsigned long flags; |
1236 | 1300 | ||
@@ -1241,21 +1305,22 @@ void disable_IO_APIC(void) | |||
1241 | entry.polarity = 0; /* High */ | 1305 | entry.polarity = 0; /* High */ |
1242 | entry.delivery_status = 0; | 1306 | entry.delivery_status = 0; |
1243 | entry.dest_mode = 0; /* Physical */ | 1307 | entry.dest_mode = 0; /* Physical */ |
1244 | entry.delivery_mode = 7; /* ExtInt */ | 1308 | entry.delivery_mode = dest_ExtINT; /* ExtInt */ |
1245 | entry.vector = 0; | 1309 | entry.vector = 0; |
1246 | entry.dest.physical.physical_dest = 0; | 1310 | entry.dest.physical.physical_dest = 0; |
1247 | 1311 | ||
1248 | |||
1249 | /* | 1312 | /* |
1250 | * Add it to the IO-APIC irq-routing table: | 1313 | * Add it to the IO-APIC irq-routing table: |
1251 | */ | 1314 | */ |
1252 | spin_lock_irqsave(&ioapic_lock, flags); | 1315 | spin_lock_irqsave(&ioapic_lock, flags); |
1253 | io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); | 1316 | io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin, |
1254 | io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); | 1317 | *(((int *)&entry)+1)); |
1318 | io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin, | ||
1319 | *(((int *)&entry)+0)); | ||
1255 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1320 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1256 | } | 1321 | } |
1257 | 1322 | ||
1258 | disconnect_bsp_APIC(pin != -1); | 1323 | disconnect_bsp_APIC(ioapic_i8259.pin != -1); |
1259 | } | 1324 | } |
1260 | 1325 | ||
1261 | /* | 1326 | /* |
@@ -1624,20 +1689,21 @@ static void setup_nmi (void) | |||
1624 | */ | 1689 | */ |
1625 | static inline void unlock_ExtINT_logic(void) | 1690 | static inline void unlock_ExtINT_logic(void) |
1626 | { | 1691 | { |
1627 | int pin, i; | 1692 | int apic, pin, i; |
1628 | struct IO_APIC_route_entry entry0, entry1; | 1693 | struct IO_APIC_route_entry entry0, entry1; |
1629 | unsigned char save_control, save_freq_select; | 1694 | unsigned char save_control, save_freq_select; |
1630 | unsigned long flags; | 1695 | unsigned long flags; |
1631 | 1696 | ||
1632 | pin = find_isa_irq_pin(8, mp_INT); | 1697 | pin = find_isa_irq_pin(8, mp_INT); |
1698 | apic = find_isa_irq_apic(8, mp_INT); | ||
1633 | if (pin == -1) | 1699 | if (pin == -1) |
1634 | return; | 1700 | return; |
1635 | 1701 | ||
1636 | spin_lock_irqsave(&ioapic_lock, flags); | 1702 | spin_lock_irqsave(&ioapic_lock, flags); |
1637 | *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin); | 1703 | *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin); |
1638 | *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin); | 1704 | *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin); |
1639 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1705 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1640 | clear_IO_APIC_pin(0, pin); | 1706 | clear_IO_APIC_pin(apic, pin); |
1641 | 1707 | ||
1642 | memset(&entry1, 0, sizeof(entry1)); | 1708 | memset(&entry1, 0, sizeof(entry1)); |
1643 | 1709 | ||
@@ -1650,8 +1716,8 @@ static inline void unlock_ExtINT_logic(void) | |||
1650 | entry1.vector = 0; | 1716 | entry1.vector = 0; |
1651 | 1717 | ||
1652 | spin_lock_irqsave(&ioapic_lock, flags); | 1718 | spin_lock_irqsave(&ioapic_lock, flags); |
1653 | io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); | 1719 | io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); |
1654 | io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); | 1720 | io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); |
1655 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1721 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1656 | 1722 | ||
1657 | save_control = CMOS_READ(RTC_CONTROL); | 1723 | save_control = CMOS_READ(RTC_CONTROL); |
@@ -1669,11 +1735,11 @@ static inline void unlock_ExtINT_logic(void) | |||
1669 | 1735 | ||
1670 | CMOS_WRITE(save_control, RTC_CONTROL); | 1736 | CMOS_WRITE(save_control, RTC_CONTROL); |
1671 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 1737 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
1672 | clear_IO_APIC_pin(0, pin); | 1738 | clear_IO_APIC_pin(apic, pin); |
1673 | 1739 | ||
1674 | spin_lock_irqsave(&ioapic_lock, flags); | 1740 | spin_lock_irqsave(&ioapic_lock, flags); |
1675 | io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); | 1741 | io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); |
1676 | io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); | 1742 | io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); |
1677 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1743 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1678 | } | 1744 | } |
1679 | 1745 | ||
@@ -1685,7 +1751,7 @@ static inline void unlock_ExtINT_logic(void) | |||
1685 | */ | 1751 | */ |
1686 | static inline void check_timer(void) | 1752 | static inline void check_timer(void) |
1687 | { | 1753 | { |
1688 | int pin1, pin2; | 1754 | int apic1, pin1, apic2, pin2; |
1689 | int vector; | 1755 | int vector; |
1690 | 1756 | ||
1691 | /* | 1757 | /* |
@@ -1706,10 +1772,13 @@ static inline void check_timer(void) | |||
1706 | init_8259A(1); | 1772 | init_8259A(1); |
1707 | enable_8259A_irq(0); | 1773 | enable_8259A_irq(0); |
1708 | 1774 | ||
1709 | pin1 = find_isa_irq_pin(0, mp_INT); | 1775 | pin1 = find_isa_irq_pin(0, mp_INT); |
1710 | pin2 = find_isa_irq_pin(0, mp_ExtINT); | 1776 | apic1 = find_isa_irq_apic(0, mp_INT); |
1777 | pin2 = ioapic_i8259.pin; | ||
1778 | apic2 = ioapic_i8259.apic; | ||
1711 | 1779 | ||
1712 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2); | 1780 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", |
1781 | vector, apic1, pin1, apic2, pin2); | ||
1713 | 1782 | ||
1714 | if (pin1 != -1) { | 1783 | if (pin1 != -1) { |
1715 | /* | 1784 | /* |
@@ -1727,17 +1796,20 @@ static inline void check_timer(void) | |||
1727 | clear_IO_APIC_pin(0, pin1); | 1796 | clear_IO_APIC_pin(0, pin1); |
1728 | return; | 1797 | return; |
1729 | } | 1798 | } |
1730 | clear_IO_APIC_pin(0, pin1); | 1799 | clear_IO_APIC_pin(apic1, pin1); |
1731 | apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); | 1800 | apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " |
1801 | "connected to IO-APIC\n"); | ||
1732 | } | 1802 | } |
1733 | 1803 | ||
1734 | apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); | 1804 | apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " |
1805 | "through the 8259A ... "); | ||
1735 | if (pin2 != -1) { | 1806 | if (pin2 != -1) { |
1736 | apic_printk(APIC_VERBOSE,"\n..... (found pin %d) ...", pin2); | 1807 | apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", |
1808 | apic2, pin2); | ||
1737 | /* | 1809 | /* |
1738 | * legacy devices should be connected to IO APIC #0 | 1810 | * legacy devices should be connected to IO APIC #0 |
1739 | */ | 1811 | */ |
1740 | setup_ExtINT_IRQ0_pin(pin2, vector); | 1812 | setup_ExtINT_IRQ0_pin(apic2, pin2, vector); |
1741 | if (timer_irq_works()) { | 1813 | if (timer_irq_works()) { |
1742 | printk("works.\n"); | 1814 | printk("works.\n"); |
1743 | nmi_watchdog_default(); | 1815 | nmi_watchdog_default(); |
@@ -1749,7 +1821,7 @@ static inline void check_timer(void) | |||
1749 | /* | 1821 | /* |
1750 | * Cleanup, just in case ... | 1822 | * Cleanup, just in case ... |
1751 | */ | 1823 | */ |
1752 | clear_IO_APIC_pin(0, pin2); | 1824 | clear_IO_APIC_pin(apic2, pin2); |
1753 | } | 1825 | } |
1754 | printk(" failed.\n"); | 1826 | printk(" failed.\n"); |
1755 | 1827 | ||