aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-01-11 16:46:06 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-11 22:05:00 -0500
commit1008fddcaed7ad3e69f72939c87b24d0d3387ca2 (patch)
tree916bb6d6d4a6e4ee6e92d936ec9ee322bbd6a7ed
parent60923df35edab273d0bd8e829cdfdc5cfbb4fd2c (diff)
[PATCH] x86_64: Memorize location of i8259 for reboots.
Currently we attempt to restore virtual wire mode on reboot, which only works if we can figure out where the i8259 is connected. This is very useful when we are kexec another kernel and likely helpful to an peculiar BIOS that make assumptions about how the system is setup. Since the acpi MADT table does not provide the location where the i8259 is connected we have to look at the hardware to figure it out. Most systems have the i8259 connected the local apic of the cpu so won't be affected but people running Opteron and some serverworks chipsets should be able to use kexec now. In addition this patch removes the hard coded assumption that the io_apic that delivers isa interrups is always known to the kernel as io_apic 0. There does not appear to be anything to guarantee that assumption is true. And From: Vivek Goyal <vgoyal@in.ibm.com> A minor fix to the patch which remembers the location of where i8259 is connected. Now counter i has been replaced by apic. counter i is having some junk value which was leading to non-detection of i8259 connected to IOAPIC. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-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