diff options
Diffstat (limited to 'arch/x86/kernel/apic_64.c')
-rw-r--r-- | arch/x86/kernel/apic_64.c | 251 |
1 files changed, 237 insertions, 14 deletions
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 446c062e831c..1a6011855af3 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; |
@@ -118,13 +125,13 @@ static int modern_apic(void) | |||
118 | return lapic_get_version() >= 0x14; | 125 | return lapic_get_version() >= 0x14; |
119 | } | 126 | } |
120 | 127 | ||
121 | void apic_wait_icr_idle(void) | 128 | void xapic_wait_icr_idle(void) |
122 | { | 129 | { |
123 | while (apic_read(APIC_ICR) & APIC_ICR_BUSY) | 130 | while (apic_read(APIC_ICR) & APIC_ICR_BUSY) |
124 | cpu_relax(); | 131 | cpu_relax(); |
125 | } | 132 | } |
126 | 133 | ||
127 | u32 safe_apic_wait_icr_idle(void) | 134 | u32 safe_xapic_wait_icr_idle(void) |
128 | { | 135 | { |
129 | u32 send_status; | 136 | u32 send_status; |
130 | int timeout; | 137 | int timeout; |
@@ -140,6 +147,69 @@ u32 safe_apic_wait_icr_idle(void) | |||
140 | return send_status; | 147 | return send_status; |
141 | } | 148 | } |
142 | 149 | ||
150 | void xapic_icr_write(u32 low, u32 id) | ||
151 | { | ||
152 | apic_write(APIC_ICR2, id << 24); | ||
153 | apic_write(APIC_ICR, low); | ||
154 | } | ||
155 | |||
156 | u64 xapic_icr_read(void) | ||
157 | { | ||
158 | u32 icr1, icr2; | ||
159 | |||
160 | icr2 = apic_read(APIC_ICR2); | ||
161 | icr1 = apic_read(APIC_ICR); | ||
162 | |||
163 | return (icr1 | ((u64)icr2 << 32)); | ||
164 | } | ||
165 | |||
166 | static struct apic_ops xapic_ops = { | ||
167 | .read = native_apic_mem_read, | ||
168 | .write = native_apic_mem_write, | ||
169 | .icr_read = xapic_icr_read, | ||
170 | .icr_write = xapic_icr_write, | ||
171 | .wait_icr_idle = xapic_wait_icr_idle, | ||
172 | .safe_wait_icr_idle = safe_xapic_wait_icr_idle, | ||
173 | }; | ||
174 | |||
175 | struct apic_ops __read_mostly *apic_ops = &xapic_ops; | ||
176 | |||
177 | EXPORT_SYMBOL_GPL(apic_ops); | ||
178 | |||
179 | static void x2apic_wait_icr_idle(void) | ||
180 | { | ||
181 | /* no need to wait for icr idle in x2apic */ | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | static u32 safe_x2apic_wait_icr_idle(void) | ||
186 | { | ||
187 | /* no need to wait for icr idle in x2apic */ | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | void x2apic_icr_write(u32 low, u32 id) | ||
192 | { | ||
193 | wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low); | ||
194 | } | ||
195 | |||
196 | u64 x2apic_icr_read(void) | ||
197 | { | ||
198 | unsigned long val; | ||
199 | |||
200 | rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val); | ||
201 | return val; | ||
202 | } | ||
203 | |||
204 | static struct apic_ops x2apic_ops = { | ||
205 | .read = native_apic_msr_read, | ||
206 | .write = native_apic_msr_write, | ||
207 | .icr_read = x2apic_icr_read, | ||
208 | .icr_write = x2apic_icr_write, | ||
209 | .wait_icr_idle = x2apic_wait_icr_idle, | ||
210 | .safe_wait_icr_idle = safe_x2apic_wait_icr_idle, | ||
211 | }; | ||
212 | |||
143 | /** | 213 | /** |
144 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 | 214 | * enable_NMI_through_LVT0 - enable NMI through local vector table 0 |
145 | */ | 215 | */ |
@@ -149,6 +219,11 @@ void __cpuinit enable_NMI_through_LVT0(void) | |||
149 | 219 | ||
150 | /* unmask and set to NMI */ | 220 | /* unmask and set to NMI */ |
151 | v = APIC_DM_NMI; | 221 | v = APIC_DM_NMI; |
222 | |||
223 | /* Level triggered for 82489DX (32bit mode) */ | ||
224 | if (!lapic_is_integrated()) | ||
225 | v |= APIC_LVT_LEVEL_TRIGGER; | ||
226 | |||
152 | apic_write(APIC_LVT0, v); | 227 | apic_write(APIC_LVT0, v); |
153 | } | 228 | } |
154 | 229 | ||
@@ -157,11 +232,14 @@ void __cpuinit enable_NMI_through_LVT0(void) | |||
157 | */ | 232 | */ |
158 | int lapic_get_maxlvt(void) | 233 | int lapic_get_maxlvt(void) |
159 | { | 234 | { |
160 | unsigned int v, maxlvt; | 235 | unsigned int v; |
161 | 236 | ||
162 | v = apic_read(APIC_LVR); | 237 | v = apic_read(APIC_LVR); |
163 | maxlvt = GET_APIC_MAXLVT(v); | 238 | /* |
164 | return maxlvt; | 239 | * - we always have APIC integrated on 64bit mode |
240 | * - 82489DXs do not report # of LVT entries | ||
241 | */ | ||
242 | return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2; | ||
165 | } | 243 | } |
166 | 244 | ||
167 | /* | 245 | /* |
@@ -629,10 +707,10 @@ int __init verify_local_APIC(void) | |||
629 | /* | 707 | /* |
630 | * The ID register is read/write in a real APIC. | 708 | * The ID register is read/write in a real APIC. |
631 | */ | 709 | */ |
632 | reg0 = read_apic_id(); | 710 | reg0 = apic_read(APIC_ID); |
633 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); | 711 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); |
634 | apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); | 712 | apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); |
635 | reg1 = read_apic_id(); | 713 | reg1 = apic_read(APIC_ID); |
636 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); | 714 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); |
637 | apic_write(APIC_ID, reg0); | 715 | apic_write(APIC_ID, reg0); |
638 | if (reg1 != (reg0 ^ APIC_ID_MASK)) | 716 | if (reg1 != (reg0 ^ APIC_ID_MASK)) |
@@ -833,6 +911,125 @@ void __cpuinit end_local_APIC_setup(void) | |||
833 | apic_pm_activate(); | 911 | apic_pm_activate(); |
834 | } | 912 | } |
835 | 913 | ||
914 | void check_x2apic(void) | ||
915 | { | ||
916 | int msr, msr2; | ||
917 | |||
918 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
919 | |||
920 | if (msr & X2APIC_ENABLE) { | ||
921 | printk("x2apic enabled by BIOS, switching to x2apic ops\n"); | ||
922 | x2apic_preenabled = x2apic = 1; | ||
923 | apic_ops = &x2apic_ops; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | void enable_x2apic(void) | ||
928 | { | ||
929 | int msr, msr2; | ||
930 | |||
931 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
932 | if (!(msr & X2APIC_ENABLE)) { | ||
933 | printk("Enabling x2apic\n"); | ||
934 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); | ||
935 | } | ||
936 | } | ||
937 | |||
938 | void enable_IR_x2apic(void) | ||
939 | { | ||
940 | #ifdef CONFIG_INTR_REMAP | ||
941 | int ret; | ||
942 | unsigned long flags; | ||
943 | |||
944 | if (!cpu_has_x2apic) | ||
945 | return; | ||
946 | |||
947 | if (!x2apic_preenabled && disable_x2apic) { | ||
948 | printk(KERN_INFO | ||
949 | "Skipped enabling x2apic and Interrupt-remapping " | ||
950 | "because of nox2apic\n"); | ||
951 | return; | ||
952 | } | ||
953 | |||
954 | if (x2apic_preenabled && disable_x2apic) | ||
955 | panic("Bios already enabled x2apic, can't enforce nox2apic"); | ||
956 | |||
957 | if (!x2apic_preenabled && skip_ioapic_setup) { | ||
958 | printk(KERN_INFO | ||
959 | "Skipped enabling x2apic and Interrupt-remapping " | ||
960 | "because of skipping io-apic setup\n"); | ||
961 | return; | ||
962 | } | ||
963 | |||
964 | ret = dmar_table_init(); | ||
965 | if (ret) { | ||
966 | printk(KERN_INFO | ||
967 | "dmar_table_init() failed with %d:\n", ret); | ||
968 | |||
969 | if (x2apic_preenabled) | ||
970 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
971 | else | ||
972 | printk(KERN_INFO | ||
973 | "Not enabling x2apic,Intr-remapping\n"); | ||
974 | return; | ||
975 | } | ||
976 | |||
977 | local_irq_save(flags); | ||
978 | mask_8259A(); | ||
979 | save_mask_IO_APIC_setup(); | ||
980 | |||
981 | ret = enable_intr_remapping(1); | ||
982 | |||
983 | if (ret && x2apic_preenabled) { | ||
984 | local_irq_restore(flags); | ||
985 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
986 | } | ||
987 | |||
988 | if (ret) | ||
989 | goto end; | ||
990 | |||
991 | if (!x2apic) { | ||
992 | x2apic = 1; | ||
993 | apic_ops = &x2apic_ops; | ||
994 | enable_x2apic(); | ||
995 | } | ||
996 | end: | ||
997 | if (ret) | ||
998 | /* | ||
999 | * IR enabling failed | ||
1000 | */ | ||
1001 | restore_IO_APIC_setup(); | ||
1002 | else | ||
1003 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | ||
1004 | |||
1005 | unmask_8259A(); | ||
1006 | local_irq_restore(flags); | ||
1007 | |||
1008 | if (!ret) { | ||
1009 | if (!x2apic_preenabled) | ||
1010 | printk(KERN_INFO | ||
1011 | "Enabled x2apic and interrupt-remapping\n"); | ||
1012 | else | ||
1013 | printk(KERN_INFO | ||
1014 | "Enabled Interrupt-remapping\n"); | ||
1015 | } else | ||
1016 | printk(KERN_ERR | ||
1017 | "Failed to enable Interrupt-remapping and x2apic\n"); | ||
1018 | #else | ||
1019 | if (!cpu_has_x2apic) | ||
1020 | return; | ||
1021 | |||
1022 | if (x2apic_preenabled) | ||
1023 | panic("x2apic enabled prior OS handover," | ||
1024 | " enable CONFIG_INTR_REMAP"); | ||
1025 | |||
1026 | printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " | ||
1027 | " and x2apic\n"); | ||
1028 | #endif | ||
1029 | |||
1030 | return; | ||
1031 | } | ||
1032 | |||
836 | /* | 1033 | /* |
837 | * Detect and enable local APICs on non-SMP boards. | 1034 | * Detect and enable local APICs on non-SMP boards. |
838 | * Original code written by Keir Fraser. | 1035 | * Original code written by Keir Fraser. |
@@ -872,7 +1069,7 @@ void __init early_init_lapic_mapping(void) | |||
872 | * Fetch the APIC ID of the BSP in case we have a | 1069 | * Fetch the APIC ID of the BSP in case we have a |
873 | * default configuration (or the MP table is broken). | 1070 | * default configuration (or the MP table is broken). |
874 | */ | 1071 | */ |
875 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1072 | boot_cpu_physical_apicid = read_apic_id(); |
876 | } | 1073 | } |
877 | 1074 | ||
878 | /** | 1075 | /** |
@@ -880,6 +1077,11 @@ void __init early_init_lapic_mapping(void) | |||
880 | */ | 1077 | */ |
881 | void __init init_apic_mappings(void) | 1078 | void __init init_apic_mappings(void) |
882 | { | 1079 | { |
1080 | if (x2apic) { | ||
1081 | boot_cpu_physical_apicid = read_apic_id(); | ||
1082 | return; | ||
1083 | } | ||
1084 | |||
883 | /* | 1085 | /* |
884 | * If no local APIC can be found then set up a fake all | 1086 | * If no local APIC can be found then set up a fake all |
885 | * zeroes page to simulate the local APIC and another | 1087 | * zeroes page to simulate the local APIC and another |
@@ -899,7 +1101,7 @@ void __init init_apic_mappings(void) | |||
899 | * Fetch the APIC ID of the BSP in case we have a | 1101 | * Fetch the APIC ID of the BSP in case we have a |
900 | * default configuration (or the MP table is broken). | 1102 | * default configuration (or the MP table is broken). |
901 | */ | 1103 | */ |
902 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1104 | boot_cpu_physical_apicid = read_apic_id(); |
903 | } | 1105 | } |
904 | 1106 | ||
905 | /* | 1107 | /* |
@@ -918,6 +1120,9 @@ int __init APIC_init_uniprocessor(void) | |||
918 | return -1; | 1120 | return -1; |
919 | } | 1121 | } |
920 | 1122 | ||
1123 | enable_IR_x2apic(); | ||
1124 | setup_apic_routing(); | ||
1125 | |||
921 | verify_local_APIC(); | 1126 | verify_local_APIC(); |
922 | 1127 | ||
923 | connect_bsp_APIC(); | 1128 | connect_bsp_APIC(); |
@@ -1093,6 +1298,11 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1093 | cpu_set(cpu, cpu_present_map); | 1298 | cpu_set(cpu, cpu_present_map); |
1094 | } | 1299 | } |
1095 | 1300 | ||
1301 | int hard_smp_processor_id(void) | ||
1302 | { | ||
1303 | return read_apic_id(); | ||
1304 | } | ||
1305 | |||
1096 | /* | 1306 | /* |
1097 | * Power management | 1307 | * Power management |
1098 | */ | 1308 | */ |
@@ -1129,7 +1339,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
1129 | 1339 | ||
1130 | maxlvt = lapic_get_maxlvt(); | 1340 | maxlvt = lapic_get_maxlvt(); |
1131 | 1341 | ||
1132 | apic_pm_state.apic_id = read_apic_id(); | 1342 | apic_pm_state.apic_id = apic_read(APIC_ID); |
1133 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); | 1343 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); |
1134 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); | 1344 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); |
1135 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); | 1345 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); |
@@ -1164,10 +1374,14 @@ static int lapic_resume(struct sys_device *dev) | |||
1164 | maxlvt = lapic_get_maxlvt(); | 1374 | maxlvt = lapic_get_maxlvt(); |
1165 | 1375 | ||
1166 | local_irq_save(flags); | 1376 | local_irq_save(flags); |
1167 | rdmsr(MSR_IA32_APICBASE, l, h); | 1377 | if (!x2apic) { |
1168 | l &= ~MSR_IA32_APICBASE_BASE; | 1378 | rdmsr(MSR_IA32_APICBASE, l, h); |
1169 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; | 1379 | l &= ~MSR_IA32_APICBASE_BASE; |
1170 | wrmsr(MSR_IA32_APICBASE, l, h); | 1380 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; |
1381 | wrmsr(MSR_IA32_APICBASE, l, h); | ||
1382 | } else | ||
1383 | enable_x2apic(); | ||
1384 | |||
1171 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); | 1385 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); |
1172 | apic_write(APIC_ID, apic_pm_state.apic_id); | 1386 | apic_write(APIC_ID, apic_pm_state.apic_id); |
1173 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); | 1387 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); |
@@ -1307,6 +1521,15 @@ __cpuinit int apic_is_clustered_box(void) | |||
1307 | return (clusters > 2); | 1521 | return (clusters > 2); |
1308 | } | 1522 | } |
1309 | 1523 | ||
1524 | static __init int setup_nox2apic(char *str) | ||
1525 | { | ||
1526 | disable_x2apic = 1; | ||
1527 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC); | ||
1528 | return 0; | ||
1529 | } | ||
1530 | early_param("nox2apic", setup_nox2apic); | ||
1531 | |||
1532 | |||
1310 | /* | 1533 | /* |
1311 | * APIC command line parameters | 1534 | * APIC command line parameters |
1312 | */ | 1535 | */ |