diff options
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r-- | arch/x86/kernel/smpboot.c | 138 |
1 files changed, 38 insertions, 100 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 249334f5080a..58d24ef917d8 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -101,11 +101,11 @@ EXPORT_SYMBOL(smp_num_siblings); | |||
101 | DEFINE_PER_CPU(u16, cpu_llc_id) = BAD_APICID; | 101 | DEFINE_PER_CPU(u16, cpu_llc_id) = BAD_APICID; |
102 | 102 | ||
103 | /* representing HT siblings of each logical CPU */ | 103 | /* representing HT siblings of each logical CPU */ |
104 | DEFINE_PER_CPU(cpumask_t, cpu_sibling_map); | 104 | DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); |
105 | EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); | 105 | EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); |
106 | 106 | ||
107 | /* representing HT and core siblings of each logical CPU */ | 107 | /* representing HT and core siblings of each logical CPU */ |
108 | DEFINE_PER_CPU(cpumask_t, cpu_core_map); | 108 | DEFINE_PER_CPU(cpumask_var_t, cpu_core_map); |
109 | EXPORT_PER_CPU_SYMBOL(cpu_core_map); | 109 | EXPORT_PER_CPU_SYMBOL(cpu_core_map); |
110 | 110 | ||
111 | /* Per CPU bogomips and other parameters */ | 111 | /* Per CPU bogomips and other parameters */ |
@@ -114,16 +114,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); | |||
114 | 114 | ||
115 | atomic_t init_deasserted; | 115 | atomic_t init_deasserted; |
116 | 116 | ||
117 | |||
118 | /* Set if we find a B stepping CPU */ | ||
119 | static int __cpuinitdata smp_b_stepping; | ||
120 | |||
121 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_32) | 117 | #if defined(CONFIG_NUMA) && defined(CONFIG_X86_32) |
122 | |||
123 | /* which logical CPUs are on which nodes */ | ||
124 | cpumask_t node_to_cpumask_map[MAX_NUMNODES] __read_mostly = | ||
125 | { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; | ||
126 | EXPORT_SYMBOL(node_to_cpumask_map); | ||
127 | /* which node each logical CPU is on */ | 118 | /* which node each logical CPU is on */ |
128 | int cpu_to_node_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 }; | 119 | int cpu_to_node_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 }; |
129 | EXPORT_SYMBOL(cpu_to_node_map); | 120 | EXPORT_SYMBOL(cpu_to_node_map); |
@@ -132,7 +123,7 @@ EXPORT_SYMBOL(cpu_to_node_map); | |||
132 | static void map_cpu_to_node(int cpu, int node) | 123 | static void map_cpu_to_node(int cpu, int node) |
133 | { | 124 | { |
134 | printk(KERN_INFO "Mapping cpu %d to node %d\n", cpu, node); | 125 | printk(KERN_INFO "Mapping cpu %d to node %d\n", cpu, node); |
135 | cpumask_set_cpu(cpu, &node_to_cpumask_map[node]); | 126 | cpumask_set_cpu(cpu, node_to_cpumask_map[node]); |
136 | cpu_to_node_map[cpu] = node; | 127 | cpu_to_node_map[cpu] = node; |
137 | } | 128 | } |
138 | 129 | ||
@@ -143,7 +134,7 @@ static void unmap_cpu_to_node(int cpu) | |||
143 | 134 | ||
144 | printk(KERN_INFO "Unmapping cpu %d from all nodes\n", cpu); | 135 | printk(KERN_INFO "Unmapping cpu %d from all nodes\n", cpu); |
145 | for (node = 0; node < MAX_NUMNODES; node++) | 136 | for (node = 0; node < MAX_NUMNODES; node++) |
146 | cpumask_clear_cpu(cpu, &node_to_cpumask_map[node]); | 137 | cpumask_clear_cpu(cpu, node_to_cpumask_map[node]); |
147 | cpu_to_node_map[cpu] = 0; | 138 | cpu_to_node_map[cpu] = 0; |
148 | } | 139 | } |
149 | #else /* !(CONFIG_NUMA && CONFIG_X86_32) */ | 140 | #else /* !(CONFIG_NUMA && CONFIG_X86_32) */ |
@@ -271,8 +262,6 @@ static void __cpuinit smp_callin(void) | |||
271 | cpumask_set_cpu(cpuid, cpu_callin_mask); | 262 | cpumask_set_cpu(cpuid, cpu_callin_mask); |
272 | } | 263 | } |
273 | 264 | ||
274 | static int __cpuinitdata unsafe_smp; | ||
275 | |||
276 | /* | 265 | /* |
277 | * Activate a secondary processor. | 266 | * Activate a secondary processor. |
278 | */ | 267 | */ |
@@ -307,7 +296,7 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
307 | __flush_tlb_all(); | 296 | __flush_tlb_all(); |
308 | #endif | 297 | #endif |
309 | 298 | ||
310 | /* This must be done before setting cpu_online_map */ | 299 | /* This must be done before setting cpu_online_mask */ |
311 | set_cpu_sibling_map(raw_smp_processor_id()); | 300 | set_cpu_sibling_map(raw_smp_processor_id()); |
312 | wmb(); | 301 | wmb(); |
313 | 302 | ||
@@ -340,75 +329,22 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
340 | cpu_idle(); | 329 | cpu_idle(); |
341 | } | 330 | } |
342 | 331 | ||
343 | static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c) | 332 | #ifdef CONFIG_CPUMASK_OFFSTACK |
333 | /* In this case, llc_shared_map is a pointer to a cpumask. */ | ||
334 | static inline void copy_cpuinfo_x86(struct cpuinfo_x86 *dst, | ||
335 | const struct cpuinfo_x86 *src) | ||
344 | { | 336 | { |
345 | /* | 337 | struct cpumask *llc = dst->llc_shared_map; |
346 | * Mask B, Pentium, but not Pentium MMX | 338 | *dst = *src; |
347 | */ | 339 | dst->llc_shared_map = llc; |
348 | if (c->x86_vendor == X86_VENDOR_INTEL && | ||
349 | c->x86 == 5 && | ||
350 | c->x86_mask >= 1 && c->x86_mask <= 4 && | ||
351 | c->x86_model <= 3) | ||
352 | /* | ||
353 | * Remember we have B step Pentia with bugs | ||
354 | */ | ||
355 | smp_b_stepping = 1; | ||
356 | |||
357 | /* | ||
358 | * Certain Athlons might work (for various values of 'work') in SMP | ||
359 | * but they are not certified as MP capable. | ||
360 | */ | ||
361 | if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) { | ||
362 | |||
363 | if (num_possible_cpus() == 1) | ||
364 | goto valid_k7; | ||
365 | |||
366 | /* Athlon 660/661 is valid. */ | ||
367 | if ((c->x86_model == 6) && ((c->x86_mask == 0) || | ||
368 | (c->x86_mask == 1))) | ||
369 | goto valid_k7; | ||
370 | |||
371 | /* Duron 670 is valid */ | ||
372 | if ((c->x86_model == 7) && (c->x86_mask == 0)) | ||
373 | goto valid_k7; | ||
374 | |||
375 | /* | ||
376 | * Athlon 662, Duron 671, and Athlon >model 7 have capability | ||
377 | * bit. It's worth noting that the A5 stepping (662) of some | ||
378 | * Athlon XP's have the MP bit set. | ||
379 | * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for | ||
380 | * more. | ||
381 | */ | ||
382 | if (((c->x86_model == 6) && (c->x86_mask >= 2)) || | ||
383 | ((c->x86_model == 7) && (c->x86_mask >= 1)) || | ||
384 | (c->x86_model > 7)) | ||
385 | if (cpu_has_mp) | ||
386 | goto valid_k7; | ||
387 | |||
388 | /* If we get here, not a certified SMP capable AMD system. */ | ||
389 | unsafe_smp = 1; | ||
390 | } | ||
391 | |||
392 | valid_k7: | ||
393 | ; | ||
394 | } | 340 | } |
395 | 341 | #else | |
396 | static void __cpuinit smp_checks(void) | 342 | static inline void copy_cpuinfo_x86(struct cpuinfo_x86 *dst, |
343 | const struct cpuinfo_x86 *src) | ||
397 | { | 344 | { |
398 | if (smp_b_stepping) | 345 | *dst = *src; |
399 | printk(KERN_WARNING "WARNING: SMP operation may be unreliable" | ||
400 | "with B stepping processors.\n"); | ||
401 | |||
402 | /* | ||
403 | * Don't taint if we are running SMP kernel on a single non-MP | ||
404 | * approved Athlon | ||
405 | */ | ||
406 | if (unsafe_smp && num_online_cpus() > 1) { | ||
407 | printk(KERN_INFO "WARNING: This combination of AMD" | ||
408 | "processors is not suitable for SMP.\n"); | ||
409 | add_taint(TAINT_UNSAFE_SMP); | ||
410 | } | ||
411 | } | 346 | } |
347 | #endif /* CONFIG_CPUMASK_OFFSTACK */ | ||
412 | 348 | ||
413 | /* | 349 | /* |
414 | * The bootstrap kernel entry code has set these up. Save them for | 350 | * The bootstrap kernel entry code has set these up. Save them for |
@@ -419,11 +355,10 @@ void __cpuinit smp_store_cpu_info(int id) | |||
419 | { | 355 | { |
420 | struct cpuinfo_x86 *c = &cpu_data(id); | 356 | struct cpuinfo_x86 *c = &cpu_data(id); |
421 | 357 | ||
422 | *c = boot_cpu_data; | 358 | copy_cpuinfo_x86(c, &boot_cpu_data); |
423 | c->cpu_index = id; | 359 | c->cpu_index = id; |
424 | if (id != 0) | 360 | if (id != 0) |
425 | identify_secondary_cpu(c); | 361 | identify_secondary_cpu(c); |
426 | smp_apply_quirks(c); | ||
427 | } | 362 | } |
428 | 363 | ||
429 | 364 | ||
@@ -444,15 +379,15 @@ void __cpuinit set_cpu_sibling_map(int cpu) | |||
444 | cpumask_set_cpu(cpu, cpu_sibling_mask(i)); | 379 | cpumask_set_cpu(cpu, cpu_sibling_mask(i)); |
445 | cpumask_set_cpu(i, cpu_core_mask(cpu)); | 380 | cpumask_set_cpu(i, cpu_core_mask(cpu)); |
446 | cpumask_set_cpu(cpu, cpu_core_mask(i)); | 381 | cpumask_set_cpu(cpu, cpu_core_mask(i)); |
447 | cpumask_set_cpu(i, &c->llc_shared_map); | 382 | cpumask_set_cpu(i, c->llc_shared_map); |
448 | cpumask_set_cpu(cpu, &o->llc_shared_map); | 383 | cpumask_set_cpu(cpu, o->llc_shared_map); |
449 | } | 384 | } |
450 | } | 385 | } |
451 | } else { | 386 | } else { |
452 | cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); | 387 | cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); |
453 | } | 388 | } |
454 | 389 | ||
455 | cpumask_set_cpu(cpu, &c->llc_shared_map); | 390 | cpumask_set_cpu(cpu, c->llc_shared_map); |
456 | 391 | ||
457 | if (current_cpu_data.x86_max_cores == 1) { | 392 | if (current_cpu_data.x86_max_cores == 1) { |
458 | cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu)); | 393 | cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu)); |
@@ -463,8 +398,8 @@ void __cpuinit set_cpu_sibling_map(int cpu) | |||
463 | for_each_cpu(i, cpu_sibling_setup_mask) { | 398 | for_each_cpu(i, cpu_sibling_setup_mask) { |
464 | if (per_cpu(cpu_llc_id, cpu) != BAD_APICID && | 399 | if (per_cpu(cpu_llc_id, cpu) != BAD_APICID && |
465 | per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) { | 400 | per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) { |
466 | cpumask_set_cpu(i, &c->llc_shared_map); | 401 | cpumask_set_cpu(i, c->llc_shared_map); |
467 | cpumask_set_cpu(cpu, &cpu_data(i).llc_shared_map); | 402 | cpumask_set_cpu(cpu, cpu_data(i).llc_shared_map); |
468 | } | 403 | } |
469 | if (c->phys_proc_id == cpu_data(i).phys_proc_id) { | 404 | if (c->phys_proc_id == cpu_data(i).phys_proc_id) { |
470 | cpumask_set_cpu(i, cpu_core_mask(cpu)); | 405 | cpumask_set_cpu(i, cpu_core_mask(cpu)); |
@@ -502,12 +437,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu) | |||
502 | if (sched_mc_power_savings || sched_smt_power_savings) | 437 | if (sched_mc_power_savings || sched_smt_power_savings) |
503 | return cpu_core_mask(cpu); | 438 | return cpu_core_mask(cpu); |
504 | else | 439 | else |
505 | return &c->llc_shared_map; | 440 | return c->llc_shared_map; |
506 | } | ||
507 | |||
508 | cpumask_t cpu_coregroup_map(int cpu) | ||
509 | { | ||
510 | return *cpu_coregroup_mask(cpu); | ||
511 | } | 441 | } |
512 | 442 | ||
513 | static void impress_friends(void) | 443 | static void impress_friends(void) |
@@ -974,9 +904,8 @@ int __cpuinit native_cpu_up(unsigned int cpu) | |||
974 | */ | 904 | */ |
975 | static __init void disable_smp(void) | 905 | static __init void disable_smp(void) |
976 | { | 906 | { |
977 | /* use the read/write pointers to the present and possible maps */ | 907 | init_cpu_present(cpumask_of(0)); |
978 | cpumask_copy(&cpu_present_map, cpumask_of(0)); | 908 | init_cpu_possible(cpumask_of(0)); |
979 | cpumask_copy(&cpu_possible_map, cpumask_of(0)); | ||
980 | smpboot_clear_io_apic_irqs(); | 909 | smpboot_clear_io_apic_irqs(); |
981 | 910 | ||
982 | if (smp_found_config) | 911 | if (smp_found_config) |
@@ -1108,6 +1037,8 @@ static void __init smp_cpu_index_default(void) | |||
1108 | */ | 1037 | */ |
1109 | void __init native_smp_prepare_cpus(unsigned int max_cpus) | 1038 | void __init native_smp_prepare_cpus(unsigned int max_cpus) |
1110 | { | 1039 | { |
1040 | unsigned int i; | ||
1041 | |||
1111 | preempt_disable(); | 1042 | preempt_disable(); |
1112 | smp_cpu_index_default(); | 1043 | smp_cpu_index_default(); |
1113 | current_cpu_data = boot_cpu_data; | 1044 | current_cpu_data = boot_cpu_data; |
@@ -1121,6 +1052,14 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) | |||
1121 | boot_cpu_logical_apicid = logical_smp_processor_id(); | 1052 | boot_cpu_logical_apicid = logical_smp_processor_id(); |
1122 | #endif | 1053 | #endif |
1123 | current_thread_info()->cpu = 0; /* needed? */ | 1054 | current_thread_info()->cpu = 0; /* needed? */ |
1055 | for_each_possible_cpu(i) { | ||
1056 | alloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL); | ||
1057 | alloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL); | ||
1058 | alloc_cpumask_var(&cpu_data(i).llc_shared_map, GFP_KERNEL); | ||
1059 | cpumask_clear(per_cpu(cpu_core_map, i)); | ||
1060 | cpumask_clear(per_cpu(cpu_sibling_map, i)); | ||
1061 | cpumask_clear(cpu_data(i).llc_shared_map); | ||
1062 | } | ||
1124 | set_cpu_sibling_map(0); | 1063 | set_cpu_sibling_map(0); |
1125 | 1064 | ||
1126 | enable_IR_x2apic(); | 1065 | enable_IR_x2apic(); |
@@ -1193,7 +1132,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus) | |||
1193 | pr_debug("Boot done.\n"); | 1132 | pr_debug("Boot done.\n"); |
1194 | 1133 | ||
1195 | impress_friends(); | 1134 | impress_friends(); |
1196 | smp_checks(); | ||
1197 | #ifdef CONFIG_X86_IO_APIC | 1135 | #ifdef CONFIG_X86_IO_APIC |
1198 | setup_ioapic_dest(); | 1136 | setup_ioapic_dest(); |
1199 | #endif | 1137 | #endif |
@@ -1210,11 +1148,11 @@ early_param("possible_cpus", _setup_possible_cpus); | |||
1210 | 1148 | ||
1211 | 1149 | ||
1212 | /* | 1150 | /* |
1213 | * cpu_possible_map should be static, it cannot change as cpu's | 1151 | * cpu_possible_mask should be static, it cannot change as cpu's |
1214 | * are onlined, or offlined. The reason is per-cpu data-structures | 1152 | * are onlined, or offlined. The reason is per-cpu data-structures |
1215 | * are allocated by some modules at init time, and dont expect to | 1153 | * are allocated by some modules at init time, and dont expect to |
1216 | * do this dynamically on cpu arrival/departure. | 1154 | * do this dynamically on cpu arrival/departure. |
1217 | * cpu_present_map on the other hand can change dynamically. | 1155 | * cpu_present_mask on the other hand can change dynamically. |
1218 | * In case when cpu_hotplug is not compiled, then we resort to current | 1156 | * In case when cpu_hotplug is not compiled, then we resort to current |
1219 | * behaviour, which is cpu_possible == cpu_present. | 1157 | * behaviour, which is cpu_possible == cpu_present. |
1220 | * - Ashok Raj | 1158 | * - Ashok Raj |