aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic_64.c
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 /arch/x86/kernel/apic_64.c
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>
Diffstat (limited to 'arch/x86/kernel/apic_64.c')
-rw-r--r--arch/x86/kernel/apic_64.c154
1 files changed, 150 insertions, 4 deletions
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 @@
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 */