diff options
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 446c062e831c..b6256587f99e 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 | */ |
@@ -629,10 +699,10 @@ int __init verify_local_APIC(void) | |||
629 | /* | 699 | /* |
630 | * The ID register is read/write in a real APIC. | 700 | * The ID register is read/write in a real APIC. |
631 | */ | 701 | */ |
632 | reg0 = read_apic_id(); | 702 | reg0 = apic_read(APIC_ID); |
633 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); | 703 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); |
634 | apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); | 704 | apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); |
635 | reg1 = read_apic_id(); | 705 | reg1 = apic_read(APIC_ID); |
636 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); | 706 | apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); |
637 | apic_write(APIC_ID, reg0); | 707 | apic_write(APIC_ID, reg0); |
638 | if (reg1 != (reg0 ^ APIC_ID_MASK)) | 708 | if (reg1 != (reg0 ^ APIC_ID_MASK)) |
@@ -833,6 +903,125 @@ void __cpuinit end_local_APIC_setup(void) | |||
833 | apic_pm_activate(); | 903 | apic_pm_activate(); |
834 | } | 904 | } |
835 | 905 | ||
906 | void check_x2apic(void) | ||
907 | { | ||
908 | int msr, msr2; | ||
909 | |||
910 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
911 | |||
912 | if (msr & X2APIC_ENABLE) { | ||
913 | printk("x2apic enabled by BIOS, switching to x2apic ops\n"); | ||
914 | x2apic_preenabled = x2apic = 1; | ||
915 | apic_ops = &x2apic_ops; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | void enable_x2apic(void) | ||
920 | { | ||
921 | int msr, msr2; | ||
922 | |||
923 | rdmsr(MSR_IA32_APICBASE, msr, msr2); | ||
924 | if (!(msr & X2APIC_ENABLE)) { | ||
925 | printk("Enabling x2apic\n"); | ||
926 | wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); | ||
927 | } | ||
928 | } | ||
929 | |||
930 | void enable_IR_x2apic(void) | ||
931 | { | ||
932 | #ifdef CONFIG_INTR_REMAP | ||
933 | int ret; | ||
934 | unsigned long flags; | ||
935 | |||
936 | if (!cpu_has_x2apic) | ||
937 | return; | ||
938 | |||
939 | if (!x2apic_preenabled && disable_x2apic) { | ||
940 | printk(KERN_INFO | ||
941 | "Skipped enabling x2apic and Interrupt-remapping " | ||
942 | "because of nox2apic\n"); | ||
943 | return; | ||
944 | } | ||
945 | |||
946 | if (x2apic_preenabled && disable_x2apic) | ||
947 | panic("Bios already enabled x2apic, can't enforce nox2apic"); | ||
948 | |||
949 | if (!x2apic_preenabled && skip_ioapic_setup) { | ||
950 | printk(KERN_INFO | ||
951 | "Skipped enabling x2apic and Interrupt-remapping " | ||
952 | "because of skipping io-apic setup\n"); | ||
953 | return; | ||
954 | } | ||
955 | |||
956 | ret = dmar_table_init(); | ||
957 | if (ret) { | ||
958 | printk(KERN_INFO | ||
959 | "dmar_table_init() failed with %d:\n", ret); | ||
960 | |||
961 | if (x2apic_preenabled) | ||
962 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
963 | else | ||
964 | printk(KERN_INFO | ||
965 | "Not enabling x2apic,Intr-remapping\n"); | ||
966 | return; | ||
967 | } | ||
968 | |||
969 | local_irq_save(flags); | ||
970 | mask_8259A(); | ||
971 | save_mask_IO_APIC_setup(); | ||
972 | |||
973 | ret = enable_intr_remapping(1); | ||
974 | |||
975 | if (ret && x2apic_preenabled) { | ||
976 | local_irq_restore(flags); | ||
977 | panic("x2apic enabled by bios. But IR enabling failed"); | ||
978 | } | ||
979 | |||
980 | if (ret) | ||
981 | goto end; | ||
982 | |||
983 | if (!x2apic) { | ||
984 | x2apic = 1; | ||
985 | apic_ops = &x2apic_ops; | ||
986 | enable_x2apic(); | ||
987 | } | ||
988 | end: | ||
989 | if (ret) | ||
990 | /* | ||
991 | * IR enabling failed | ||
992 | */ | ||
993 | restore_IO_APIC_setup(); | ||
994 | else | ||
995 | reinit_intr_remapped_IO_APIC(x2apic_preenabled); | ||
996 | |||
997 | unmask_8259A(); | ||
998 | local_irq_restore(flags); | ||
999 | |||
1000 | if (!ret) { | ||
1001 | if (!x2apic_preenabled) | ||
1002 | printk(KERN_INFO | ||
1003 | "Enabled x2apic and interrupt-remapping\n"); | ||
1004 | else | ||
1005 | printk(KERN_INFO | ||
1006 | "Enabled Interrupt-remapping\n"); | ||
1007 | } else | ||
1008 | printk(KERN_ERR | ||
1009 | "Failed to enable Interrupt-remapping and x2apic\n"); | ||
1010 | #else | ||
1011 | if (!cpu_has_x2apic) | ||
1012 | return; | ||
1013 | |||
1014 | if (x2apic_preenabled) | ||
1015 | panic("x2apic enabled prior OS handover," | ||
1016 | " enable CONFIG_INTR_REMAP"); | ||
1017 | |||
1018 | printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " | ||
1019 | " and x2apic\n"); | ||
1020 | #endif | ||
1021 | |||
1022 | return; | ||
1023 | } | ||
1024 | |||
836 | /* | 1025 | /* |
837 | * Detect and enable local APICs on non-SMP boards. | 1026 | * Detect and enable local APICs on non-SMP boards. |
838 | * Original code written by Keir Fraser. | 1027 | * Original code written by Keir Fraser. |
@@ -872,7 +1061,7 @@ void __init early_init_lapic_mapping(void) | |||
872 | * Fetch the APIC ID of the BSP in case we have a | 1061 | * Fetch the APIC ID of the BSP in case we have a |
873 | * default configuration (or the MP table is broken). | 1062 | * default configuration (or the MP table is broken). |
874 | */ | 1063 | */ |
875 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1064 | boot_cpu_physical_apicid = read_apic_id(); |
876 | } | 1065 | } |
877 | 1066 | ||
878 | /** | 1067 | /** |
@@ -880,6 +1069,11 @@ void __init early_init_lapic_mapping(void) | |||
880 | */ | 1069 | */ |
881 | void __init init_apic_mappings(void) | 1070 | void __init init_apic_mappings(void) |
882 | { | 1071 | { |
1072 | if (x2apic) { | ||
1073 | boot_cpu_physical_apicid = read_apic_id(); | ||
1074 | return; | ||
1075 | } | ||
1076 | |||
883 | /* | 1077 | /* |
884 | * If no local APIC can be found then set up a fake all | 1078 | * If no local APIC can be found then set up a fake all |
885 | * zeroes page to simulate the local APIC and another | 1079 | * zeroes page to simulate the local APIC and another |
@@ -899,7 +1093,7 @@ void __init init_apic_mappings(void) | |||
899 | * Fetch the APIC ID of the BSP in case we have a | 1093 | * Fetch the APIC ID of the BSP in case we have a |
900 | * default configuration (or the MP table is broken). | 1094 | * default configuration (or the MP table is broken). |
901 | */ | 1095 | */ |
902 | boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); | 1096 | boot_cpu_physical_apicid = read_apic_id(); |
903 | } | 1097 | } |
904 | 1098 | ||
905 | /* | 1099 | /* |
@@ -918,6 +1112,9 @@ int __init APIC_init_uniprocessor(void) | |||
918 | return -1; | 1112 | return -1; |
919 | } | 1113 | } |
920 | 1114 | ||
1115 | enable_IR_x2apic(); | ||
1116 | setup_apic_routing(); | ||
1117 | |||
921 | verify_local_APIC(); | 1118 | verify_local_APIC(); |
922 | 1119 | ||
923 | connect_bsp_APIC(); | 1120 | connect_bsp_APIC(); |
@@ -1093,6 +1290,11 @@ void __cpuinit generic_processor_info(int apicid, int version) | |||
1093 | cpu_set(cpu, cpu_present_map); | 1290 | cpu_set(cpu, cpu_present_map); |
1094 | } | 1291 | } |
1095 | 1292 | ||
1293 | int hard_smp_processor_id(void) | ||
1294 | { | ||
1295 | return read_apic_id(); | ||
1296 | } | ||
1297 | |||
1096 | /* | 1298 | /* |
1097 | * Power management | 1299 | * Power management |
1098 | */ | 1300 | */ |
@@ -1129,7 +1331,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
1129 | 1331 | ||
1130 | maxlvt = lapic_get_maxlvt(); | 1332 | maxlvt = lapic_get_maxlvt(); |
1131 | 1333 | ||
1132 | apic_pm_state.apic_id = read_apic_id(); | 1334 | apic_pm_state.apic_id = apic_read(APIC_ID); |
1133 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); | 1335 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); |
1134 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); | 1336 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); |
1135 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); | 1337 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); |
@@ -1164,10 +1366,14 @@ static int lapic_resume(struct sys_device *dev) | |||
1164 | maxlvt = lapic_get_maxlvt(); | 1366 | maxlvt = lapic_get_maxlvt(); |
1165 | 1367 | ||
1166 | local_irq_save(flags); | 1368 | local_irq_save(flags); |
1167 | rdmsr(MSR_IA32_APICBASE, l, h); | 1369 | if (!x2apic) { |
1168 | l &= ~MSR_IA32_APICBASE_BASE; | 1370 | rdmsr(MSR_IA32_APICBASE, l, h); |
1169 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; | 1371 | l &= ~MSR_IA32_APICBASE_BASE; |
1170 | wrmsr(MSR_IA32_APICBASE, l, h); | 1372 | l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; |
1373 | wrmsr(MSR_IA32_APICBASE, l, h); | ||
1374 | } else | ||
1375 | enable_x2apic(); | ||
1376 | |||
1171 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); | 1377 | apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); |
1172 | apic_write(APIC_ID, apic_pm_state.apic_id); | 1378 | apic_write(APIC_ID, apic_pm_state.apic_id); |
1173 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); | 1379 | apic_write(APIC_DFR, apic_pm_state.apic_dfr); |
@@ -1307,6 +1513,15 @@ __cpuinit int apic_is_clustered_box(void) | |||
1307 | return (clusters > 2); | 1513 | return (clusters > 2); |
1308 | } | 1514 | } |
1309 | 1515 | ||
1516 | static __init int setup_nox2apic(char *str) | ||
1517 | { | ||
1518 | disable_x2apic = 1; | ||
1519 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC); | ||
1520 | return 0; | ||
1521 | } | ||
1522 | early_param("nox2apic", setup_nox2apic); | ||
1523 | |||
1524 | |||
1310 | /* | 1525 | /* |
1311 | * APIC command line parameters | 1526 | * APIC command line parameters |
1312 | */ | 1527 | */ |