aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2005-06-25 17:57:45 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 19:24:47 -0400
commit208fb93162d51faa69b9774fa7809858d84fd9dc (patch)
tree895115891463d3318677df4c3d76f6eca751eccd /arch
parent650927ef8ab1e9b05b77a3f32ca7adcedaae9306 (diff)
[PATCH] kexec: x86_64: restore 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')
-rw-r--r--arch/x86_64/kernel/apic.c38
-rw-r--r--arch/x86_64/kernel/io_apic.c36
2 files changed, 71 insertions, 3 deletions
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 2a6c893ccf6..375d369570c 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void)
133 } 133 }
134} 134}
135 135
136void disconnect_bsp_APIC(void) 136void disconnect_bsp_APIC(int virt_wire_setup)
137{ 137{
138 if (pic_mode) { 138 if (pic_mode) {
139 /* 139 /*
@@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void)
146 outb(0x70, 0x22); 146 outb(0x70, 0x22);
147 outb(0x00, 0x23); 147 outb(0x00, 0x23);
148 } 148 }
149 else {
150 /* Go back to Virtual Wire compatibility mode */
151 unsigned long value;
152
153 /* For the spurious interrupt use vector F, and enable it */
154 value = apic_read(APIC_SPIV);
155 value &= ~APIC_VECTOR_MASK;
156 value |= APIC_SPIV_APIC_ENABLED;
157 value |= 0xf;
158 apic_write_around(APIC_SPIV, value);
159
160 if (!virt_wire_setup) {
161 /* For LVT0 make it edge triggered, active high, external and enabled */
162 value = apic_read(APIC_LVT0);
163 value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
164 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
165 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
166 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
167 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
168 apic_write_around(APIC_LVT0, value);
169 }
170 else {
171 /* Disable LVT0 */
172 apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
173 }
174
175 /* For LVT1 make it edge triggered, active high, nmi and enabled */
176 value = apic_read(APIC_LVT1);
177 value &= ~(
178 APIC_MODE_MASK | APIC_SEND_PENDING |
179 APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
180 APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
181 value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
182 value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
183 apic_write_around(APIC_LVT1, value);
184 }
149} 185}
150 186
151void disable_local_APIC(void) 187void disable_local_APIC(void)
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index afd87e64d0a..157190d986b 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type)
330/* 330/*
331 * Find the pin to which IRQ[irq] (ISA) is connected 331 * Find the pin to which IRQ[irq] (ISA) is connected
332 */ 332 */
333static int __init find_isa_irq_pin(int irq, int type) 333static int find_isa_irq_pin(int irq, int type)
334{ 334{
335 int i; 335 int i;
336 336
@@ -1132,12 +1132,44 @@ static void __init enable_IO_APIC(void)
1132 */ 1132 */
1133void disable_IO_APIC(void) 1133void disable_IO_APIC(void)
1134{ 1134{
1135 int pin;
1135 /* 1136 /*
1136 * Clear the IO-APIC before rebooting: 1137 * Clear the IO-APIC before rebooting:
1137 */ 1138 */
1138 clear_IO_APIC(); 1139 clear_IO_APIC();
1139 1140
1140 disconnect_bsp_APIC(); 1141 /*
1142 * If the i82559 is routed through an IOAPIC
1143 * Put that IOAPIC in virtual wire mode
1144 * so legacy interrups can be delivered.
1145 */
1146 pin = find_isa_irq_pin(0, mp_ExtINT);
1147 if (pin != -1) {
1148 struct IO_APIC_route_entry entry;
1149 unsigned long flags;
1150
1151 memset(&entry, 0, sizeof(entry));
1152 entry.mask = 0; /* Enabled */
1153 entry.trigger = 0; /* Edge */
1154 entry.irr = 0;
1155 entry.polarity = 0; /* High */
1156 entry.delivery_status = 0;
1157 entry.dest_mode = 0; /* Physical */
1158 entry.delivery_mode = 7; /* ExtInt */
1159 entry.vector = 0;
1160 entry.dest.physical.physical_dest = 0;
1161
1162
1163 /*
1164 * Add it to the IO-APIC irq-routing table:
1165 */
1166 spin_lock_irqsave(&ioapic_lock, flags);
1167 io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
1168 io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
1169 spin_unlock_irqrestore(&ioapic_lock, flags);
1170 }
1171
1172 disconnect_bsp_APIC(pin != -1);
1141} 1173}
1142 1174
1143/* 1175/*