aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/io_apic.c2
-rw-r--r--arch/x86_64/kernel/io_apic.c144
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
48int disable_timer_pin_1 __initdata; 48int disable_timer_pin_1 __initdata;
49 49
50/* Where if anywhere is the i8259 connect in external int mode */
51static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
52
50static DEFINE_SPINLOCK(ioapic_lock); 53static 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 */
364static int find_isa_irq_pin(int irq, int type) 367static 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
385static 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 */
875static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) 903static 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)
1186static void __init enable_IO_APIC(void) 1214static 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 */
1219void disable_IO_APIC(void) 1285void 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 */
1625static inline void unlock_ExtINT_logic(void) 1690static 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 */
1686static inline void check_timer(void) 1752static 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