aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-07-10 14:16:58 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-12 02:45:06 -0400
commit6e1cb38a2aef7680975e71f23de187859ee8b158 (patch)
tree4044df869c6314dcdac700f3fdd3cc256cc9d3a7
parent75c46fa61bc5b4ccd20a168ff325c58771248fcd (diff)
x64, x2apic/intr-remap: add x2apic support, including enabling interrupt-remapping
x2apic support. Interrupt-remapping must be enabled before enabling x2apic, this is needed to ensure that IO interrupts continue to work properly after the cpu mode is changed to x2apic(which uses 32bit extended physical/cluster apic id). On systems where apicid's are > 255, BIOS can handover the control to OS in x2apic mode. Or if the OS handover was in legacy xapic mode, check if it is capable of x2apic mode. And if we succeed in enabling Interrupt-remapping, then we can enable x2apic mode in the CPU. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: akpm@linux-foundation.org Cc: arjan@linux.intel.com Cc: andi@firstfloor.org Cc: ebiederm@xmission.com Cc: jbarnes@virtuousgeek.org Cc: steiner@sgi.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--arch/x86/kernel/acpi/boot.c2
-rw-r--r--arch/x86/kernel/apic_64.c154
-rw-r--r--arch/x86/kernel/cpu/common_64.c2
-rw-r--r--arch/x86/kernel/genapic_64.c1
-rw-r--r--arch/x86/kernel/mpparse.c2
-rw-r--r--arch/x86/kernel/setup.c2
-rw-r--r--arch/x86/kernel/smpboot.c5
-rw-r--r--include/asm-x86/apic.h5
9 files changed, 171 insertions, 4 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 795c487af8e..56689ef1a15 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 785700a08e9..8705262ddcd 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 d5c06917b5b..dd0501039f0 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 @@
46static int disable_apic_timer __cpuinitdata; 48static int disable_apic_timer __cpuinitdata;
47static int apic_calibrate_pmtmr __initdata; 49static int apic_calibrate_pmtmr __initdata;
48int disable_apic; 50int disable_apic;
51int disable_x2apic;
49int x2apic; 52int x2apic;
50 53
54/* x2apic enabled before OS handover */
55int x2apic_preenabled;
56
51/* Local APIC timer works in C2 */ 57/* Local APIC timer works in C2 */
52int local_apic_timer_c2_ok; 58int local_apic_timer_c2_ok;
53EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); 59EXPORT_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
905void 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
918void 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
929void 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 }
987end:
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 */
944void __init init_apic_mappings(void) 1069void __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
1521static __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}
1527early_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 36537ab9e56..e7bf3c2dc5f 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 1029e178cdf..792e21ba1a8 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 3b25e49380c..70e1f3e287f 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 987b6fde3a9..2e78a143dec 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 c55263b3df0..0c43e1f2e7d 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 aa746704a5c..129752dd252 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -100,6 +100,11 @@ extern void apic_wait_icr_idle(void);
100extern u32 safe_apic_wait_icr_idle(void); 100extern u32 safe_apic_wait_icr_idle(void);
101extern void apic_icr_write(u32 low, u32 id); 101extern void apic_icr_write(u32 low, u32 id);
102#else 102#else
103extern int x2apic, x2apic_preenabled;
104extern void check_x2apic(void);
105extern void enable_x2apic(void);
106extern void enable_IR_x2apic(void);
107extern void x2apic_icr_write(u32 low, u32 id);
103 108
104struct apic_ops { 109struct apic_ops {
105 u32 (*read)(u32 reg); 110 u32 (*read)(u32 reg);