diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-08-15 07:46:28 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-15 07:46:28 -0400 |
commit | 5aa37e4f0614e3b1f385426ce1e962e84c275bdf (patch) | |
tree | 3d8c30207989d09fde8ffb2c3c44c6b923d70062 /arch/x86/kernel/apic_64.c | |
parent | d4c63ec060f3315653c0ae5bc3a7fe2419a2282f (diff) | |
parent | b76d69ed721e8365739c3bd5dd7891efbea88494 (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.c | 237 |
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 @@ | |||
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; | ||
52 | int x2apic; | ||
53 | |||
54 | /* x2apic enabled before OS handover */ | ||
55 | int x2apic_preenabled; | ||
49 | 56 | ||
50 | /* Local APIC timer works in C2 */ | 57 | /* Local APIC timer works in C2 */ |
51 | int local_apic_timer_c2_ok; | 58 | int 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 | ||
122 | void apic_wait_icr_idle(void) | 129 | void 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 | ||
128 | u32 safe_apic_wait_icr_idle(void) | 135 | u32 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 | ||
151 | void xapic_icr_write(u32 low, u32 id) | ||
152 | { | ||
153 | apic_write(APIC_ICR2, id << 24); | ||
154 | apic_write(APIC_ICR, low); | ||
155 | } | ||
156 | |||
157 | u64 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 | |||
167 | static 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 | |||
176 | struct apic_ops __read_mostly *apic_ops = &xapic_ops; | ||
177 | |||
178 | EXPORT_SYMBOL_GPL(apic_ops); | ||
179 | |||
180 | static void x2apic_wait_icr_idle(void) | ||
181 | { | ||
182 | /* no need to wait for icr idle in x2apic */ | ||
183 | return; | ||
184 | } | ||
185 | |||
186 | static u32 safe_x2apic_wait_icr_idle(void) | ||
187 | { | ||
188 | /* no need to wait for icr idle in x2apic */ | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | void x2apic_icr_write(u32 low, u32 id) | ||
193 | { | ||
194 | wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low); | ||
195 | } | ||
196 | |||
197 | u64 x2apic_icr_read(void) | ||
198 | { | ||
199 | unsigned long val; | ||
200 | |||
201 | rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val); | ||
202 | return val; | ||
203 | } | ||
204 | |||
205 | static 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 | ||
915 | void 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 | |||
928 | void 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 | |||
939 | void 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 | } | ||
997 | end: | ||
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 | */ |
890 | void __init init_apic_mappings(void) | 1079 | void __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 | ||
1308 | int 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 | ||
1531 | static __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 | } | ||
1537 | early_param("nox2apic", setup_nox2apic); | ||
1538 | |||
1539 | |||
1325 | /* | 1540 | /* |
1326 | * APIC command line parameters | 1541 | * APIC command line parameters |
1327 | */ | 1542 | */ |