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 | ||
