diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic_64.c | 154 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/genapic_64.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/mpparse.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 5 | ||||
-rw-r--r-- | include/asm-x86/apic.h | 5 |
9 files changed, 171 insertions, 4 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 795c487af8e4..56689ef1a159 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1377,6 +1377,8 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1377 | 1377 | ||
1378 | nolapic_timer [X86-32,APIC] Do not use the local APIC timer. | 1378 | nolapic_timer [X86-32,APIC] Do not use the local APIC timer. |
1379 | 1379 | ||
1380 | nox2apic [X86-64,APIC] Do not enable x2APIC mode. | ||
1381 | |||
1380 | noltlbs [PPC] Do not use large page/tlb entries for kernel | 1382 | noltlbs [PPC] Do not use large page/tlb entries for kernel |
1381 | lowmem mapping on PPC40x. | 1383 | lowmem mapping on PPC40x. |
1382 | 1384 | ||
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 785700a08e9d..8705262ddcda 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -1337,7 +1337,9 @@ static void __init acpi_process_madt(void) | |||
1337 | acpi_ioapic = 1; | 1337 | acpi_ioapic = 1; |
1338 | 1338 | ||
1339 | smp_found_config = 1; | 1339 | smp_found_config = 1; |
1340 | #ifdef CONFIG_X86_32 | ||
1340 | setup_apic_routing(); | 1341 | setup_apic_routing(); |
1342 | #endif | ||
1341 | } | 1343 | } |
1342 | } | 1344 | } |
1343 | if (error == -EINVAL) { | 1345 | if (error == -EINVAL) { |
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index d5c06917b5b1..dd0501039f09 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/clockchips.h> | 27 | #include <linux/clockchips.h> |
28 | #include <linux/acpi_pmtmr.h> | 28 | #include <linux/acpi_pmtmr.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/dmar.h> | ||
30 | 31 | ||
31 | #include <asm/atomic.h> | 32 | #include <asm/atomic.h> |
32 | #include <asm/smp.h> | 33 | #include <asm/smp.h> |
@@ -39,6 +40,7 @@ | |||
39 | #include <asm/proto.h> | 40 | #include <asm/proto.h> |
40 | #include <asm/timex.h> | 41 | #include <asm/timex.h> |
41 | #include <asm/apic.h> | 42 | #include <asm/apic.h> |
43 | #include <asm/i8259.h> | ||
42 | 44 | ||
43 | #include <mach_ipi.h> | 45 | #include <mach_ipi.h> |
44 | #include <mach_apic.h> | 46 | #include <mach_apic.h> |
@@ -46,8 +48,12 @@ | |||
46 | static int disable_apic_timer __cpuinitdata; | 48 | static int disable_apic_timer __cpuinitdata; |
47 | static int apic_calibrate_pmtmr __initdata; | 49 | static int apic_calibrate_pmtmr __initdata; |
48 | int disable_apic; | 50 | int disable_apic; |
51 | int disable_x2apic; | ||
49 | int x2apic; | 52 | int x2apic; |
50 | 53 | ||
54 | /* x2apic enabled before OS handover */ | ||
55 | int x2apic_preenabled; | ||
56 | |||
51 | /* Local APIC timer works in C2 */ | 57 | /* Local APIC timer works in C2 */ |
52 | int local_apic_timer_c2_ok; | 58 | int local_apic_timer_c2_ok; |
53 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); | 59 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); |
@@ -896,6 +902,125 @@ void __cpuinit end_local_APIC_setup(void) | |||
896 | apic_pm_activate(); | 902 | apic_pm_activate(); |
897 | } | 903 | } |
898 | 904 | ||
905 | void check_x2apic(void) | ||
906 | { | ||
907 | int msr, msr2; | ||
908 | |||
909 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
910 | |||
911 | if (msr & X2APIC_ENABLE) { | ||
912 | printk("x2apic enabled by BIOS, switching to x2apic ops\n"); | ||
913 | x2apic_preenabled = x2apic = 1; | ||
914 | apic_ops = &x2apic_ops; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | void enable_x2apic(void) | ||
919 | { | ||
920 | int msr, msr2; | ||
921 | |||
922 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
923 | if (!(msr & X2APIC_ENABLE)) { | ||
924 | printk("Enabling x2apic\n"); | ||
925 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | void enable_IR_x2apic(void) | ||
930 | { | ||
931 | #ifdef CONFIG_INTR_REMAP | ||
932 | int ret; | ||
933 | unsigned long flags; | ||
934 | |||
935 | if (!cpu_has_x2apic) | ||
936 | return; | ||
937 | |||
938 | if (!x2apic_preenabled && disable_x2apic) { | ||
939 | printk(KERN_INFO | ||
940 | "Skipped enabling x2apic and Interrupt-remapping " | ||
941 | "because of nox2apic\n"); | ||
942 | return; | ||
943 | } | ||
944 | |||
945 | if (x2apic_preenabled && disable_x2apic) | ||
946 | panic("Bios already enabled x2apic, can't enforce nox2apic"); | ||
947 | |||
948 | if (!x2apic_preenabled && skip_ioapic_setup) { | ||
949 | printk(KERN_INFO | ||
950 | "Skipped enabling x2apic and Interrupt-remapping " | ||
951 | "because of skipping io-apic setup\n"); | ||
952 | return; | ||
953 | } | ||
954 | |||
955 | ret = dmar_table_init(); | ||
956 | if (ret) { | ||
957 | printk(KERN_INFO | ||
958 | "dmar_table_init() failed with %d:\n", ret); | ||
959 | |||
960 | if (x2apic_preenabled) | ||
961 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
962 | else | ||
963 | printk(KERN_INFO | ||
964 | "Not enabling x2apic,Intr-remapping\n"); | ||
965 | return; | ||
966 | } | ||
967 | |||
968 | local_irq_save(flags); | ||
969 | mask_8259A(); | ||
970 | save_mask_IO_APIC_setup(); | ||
971 | |||
972 | ret = enable_intr_remapping(1); | ||
973 | |||
974 | if (ret && x2apic_preenabled) { | ||
975 | local_irq_restore(flags); | ||
976 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
977 | } | ||
978 | |||
979 | if (ret) | ||
980 | goto end; | ||
981 | |||
982 | if (!x2apic) { | ||
983 | x2apic = 1; | ||
984 | apic_ops = &x2apic_ops; | ||
985 | enable_x2apic(); | ||
986 | } | ||
987 | end: | ||
988 | if (ret) | ||
989 | /* | ||
990 | * IR enabling failed | ||
991 | */ | ||
992 | restore_IO_APIC_setup(); | ||
993 | else | ||
994 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | ||
995 | |||
996 | unmask_8259A(); | ||
997 | local_irq_restore(flags); | ||
998 | |||
999 | if (!ret) { | ||
1000 | if (!x2apic_preenabled) | ||
1001 | printk(KERN_INFO | ||
1002 | "Enabled x2apic and interrupt-remapping\n"); | ||
1003 | else | ||
1004 | printk(KERN_INFO | ||
1005 | "Enabled Interrupt-remapping\n"); | ||
1006 | } else | ||
1007 | printk(KERN_ERR | ||
1008 | "Failed to enable Interrupt-remapping and x2apic\n"); | ||
1009 | #else | ||
1010 | if (!cpu_has_x2apic) | ||
1011 | return; | ||
1012 | |||
1013 | if (x2apic_preenabled) | ||
1014 | panic("x2apic enabled prior OS handover," | ||
1015 | " enable CONFIG_INTR_REMAP"); | ||
1016 | |||
1017 | printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " | ||
1018 | " and x2apic\n"); | ||
1019 | #endif | ||
1020 | |||
1021 | return; | ||
1022 | } | ||
1023 | |||
899 | /* | 1024 | /* |
900 | * Detect and enable local APICs on non-SMP boards. | 1025 | * Detect and enable local APICs on non-SMP boards. |
901 | * Original code written by Keir Fraser. | 1026 | * Original code written by Keir Fraser. |
@@ -943,6 +1068,11 @@ void __init early_init_lapic_mapping(void) | |||
943 | */ | 1068 | */ |
944 | void __init init_apic_mappings(void) | 1069 | void __init init_apic_mappings(void) |
945 | { | 1070 | { |
1071 | if (x2apic) { | ||
1072 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | ||
1073 | return; | ||
1074 | } | ||
1075 | |||
946 | /* | 1076 | /* |
947 | * If no local APIC can be found then set up a fake all | 1077 | * If no local APIC can be found then set up a fake all |
948 | * zeroes page to simulate the local APIC and another | 1078 | * zeroes page to simulate the local APIC and another |
@@ -981,6 +1111,9 @@ int __init APIC_init_uniprocessor(void) | |||
981 | return -1; | 1111 | return -1; |
982 | } | 1112 | } |
983 | 1113 | ||
1114 | enable_IR_x2apic(); | ||
1115 | setup_apic_routing(); | ||
1116 | |||
984 | verify_local_APIC(); | 1117 | verify_local_APIC(); |
985 | 1118 | ||
986 | connect_bsp_APIC(); | 1119 | connect_bsp_APIC(); |
@@ -1238,10 +1371,14 @@ static int lapic_resume(struct sys_device *dev) | |||
1238 | maxlvt = lapic_get_maxlvt(); | 1371 | maxlvt = lapic_get_maxlvt(); |
1239 | 1372 | ||
1240 | local_irq_save(flags); | 1373 | local_irq_save(flags); |
1241 | rdmsr(MSR_IA32_APICBASE, l, h); | 1374 | if (!x2apic) { |
1242 | l &= ~MSR_IA32_APICBASE_BASE; | 1375 | rdmsr(MSR_IA32_APICBASE, l, h); |
1243 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; | 1376 | l &= ~MSR_IA32_APICBASE_BASE; |
1244 | wrmsr(MSR_IA32_APICBASE, l, h); | 1377 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; |
1378 | wrmsr(MSR_IA32_APICBASE, l, h); | ||
1379 | } else | ||
1380 | enable_x2apic(); | ||
1381 | |||
1245 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); | 1382 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); |
1246 | apic_write(APIC_ID, apic_pm_state.apic_id); | 1383 | apic_write(APIC_ID, apic_pm_state.apic_id); |
1247 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); | 1384 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); |
@@ -1381,6 +1518,15 @@ __cpuinit int apic_is_clustered_box(void) | |||
1381 | return (clusters > 2); | 1518 | return (clusters > 2); |
1382 | } | 1519 | } |
1383 | 1520 | ||
1521 | static __init int setup_nox2apic(char *str) | ||
1522 | { | ||
1523 | disable_x2apic = 1; | ||
1524 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC); | ||
1525 | return 0; | ||
1526 | } | ||
1527 | early_param("nox2apic", setup_nox2apic); | ||
1528 | |||
1529 | |||
1384 | /* | 1530 | /* |
1385 | * APIC command line parameters | 1531 | * APIC command line parameters |
1386 | */ | 1532 | */ |
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c index 36537ab9e56a..e7bf3c2dc5fe 100644 --- a/arch/x86/kernel/cpu/common_64.c +++ b/arch/x86/kernel/cpu/common_64.c | |||
@@ -606,6 +606,8 @@ void __cpuinit cpu_init(void) | |||
606 | barrier(); | 606 | barrier(); |
607 | 607 | ||
608 | check_efer(); | 608 | check_efer(); |
609 | if (cpu != 0 && x2apic) | ||
610 | enable_x2apic(); | ||
609 | 611 | ||
610 | /* | 612 | /* |
611 | * set up and load the per-CPU TSS | 613 | * set up and load the per-CPU TSS |
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c index 1029e178cdf7..792e21ba1a81 100644 --- a/arch/x86/kernel/genapic_64.c +++ b/arch/x86/kernel/genapic_64.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/ctype.h> | 16 | #include <linux/ctype.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/hardirq.h> | 18 | #include <linux/hardirq.h> |
19 | #include <linux/dmar.h> | ||
19 | 20 | ||
20 | #include <asm/smp.h> | 21 | #include <asm/smp.h> |
21 | #include <asm/ipi.h> | 22 | #include <asm/ipi.h> |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 3b25e49380c6..70e1f3e287fb 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
@@ -545,7 +545,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early) | |||
545 | generic_bigsmp_probe(); | 545 | generic_bigsmp_probe(); |
546 | #endif | 546 | #endif |
547 | 547 | ||
548 | #ifdef CONFIG_X86_32 | ||
548 | setup_apic_routing(); | 549 | setup_apic_routing(); |
550 | #endif | ||
549 | if (!num_processors) | 551 | if (!num_processors) |
550 | printk(KERN_ERR "MPTABLE: no processors registered!\n"); | 552 | printk(KERN_ERR "MPTABLE: no processors registered!\n"); |
551 | return num_processors; | 553 | return num_processors; |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 987b6fde3a99..2e78a143dec3 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -730,6 +730,8 @@ void __init setup_arch(char **cmdline_p) | |||
730 | num_physpages = max_pfn; | 730 | num_physpages = max_pfn; |
731 | 731 | ||
732 | check_efer(); | 732 | check_efer(); |
733 | if (cpu_has_x2apic) | ||
734 | check_x2apic(); | ||
733 | 735 | ||
734 | /* How many end-of-memory variables you have, grandma! */ | 736 | /* How many end-of-memory variables you have, grandma! */ |
735 | /* need this before calling reserve_initrd */ | 737 | /* need this before calling reserve_initrd */ |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index c55263b3df02..0c43e1f2e7d3 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -1145,6 +1145,11 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) | |||
1145 | current_thread_info()->cpu = 0; /* needed? */ | 1145 | current_thread_info()->cpu = 0; /* needed? */ |
1146 | set_cpu_sibling_map(0); | 1146 | set_cpu_sibling_map(0); |
1147 | 1147 | ||
1148 | #ifdef CONFIG_X86_64 | ||
1149 | enable_IR_x2apic(); | ||
1150 | setup_apic_routing(); | ||
1151 | #endif | ||
1152 | |||
1148 | if (smp_sanity_check(max_cpus) < 0) { | 1153 | if (smp_sanity_check(max_cpus) < 0) { |
1149 | printk(KERN_INFO "SMP disabled\n"); | 1154 | printk(KERN_INFO "SMP disabled\n"); |
1150 | disable_smp(); | 1155 | disable_smp(); |
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h index aa746704a5c9..129752dd2525 100644 --- a/include/asm-x86/apic.h +++ b/include/asm-x86/apic.h | |||
@@ -100,6 +100,11 @@ extern void apic_wait_icr_idle(void); | |||
100 | extern u32 safe_apic_wait_icr_idle(void); | 100 | extern u32 safe_apic_wait_icr_idle(void); |
101 | extern void apic_icr_write(u32 low, u32 id); | 101 | extern void apic_icr_write(u32 low, u32 id); |
102 | #else | 102 | #else |
103 | extern int x2apic, x2apic_preenabled; | ||
104 | extern void check_x2apic(void); | ||
105 | extern void enable_x2apic(void); | ||
106 | extern void enable_IR_x2apic(void); | ||
107 | extern void x2apic_icr_write(u32 low, u32 id); | ||
103 | 108 | ||
104 | struct apic_ops { | 109 | struct apic_ops { |
105 | u32 (*read)(u32 reg); | 110 | u32 (*read)(u32 reg); |