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; |
