aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic_64.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-08-15 07:46:28 -0400
committerIngo Molnar <mingo@elte.hu>2008-08-15 07:46:28 -0400
commit5aa37e4f0614e3b1f385426ce1e962e84c275bdf (patch)
tree3d8c30207989d09fde8ffb2c3c44c6b923d70062 /arch/x86/kernel/apic_64.c
parentd4c63ec060f3315653c0ae5bc3a7fe2419a2282f (diff)
parentb76d69ed721e8365739c3bd5dd7891efbea88494 (diff)
Merge branch 'x86/core' into x86/apic
Diffstat (limited to 'arch/x86/kernel/apic_64.c')
-rw-r--r--arch/x86/kernel/apic_64.c237
1 files changed, 226 insertions, 11 deletions
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 7615b4b9c3f3..69a876be506f 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,6 +48,11 @@
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;
52int x2apic;
53
54/* x2apic enabled before OS handover */
55int x2apic_preenabled;
49 56
50/* Local APIC timer works in C2 */ 57/* Local APIC timer works in C2 */
51int local_apic_timer_c2_ok; 58int local_apic_timer_c2_ok;
@@ -119,13 +126,13 @@ static int modern_apic(void)
119 return lapic_get_version() >= 0x14; 126 return lapic_get_version() >= 0x14;
120} 127}
121 128
122void apic_wait_icr_idle(void) 129void xapic_wait_icr_idle(void)
123{ 130{
124 while (apic_read(APIC_ICR) & APIC_ICR_BUSY) 131 while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
125 cpu_relax(); 132 cpu_relax();
126} 133}
127 134
128u32 safe_apic_wait_icr_idle(void) 135u32 safe_xapic_wait_icr_idle(void)
129{ 136{
130 u32 send_status; 137 u32 send_status;
131 int timeout; 138 int timeout;
@@ -141,6 +148,69 @@ u32 safe_apic_wait_icr_idle(void)
141 return send_status; 148 return send_status;
142} 149}
143 150
151void xapic_icr_write(u32 low, u32 id)
152{
153 apic_write(APIC_ICR2, id << 24);
154 apic_write(APIC_ICR, low);
155}
156
157u64 xapic_icr_read(void)
158{
159 u32 icr1, icr2;
160
161 icr2 = apic_read(APIC_ICR2);
162 icr1 = apic_read(APIC_ICR);
163
164 return (icr1 | ((u64)icr2 << 32));
165}
166
167static struct apic_ops xapic_ops = {
168 .read = native_apic_mem_read,
169 .write = native_apic_mem_write,
170 .icr_read = xapic_icr_read,
171 .icr_write = xapic_icr_write,
172 .wait_icr_idle = xapic_wait_icr_idle,
173 .safe_wait_icr_idle = safe_xapic_wait_icr_idle,
174};
175
176struct apic_ops __read_mostly *apic_ops = &xapic_ops;
177
178EXPORT_SYMBOL_GPL(apic_ops);
179
180static void x2apic_wait_icr_idle(void)
181{
182 /* no need to wait for icr idle in x2apic */
183 return;
184}
185
186static u32 safe_x2apic_wait_icr_idle(void)
187{
188 /* no need to wait for icr idle in x2apic */
189 return 0;
190}
191
192void x2apic_icr_write(u32 low, u32 id)
193{
194 wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low);
195}
196
197u64 x2apic_icr_read(void)
198{
199 unsigned long val;
200
201 rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val);
202 return val;
203}
204
205static struct apic_ops x2apic_ops = {
206 .read = native_apic_msr_read,
207 .write = native_apic_msr_write,
208 .icr_read = x2apic_icr_read,
209 .icr_write = x2apic_icr_write,
210 .wait_icr_idle = x2apic_wait_icr_idle,
211 .safe_wait_icr_idle = safe_x2apic_wait_icr_idle,
212};
213
144/** 214/**
145 * enable_NMI_through_LVT0 - enable NMI through local vector table 0 215 * enable_NMI_through_LVT0 - enable NMI through local vector table 0
146 */ 216 */
@@ -638,10 +708,10 @@ int __init verify_local_APIC(void)
638 /* 708 /*
639 * The ID register is read/write in a real APIC. 709 * The ID register is read/write in a real APIC.
640 */ 710 */
641 reg0 = read_apic_id(); 711 reg0 = apic_read(APIC_ID);
642 apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); 712 apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
643 apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); 713 apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
644 reg1 = read_apic_id(); 714 reg1 = apic_read(APIC_ID);
645 apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); 715 apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
646 apic_write(APIC_ID, reg0); 716 apic_write(APIC_ID, reg0);
647 if (reg1 != (reg0 ^ APIC_ID_MASK)) 717 if (reg1 != (reg0 ^ APIC_ID_MASK))
@@ -842,6 +912,125 @@ void __cpuinit end_local_APIC_setup(void)
842 apic_pm_activate(); 912 apic_pm_activate();
843} 913}
844 914
915void check_x2apic(void)
916{
917 int msr, msr2;
918
919 rdmsr(MSR_IA32_APICBASE, msr, msr2);
920
921 if (msr & X2APIC_ENABLE) {
922 printk("x2apic enabled by BIOS, switching to x2apic ops\n");
923 x2apic_preenabled = x2apic = 1;
924 apic_ops = &x2apic_ops;
925 }
926}
927
928void enable_x2apic(void)
929{
930 int msr, msr2;
931
932 rdmsr(MSR_IA32_APICBASE, msr, msr2);
933 if (!(msr & X2APIC_ENABLE)) {
934 printk("Enabling x2apic\n");
935 wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
936 }
937}
938
939void enable_IR_x2apic(void)
940{
941#ifdef CONFIG_INTR_REMAP
942 int ret;
943 unsigned long flags;
944
945 if (!cpu_has_x2apic)
946 return;
947
948 if (!x2apic_preenabled && disable_x2apic) {
949 printk(KERN_INFO
950 "Skipped enabling x2apic and Interrupt-remapping "
951 "because of nox2apic\n");
952 return;
953 }
954
955 if (x2apic_preenabled && disable_x2apic)
956 panic("Bios already enabled x2apic, can't enforce nox2apic");
957
958 if (!x2apic_preenabled && skip_ioapic_setup) {
959 printk(KERN_INFO
960 "Skipped enabling x2apic and Interrupt-remapping "
961 "because of skipping io-apic setup\n");
962 return;
963 }
964
965 ret = dmar_table_init();
966 if (ret) {
967 printk(KERN_INFO
968 "dmar_table_init() failed with %d:\n", ret);
969
970 if (x2apic_preenabled)
971 panic("x2apic enabled by bios. But IR enabling failed");
972 else
973 printk(KERN_INFO
974 "Not enabling x2apic,Intr-remapping\n");
975 return;
976 }
977
978 local_irq_save(flags);
979 mask_8259A();
980 save_mask_IO_APIC_setup();
981
982 ret = enable_intr_remapping(1);
983
984 if (ret && x2apic_preenabled) {
985 local_irq_restore(flags);
986 panic("x2apic enabled by bios. But IR enabling failed");
987 }
988
989 if (ret)
990 goto end;
991
992 if (!x2apic) {
993 x2apic = 1;
994 apic_ops = &x2apic_ops;
995 enable_x2apic();
996 }
997end:
998 if (ret)
999 /*
1000 * IR enabling failed
1001 */
1002 restore_IO_APIC_setup();
1003 else
1004 reinit_intr_remapped_IO_APIC(x2apic_preenabled);
1005
1006 unmask_8259A();
1007 local_irq_restore(flags);
1008
1009 if (!ret) {
1010 if (!x2apic_preenabled)
1011 printk(KERN_INFO
1012 "Enabled x2apic and interrupt-remapping\n");
1013 else
1014 printk(KERN_INFO
1015 "Enabled Interrupt-remapping\n");
1016 } else
1017 printk(KERN_ERR
1018 "Failed to enable Interrupt-remapping and x2apic\n");
1019#else
1020 if (!cpu_has_x2apic)
1021 return;
1022
1023 if (x2apic_preenabled)
1024 panic("x2apic enabled prior OS handover,"
1025 " enable CONFIG_INTR_REMAP");
1026
1027 printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
1028 " and x2apic\n");
1029#endif
1030
1031 return;
1032}
1033
845/* 1034/*
846 * Detect and enable local APICs on non-SMP boards. 1035 * Detect and enable local APICs on non-SMP boards.
847 * Original code written by Keir Fraser. 1036 * Original code written by Keir Fraser.
@@ -881,7 +1070,7 @@ void __init early_init_lapic_mapping(void)
881 * Fetch the APIC ID of the BSP in case we have a 1070 * Fetch the APIC ID of the BSP in case we have a
882 * default configuration (or the MP table is broken). 1071 * default configuration (or the MP table is broken).
883 */ 1072 */
884 boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); 1073 boot_cpu_physical_apicid = read_apic_id();
885} 1074}
886 1075
887/** 1076/**
@@ -889,6 +1078,11 @@ void __init early_init_lapic_mapping(void)
889 */ 1078 */
890void __init init_apic_mappings(void) 1079void __init init_apic_mappings(void)
891{ 1080{
1081 if (x2apic) {
1082 boot_cpu_physical_apicid = read_apic_id();
1083 return;
1084 }
1085
892 /* 1086 /*
893 * If no local APIC can be found then set up a fake all 1087 * If no local APIC can be found then set up a fake all
894 * zeroes page to simulate the local APIC and another 1088 * zeroes page to simulate the local APIC and another
@@ -908,7 +1102,7 @@ void __init init_apic_mappings(void)
908 * Fetch the APIC ID of the BSP in case we have a 1102 * Fetch the APIC ID of the BSP in case we have a
909 * default configuration (or the MP table is broken). 1103 * default configuration (or the MP table is broken).
910 */ 1104 */
911 boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); 1105 boot_cpu_physical_apicid = read_apic_id();
912} 1106}
913 1107
914/* 1108/*
@@ -927,6 +1121,9 @@ int __init APIC_init_uniprocessor(void)
927 return -1; 1121 return -1;
928 } 1122 }
929 1123
1124 enable_IR_x2apic();
1125 setup_apic_routing();
1126
930 verify_local_APIC(); 1127 verify_local_APIC();
931 1128
932 connect_bsp_APIC(); 1129 connect_bsp_APIC();
@@ -1108,6 +1305,11 @@ void __cpuinit generic_processor_info(int apicid, int version)
1108 cpu_set(cpu, cpu_present_map); 1305 cpu_set(cpu, cpu_present_map);
1109} 1306}
1110 1307
1308int hard_smp_processor_id(void)
1309{
1310 return read_apic_id();
1311}
1312
1111/* 1313/*
1112 * Power management 1314 * Power management
1113 */ 1315 */
@@ -1144,7 +1346,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
1144 1346
1145 maxlvt = lapic_get_maxlvt(); 1347 maxlvt = lapic_get_maxlvt();
1146 1348
1147 apic_pm_state.apic_id = read_apic_id(); 1349 apic_pm_state.apic_id = apic_read(APIC_ID);
1148 apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); 1350 apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
1149 apic_pm_state.apic_ldr = apic_read(APIC_LDR); 1351 apic_pm_state.apic_ldr = apic_read(APIC_LDR);
1150 apic_pm_state.apic_dfr = apic_read(APIC_DFR); 1352 apic_pm_state.apic_dfr = apic_read(APIC_DFR);
@@ -1179,10 +1381,14 @@ static int lapic_resume(struct sys_device *dev)
1179 maxlvt = lapic_get_maxlvt(); 1381 maxlvt = lapic_get_maxlvt();
1180 1382
1181 local_irq_save(flags); 1383 local_irq_save(flags);
1182 rdmsr(MSR_IA32_APICBASE, l, h); 1384 if (!x2apic) {
1183 l &= ~MSR_IA32_APICBASE_BASE; 1385 rdmsr(MSR_IA32_APICBASE, l, h);
1184 l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; 1386 l &= ~MSR_IA32_APICBASE_BASE;
1185 wrmsr(MSR_IA32_APICBASE, l, h); 1387 l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
1388 wrmsr(MSR_IA32_APICBASE, l, h);
1389 } else
1390 enable_x2apic();
1391
1186 apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); 1392 apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
1187 apic_write(APIC_ID, apic_pm_state.apic_id); 1393 apic_write(APIC_ID, apic_pm_state.apic_id);
1188 apic_write(APIC_DFR, apic_pm_state.apic_dfr); 1394 apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -1322,6 +1528,15 @@ __cpuinit int apic_is_clustered_box(void)
1322 return (clusters > 2); 1528 return (clusters > 2);
1323} 1529}
1324 1530
1531static __init int setup_nox2apic(char *str)
1532{
1533 disable_x2apic = 1;
1534 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
1535 return 0;
1536}
1537early_param("nox2apic", setup_nox2apic);
1538
1539
1325/* 1540/*
1326 * APIC command line parameters 1541 * APIC command line parameters
1327 */ 1542 */