aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-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/*