diff options
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r-- | arch/i386/kernel/apic.c | 80 |
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 | */ | ||
46 | int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ | ||
47 | |||
48 | /* | ||
43 | * Debug level | 49 | * Debug level |
44 | */ | 50 | */ |
45 | int apic_verbosity; | 51 | int apic_verbosity; |
@@ -205,7 +211,7 @@ void __init connect_bsp_APIC(void) | |||
205 | enable_apic_mode(); | 211 | enable_apic_mode(); |
206 | } | 212 | } |
207 | 213 | ||
208 | void disconnect_bsp_APIC(void) | 214 | void 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 | ||
224 | void disable_local_APIC(void) | 266 | void 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 | ||
366 | void __init setup_local_APIC (void) | 408 | void __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 | ||
637 | static void __init apic_pm_activate(void) | 679 | static 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 | */ | ||
671 | int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ | ||
672 | |||
673 | static 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 | |||
681 | static int __init lapic_enable(char *str) | ||
682 | { | ||
683 | enable_local_apic = 1; | ||
684 | return 0; | ||
685 | } | ||
686 | __setup("lapic", lapic_enable); | ||
687 | |||
688 | static int __init apic_set_verbosity(char *str) | 710 | static 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 | */ |
858 | static unsigned int __init get_8254_timer_count(void) | 880 | static 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 */ |
877 | static void __init wait_8254_wraparound(void) | 899 | static 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 | */ |
897 | void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound; | 919 | void (*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 | ||
933 | static void __init setup_APIC_timer(unsigned int clocks) | 955 | static 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 | ||
1046 | void __init setup_secondary_APIC_clock(void) | 1068 | void __devinit setup_secondary_APIC_clock(void) |
1047 | { | 1069 | { |
1048 | setup_APIC_timer(calibration_result); | 1070 | setup_APIC_timer(calibration_result); |
1049 | } | 1071 | } |
1050 | 1072 | ||
1051 | void __init disable_APIC_timer(void) | 1073 | void __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; |