aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2005-06-25 17:57:44 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 19:24:47 -0400
commit650927ef8ab1e9b05b77a3f32ca7adcedaae9306 (patch)
tree25ae75b36a2543d6f7ccc6bbe30c35c65d038ee3 /arch/i386
parent719e711050482be667dafd39ec787859d353931c (diff)
[PATCH] kexec: x86: resture apic virtual wire mode on shutdown
When coming out of apic mode attempt to set the appropriate apic back into virtual wire mode. This improves on previous versions of this patch by by never setting bot the local apic and the ioapic into veritual wire mode. This code looks at data from the mptable to see if an ioapic has an ExtInt input to make this decision. A future improvement is to figure out which apic or ioapic was in virtual wire mode at boot time and to remember it. That is potentially a more accurate method, of selecting which apic to place in virutal wire mode. Signed-off-by: Eric Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/apic.c38
-rw-r--r--arch/i386/kernel/io_apic.c33
2 files changed, 69 insertions, 2 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index cf45bed96d08..93df90bbb87e 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -211,7 +211,7 @@ void __init connect_bsp_APIC(void)
211 enable_apic_mode(); 211 enable_apic_mode();
212} 212}
213 213
214void disconnect_bsp_APIC(void) 214void disconnect_bsp_APIC(int virt_wire_setup)
215{ 215{
216 if (pic_mode) { 216 if (pic_mode) {
217 /* 217 /*
@@ -225,6 +225,42 @@ void disconnect_bsp_APIC(void)
225 outb(0x70, 0x22); 225 outb(0x70, 0x22);
226 outb(0x00, 0x23); 226 outb(0x00, 0x23);
227 } 227 }
228 else {
229 /* Go back to Virtual Wire compatibility mode */
230 unsigned long value;
231
232 /* For the spurious interrupt use vector F, and enable it */
233 value = apic_read(APIC_SPIV);
234 value &= ~APIC_VECTOR_MASK;
235 value |= APIC_SPIV_APIC_ENABLED;
236 value |= 0xf;
237 apic_write_around(APIC_SPIV, value);
238
239 if (!virt_wire_setup) {
240 /* For LVT0 make it edge triggered, active high, external and enabled */
241 value = apic_read(APIC_LVT0);
242 value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
243 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
244 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
245 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
246 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
247 apic_write_around(APIC_LVT0, value);
248 }
249 else {
250 /* Disable LVT0 */
251 apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
252 }
253
254 /* For LVT1 make it edge triggered, active high, nmi and enabled */
255 value = apic_read(APIC_LVT1);
256 value &= ~(
257 APIC_MODE_MASK | APIC_SEND_PENDING |
258 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
259 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
260 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
261 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
262 apic_write_around(APIC_LVT1, value);
263 }
228} 264}
229 265
230void disable_local_APIC(void) 266void disable_local_APIC(void)
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 3c2b3bdfc807..fc81c8cddd22 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -1636,12 +1636,43 @@ static void __init enable_IO_APIC(void)
1636 */ 1636 */
1637void disable_IO_APIC(void) 1637void disable_IO_APIC(void)
1638{ 1638{
1639 int pin;
1639 /* 1640 /*
1640 * Clear the IO-APIC before rebooting: 1641 * Clear the IO-APIC before rebooting:
1641 */ 1642 */
1642 clear_IO_APIC(); 1643 clear_IO_APIC();
1643 1644
1644 disconnect_bsp_APIC(); 1645 /*
1646 * If the i82559 is routed through an IOAPIC
1647 * Put that IOAPIC in virtual wire mode
1648 * so legacy interrups can be delivered.
1649 */
1650 pin = find_isa_irq_pin(0, mp_ExtINT);
1651 if (pin != -1) {
1652 struct IO_APIC_route_entry entry;
1653 unsigned long flags;
1654
1655 memset(&entry, 0, sizeof(entry));
1656 entry.mask = 0; /* Enabled */
1657 entry.trigger = 0; /* Edge */
1658 entry.irr = 0;
1659 entry.polarity = 0; /* High */
1660 entry.delivery_status = 0;
1661 entry.dest_mode = 0; /* Physical */
1662 entry.delivery_mode = 7; /* ExtInt */
1663 entry.vector = 0;
1664 entry.dest.physical.physical_dest = 0;
1665
1666
1667 /*
1668 * Add it to the IO-APIC irq-routing table:
1669 */
1670 spin_lock_irqsave(&ioapic_lock, flags);
1671 io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
1672 io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
1673 spin_unlock_irqrestore(&ioapic_lock, flags);
1674 }
1675 disconnect_bsp_APIC(pin != -1);
1645} 1676}
1646 1677
1647/* 1678/*