aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r--arch/i386/kernel/apic.c80
1 files changed, 51 insertions, 29 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 8d993fa71754..93df90bbb87e 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -26,6 +26,7 @@
26#include <linux/mc146818rtc.h> 26#include <linux/mc146818rtc.h>
27#include <linux/kernel_stat.h> 27#include <linux/kernel_stat.h>
28#include <linux/sysdev.h> 28#include <linux/sysdev.h>
29#include <linux/cpu.h>
29 30
30#include <asm/atomic.h> 31#include <asm/atomic.h>
31#include <asm/smp.h> 32#include <asm/smp.h>
@@ -40,6 +41,11 @@
40#include "io_ports.h" 41#include "io_ports.h"
41 42
42/* 43/*
44 * Knob to control our willingness to enable the local APIC.
45 */
46int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
47
48/*
43 * Debug level 49 * Debug level
44 */ 50 */
45int apic_verbosity; 51int apic_verbosity;
@@ -205,7 +211,7 @@ void __init connect_bsp_APIC(void)
205 enable_apic_mode(); 211 enable_apic_mode();
206} 212}
207 213
208void disconnect_bsp_APIC(void) 214void disconnect_bsp_APIC(int virt_wire_setup)
209{ 215{
210 if (pic_mode) { 216 if (pic_mode) {
211 /* 217 /*
@@ -219,6 +225,42 @@ void disconnect_bsp_APIC(void)
219 outb(0x70, 0x22); 225 outb(0x70, 0x22);
220 outb(0x00, 0x23); 226 outb(0x00, 0x23);
221 } 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 }
222} 264}
223 265
224void disable_local_APIC(void) 266void disable_local_APIC(void)
@@ -363,7 +405,7 @@ void __init init_bsp_APIC(void)
363 apic_write_around(APIC_LVT1, value); 405 apic_write_around(APIC_LVT1, value);
364} 406}
365 407
366void __init setup_local_APIC (void) 408void __devinit setup_local_APIC(void)
367{ 409{
368 unsigned long oldvalue, value, ver, maxlvt; 410 unsigned long oldvalue, value, ver, maxlvt;
369 411
@@ -634,7 +676,7 @@ static struct sys_device device_lapic = {
634 .cls = &lapic_sysclass, 676 .cls = &lapic_sysclass,
635}; 677};
636 678
637static void __init apic_pm_activate(void) 679static void __devinit apic_pm_activate(void)
638{ 680{
639 apic_pm_state.active = 1; 681 apic_pm_state.active = 1;
640} 682}
@@ -665,26 +707,6 @@ static void apic_pm_activate(void) { }
665 * Original code written by Keir Fraser. 707 * Original code written by Keir Fraser.
666 */ 708 */
667 709
668/*
669 * Knob to control our willingness to enable the local APIC.
670 */
671int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
672
673static int __init lapic_disable(char *str)
674{
675 enable_local_apic = -1;
676 clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
677 return 0;
678}
679__setup("nolapic", lapic_disable);
680
681static int __init lapic_enable(char *str)
682{
683 enable_local_apic = 1;
684 return 0;
685}
686__setup("lapic", lapic_enable);
687
688static int __init apic_set_verbosity(char *str) 710static int __init apic_set_verbosity(char *str)
689{ 711{
690 if (strcmp("debug", str) == 0) 712 if (strcmp("debug", str) == 0)
@@ -855,7 +877,7 @@ fake_ioapic_page:
855 * but we do not accept timer interrupts yet. We only allow the BP 877 * but we do not accept timer interrupts yet. We only allow the BP
856 * to calibrate. 878 * to calibrate.
857 */ 879 */
858static unsigned int __init get_8254_timer_count(void) 880static unsigned int __devinit get_8254_timer_count(void)
859{ 881{
860 extern spinlock_t i8253_lock; 882 extern spinlock_t i8253_lock;
861 unsigned long flags; 883 unsigned long flags;
@@ -874,7 +896,7 @@ static unsigned int __init get_8254_timer_count(void)
874} 896}
875 897
876/* next tick in 8254 can be caught by catching timer wraparound */ 898/* next tick in 8254 can be caught by catching timer wraparound */
877static void __init wait_8254_wraparound(void) 899static void __devinit wait_8254_wraparound(void)
878{ 900{
879 unsigned int curr_count, prev_count; 901 unsigned int curr_count, prev_count;
880 902
@@ -894,7 +916,7 @@ static void __init wait_8254_wraparound(void)
894 * Default initialization for 8254 timers. If we use other timers like HPET, 916 * Default initialization for 8254 timers. If we use other timers like HPET,
895 * we override this later 917 * we override this later
896 */ 918 */
897void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound; 919void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound;
898 920
899/* 921/*
900 * This function sets up the local APIC timer, with a timeout of 922 * This function sets up the local APIC timer, with a timeout of
@@ -930,7 +952,7 @@ static void __setup_APIC_LVTT(unsigned int clocks)
930 apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); 952 apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
931} 953}
932 954
933static void __init setup_APIC_timer(unsigned int clocks) 955static void __devinit setup_APIC_timer(unsigned int clocks)
934{ 956{
935 unsigned long flags; 957 unsigned long flags;
936 958
@@ -1043,12 +1065,12 @@ void __init setup_boot_APIC_clock(void)
1043 local_irq_enable(); 1065 local_irq_enable();
1044} 1066}
1045 1067
1046void __init setup_secondary_APIC_clock(void) 1068void __devinit setup_secondary_APIC_clock(void)
1047{ 1069{
1048 setup_APIC_timer(calibration_result); 1070 setup_APIC_timer(calibration_result);
1049} 1071}
1050 1072
1051void __init disable_APIC_timer(void) 1073void __devinit disable_APIC_timer(void)
1052{ 1074{
1053 if (using_apic_timer) { 1075 if (using_apic_timer) {
1054 unsigned long v; 1076 unsigned long v;