aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r--arch/sparc64/kernel/smp.c251
1 files changed, 201 insertions, 50 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 40e40f968d61..b448d33321c6 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -1,6 +1,6 @@
1/* smp.c: Sparc64 SMP support. 1/* smp.c: Sparc64 SMP support.
2 * 2 *
3 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 3 * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
4 */ 4 */
5 5
6#include <linux/module.h> 6#include <linux/module.h>
@@ -28,6 +28,8 @@
28#include <asm/tlbflush.h> 28#include <asm/tlbflush.h>
29#include <asm/mmu_context.h> 29#include <asm/mmu_context.h>
30#include <asm/cpudata.h> 30#include <asm/cpudata.h>
31#include <asm/hvtramp.h>
32#include <asm/io.h>
31 33
32#include <asm/irq.h> 34#include <asm/irq.h>
33#include <asm/irq_regs.h> 35#include <asm/irq_regs.h>
@@ -41,22 +43,26 @@
41#include <asm/sections.h> 43#include <asm/sections.h>
42#include <asm/prom.h> 44#include <asm/prom.h>
43#include <asm/mdesc.h> 45#include <asm/mdesc.h>
46#include <asm/ldc.h>
47#include <asm/hypervisor.h>
44 48
45extern void calibrate_delay(void); 49extern void calibrate_delay(void);
46 50
47int sparc64_multi_core __read_mostly; 51int sparc64_multi_core __read_mostly;
48 52
49/* Please don't make this stuff initdata!!! --DaveM */ 53cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
50unsigned char boot_cpu_id;
51
52cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; 54cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
53cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
54cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = 55cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly =
55 { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; 56 { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
56cpumask_t cpu_core_map[NR_CPUS] __read_mostly = 57cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
57 { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; 58 { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
59
60EXPORT_SYMBOL(cpu_possible_map);
61EXPORT_SYMBOL(cpu_online_map);
62EXPORT_SYMBOL(cpu_sibling_map);
63EXPORT_SYMBOL(cpu_core_map);
64
58static cpumask_t smp_commenced_mask; 65static cpumask_t smp_commenced_mask;
59static cpumask_t cpu_callout_map;
60 66
61void smp_info(struct seq_file *m) 67void smp_info(struct seq_file *m)
62{ 68{
@@ -73,18 +79,17 @@ void smp_bogo(struct seq_file *m)
73 79
74 for_each_online_cpu(i) 80 for_each_online_cpu(i)
75 seq_printf(m, 81 seq_printf(m,
76 "Cpu%dBogo\t: %lu.%02lu\n"
77 "Cpu%dClkTck\t: %016lx\n", 82 "Cpu%dClkTck\t: %016lx\n",
78 i, cpu_data(i).udelay_val / (500000/HZ),
79 (cpu_data(i).udelay_val / (5000/HZ)) % 100,
80 i, cpu_data(i).clock_tick); 83 i, cpu_data(i).clock_tick);
81} 84}
82 85
86static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
87
83extern void setup_sparc64_timer(void); 88extern void setup_sparc64_timer(void);
84 89
85static volatile unsigned long callin_flag = 0; 90static volatile unsigned long callin_flag = 0;
86 91
87void __init smp_callin(void) 92void __devinit smp_callin(void)
88{ 93{
89 int cpuid = hard_smp_processor_id(); 94 int cpuid = hard_smp_processor_id();
90 95
@@ -102,8 +107,6 @@ void __init smp_callin(void)
102 107
103 local_irq_enable(); 108 local_irq_enable();
104 109
105 calibrate_delay();
106 cpu_data(cpuid).udelay_val = loops_per_jiffy;
107 callin_flag = 1; 110 callin_flag = 1;
108 __asm__ __volatile__("membar #Sync\n\t" 111 __asm__ __volatile__("membar #Sync\n\t"
109 "flush %%g6" : : : "memory"); 112 "flush %%g6" : : : "memory");
@@ -120,7 +123,9 @@ void __init smp_callin(void)
120 while (!cpu_isset(cpuid, smp_commenced_mask)) 123 while (!cpu_isset(cpuid, smp_commenced_mask))
121 rmb(); 124 rmb();
122 125
126 spin_lock(&call_lock);
123 cpu_set(cpuid, cpu_online_map); 127 cpu_set(cpuid, cpu_online_map);
128 spin_unlock(&call_lock);
124 129
125 /* idle thread is expected to have preempt disabled */ 130 /* idle thread is expected to have preempt disabled */
126 preempt_disable(); 131 preempt_disable();
@@ -268,6 +273,67 @@ static void smp_synchronize_one_tick(int cpu)
268 spin_unlock_irqrestore(&itc_sync_lock, flags); 273 spin_unlock_irqrestore(&itc_sync_lock, flags);
269} 274}
270 275
276#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
277/* XXX Put this in some common place. XXX */
278static unsigned long kimage_addr_to_ra(void *p)
279{
280 unsigned long val = (unsigned long) p;
281
282 return kern_base + (val - KERNBASE);
283}
284
285static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
286{
287 extern unsigned long sparc64_ttable_tl0;
288 extern unsigned long kern_locked_tte_data;
289 extern int bigkernel;
290 struct hvtramp_descr *hdesc;
291 unsigned long trampoline_ra;
292 struct trap_per_cpu *tb;
293 u64 tte_vaddr, tte_data;
294 unsigned long hv_err;
295
296 hdesc = kzalloc(sizeof(*hdesc), GFP_KERNEL);
297 if (!hdesc) {
298 printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate "
299 "hvtramp_descr.\n");
300 return;
301 }
302
303 hdesc->cpu = cpu;
304 hdesc->num_mappings = (bigkernel ? 2 : 1);
305
306 tb = &trap_block[cpu];
307 tb->hdesc = hdesc;
308
309 hdesc->fault_info_va = (unsigned long) &tb->fault_info;
310 hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
311
312 hdesc->thread_reg = thread_reg;
313
314 tte_vaddr = (unsigned long) KERNBASE;
315 tte_data = kern_locked_tte_data;
316
317 hdesc->maps[0].vaddr = tte_vaddr;
318 hdesc->maps[0].tte = tte_data;
319 if (bigkernel) {
320 tte_vaddr += 0x400000;
321 tte_data += 0x400000;
322 hdesc->maps[1].vaddr = tte_vaddr;
323 hdesc->maps[1].tte = tte_data;
324 }
325
326 trampoline_ra = kimage_addr_to_ra(hv_cpu_startup);
327
328 hv_err = sun4v_cpu_start(cpu, trampoline_ra,
329 kimage_addr_to_ra(&sparc64_ttable_tl0),
330 __pa(hdesc));
331 if (hv_err)
332 printk(KERN_ERR "ldom_startcpu_cpuid: sun4v_cpu_start() "
333 "gives error %lu\n", hv_err);
334}
335#endif
336
271extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); 337extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
272 338
273extern unsigned long sparc64_cpu_startup; 339extern unsigned long sparc64_cpu_startup;
@@ -280,6 +346,7 @@ static struct thread_info *cpu_new_thread = NULL;
280 346
281static int __devinit smp_boot_one_cpu(unsigned int cpu) 347static int __devinit smp_boot_one_cpu(unsigned int cpu)
282{ 348{
349 struct trap_per_cpu *tb = &trap_block[cpu];
283 unsigned long entry = 350 unsigned long entry =
284 (unsigned long)(&sparc64_cpu_startup); 351 (unsigned long)(&sparc64_cpu_startup);
285 unsigned long cookie = 352 unsigned long cookie =
@@ -290,20 +357,25 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
290 p = fork_idle(cpu); 357 p = fork_idle(cpu);
291 callin_flag = 0; 358 callin_flag = 0;
292 cpu_new_thread = task_thread_info(p); 359 cpu_new_thread = task_thread_info(p);
293 cpu_set(cpu, cpu_callout_map);
294 360
295 if (tlb_type == hypervisor) { 361 if (tlb_type == hypervisor) {
296 /* Alloc the mondo queues, cpu will load them. */ 362 /* Alloc the mondo queues, cpu will load them. */
297 sun4v_init_mondo_queues(0, cpu, 1, 0); 363 sun4v_init_mondo_queues(0, cpu, 1, 0);
298 364
299 prom_startcpu_cpuid(cpu, entry, cookie); 365#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
366 if (ldom_domaining_enabled)
367 ldom_startcpu_cpuid(cpu,
368 (unsigned long) cpu_new_thread);
369 else
370#endif
371 prom_startcpu_cpuid(cpu, entry, cookie);
300 } else { 372 } else {
301 struct device_node *dp = of_find_node_by_cpuid(cpu); 373 struct device_node *dp = of_find_node_by_cpuid(cpu);
302 374
303 prom_startcpu(dp->node, entry, cookie); 375 prom_startcpu(dp->node, entry, cookie);
304 } 376 }
305 377
306 for (timeout = 0; timeout < 5000000; timeout++) { 378 for (timeout = 0; timeout < 50000; timeout++) {
307 if (callin_flag) 379 if (callin_flag)
308 break; 380 break;
309 udelay(100); 381 udelay(100);
@@ -313,11 +385,15 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
313 ret = 0; 385 ret = 0;
314 } else { 386 } else {
315 printk("Processor %d is stuck.\n", cpu); 387 printk("Processor %d is stuck.\n", cpu);
316 cpu_clear(cpu, cpu_callout_map);
317 ret = -ENODEV; 388 ret = -ENODEV;
318 } 389 }
319 cpu_new_thread = NULL; 390 cpu_new_thread = NULL;
320 391
392 if (tb->hdesc) {
393 kfree(tb->hdesc);
394 tb->hdesc = NULL;
395 }
396
321 return ret; 397 return ret;
322} 398}
323 399
@@ -720,7 +796,6 @@ struct call_data_struct {
720 int wait; 796 int wait;
721}; 797};
722 798
723static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
724static struct call_data_struct *call_data; 799static struct call_data_struct *call_data;
725 800
726extern unsigned long xcall_call_function; 801extern unsigned long xcall_call_function;
@@ -1152,34 +1227,14 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
1152 preempt_enable(); 1227 preempt_enable();
1153} 1228}
1154 1229
1155void __init smp_tick_init(void)
1156{
1157 boot_cpu_id = hard_smp_processor_id();
1158}
1159
1160/* /proc/profile writes can call this, don't __init it please. */ 1230/* /proc/profile writes can call this, don't __init it please. */
1161int setup_profiling_timer(unsigned int multiplier) 1231int setup_profiling_timer(unsigned int multiplier)
1162{ 1232{
1163 return -EINVAL; 1233 return -EINVAL;
1164} 1234}
1165 1235
1166/* Constrain the number of cpus to max_cpus. */
1167void __init smp_prepare_cpus(unsigned int max_cpus) 1236void __init smp_prepare_cpus(unsigned int max_cpus)
1168{ 1237{
1169 int i;
1170
1171 if (num_possible_cpus() > max_cpus) {
1172 for_each_possible_cpu(i) {
1173 if (i != boot_cpu_id) {
1174 cpu_clear(i, phys_cpu_present_map);
1175 cpu_clear(i, cpu_present_map);
1176 if (num_possible_cpus() <= max_cpus)
1177 break;
1178 }
1179 }
1180 }
1181
1182 cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
1183} 1238}
1184 1239
1185void __devinit smp_prepare_boot_cpu(void) 1240void __devinit smp_prepare_boot_cpu(void)
@@ -1190,30 +1245,32 @@ void __devinit smp_fill_in_sib_core_maps(void)
1190{ 1245{
1191 unsigned int i; 1246 unsigned int i;
1192 1247
1193 for_each_possible_cpu(i) { 1248 for_each_present_cpu(i) {
1194 unsigned int j; 1249 unsigned int j;
1195 1250
1251 cpus_clear(cpu_core_map[i]);
1196 if (cpu_data(i).core_id == 0) { 1252 if (cpu_data(i).core_id == 0) {
1197 cpu_set(i, cpu_core_map[i]); 1253 cpu_set(i, cpu_core_map[i]);
1198 continue; 1254 continue;
1199 } 1255 }
1200 1256
1201 for_each_possible_cpu(j) { 1257 for_each_present_cpu(j) {
1202 if (cpu_data(i).core_id == 1258 if (cpu_data(i).core_id ==
1203 cpu_data(j).core_id) 1259 cpu_data(j).core_id)
1204 cpu_set(j, cpu_core_map[i]); 1260 cpu_set(j, cpu_core_map[i]);
1205 } 1261 }
1206 } 1262 }
1207 1263
1208 for_each_possible_cpu(i) { 1264 for_each_present_cpu(i) {
1209 unsigned int j; 1265 unsigned int j;
1210 1266
1267 cpus_clear(cpu_sibling_map[i]);
1211 if (cpu_data(i).proc_id == -1) { 1268 if (cpu_data(i).proc_id == -1) {
1212 cpu_set(i, cpu_sibling_map[i]); 1269 cpu_set(i, cpu_sibling_map[i]);
1213 continue; 1270 continue;
1214 } 1271 }
1215 1272
1216 for_each_possible_cpu(j) { 1273 for_each_present_cpu(j) {
1217 if (cpu_data(i).proc_id == 1274 if (cpu_data(i).proc_id ==
1218 cpu_data(j).proc_id) 1275 cpu_data(j).proc_id)
1219 cpu_set(j, cpu_sibling_map[i]); 1276 cpu_set(j, cpu_sibling_map[i]);
@@ -1242,18 +1299,112 @@ int __cpuinit __cpu_up(unsigned int cpu)
1242 return ret; 1299 return ret;
1243} 1300}
1244 1301
1245void __init smp_cpus_done(unsigned int max_cpus) 1302#ifdef CONFIG_HOTPLUG_CPU
1303void cpu_play_dead(void)
1304{
1305 int cpu = smp_processor_id();
1306 unsigned long pstate;
1307
1308 idle_task_exit();
1309
1310 if (tlb_type == hypervisor) {
1311 struct trap_per_cpu *tb = &trap_block[cpu];
1312
1313 sun4v_cpu_qconf(HV_CPU_QUEUE_CPU_MONDO,
1314 tb->cpu_mondo_pa, 0);
1315 sun4v_cpu_qconf(HV_CPU_QUEUE_DEVICE_MONDO,
1316 tb->dev_mondo_pa, 0);
1317 sun4v_cpu_qconf(HV_CPU_QUEUE_RES_ERROR,
1318 tb->resum_mondo_pa, 0);
1319 sun4v_cpu_qconf(HV_CPU_QUEUE_NONRES_ERROR,
1320 tb->nonresum_mondo_pa, 0);
1321 }
1322
1323 cpu_clear(cpu, smp_commenced_mask);
1324 membar_safe("#Sync");
1325
1326 local_irq_disable();
1327
1328 __asm__ __volatile__(
1329 "rdpr %%pstate, %0\n\t"
1330 "wrpr %0, %1, %%pstate"
1331 : "=r" (pstate)
1332 : "i" (PSTATE_IE));
1333
1334 while (1)
1335 barrier();
1336}
1337
1338int __cpu_disable(void)
1246{ 1339{
1247 unsigned long bogosum = 0; 1340 int cpu = smp_processor_id();
1341 cpuinfo_sparc *c;
1248 int i; 1342 int i;
1249 1343
1250 for_each_online_cpu(i) 1344 for_each_cpu_mask(i, cpu_core_map[cpu])
1251 bogosum += cpu_data(i).udelay_val; 1345 cpu_clear(cpu, cpu_core_map[i]);
1252 printk("Total of %ld processors activated " 1346 cpus_clear(cpu_core_map[cpu]);
1253 "(%lu.%02lu BogoMIPS).\n", 1347
1254 (long) num_online_cpus(), 1348 for_each_cpu_mask(i, cpu_sibling_map[cpu])
1255 bogosum/(500000/HZ), 1349 cpu_clear(cpu, cpu_sibling_map[i]);
1256 (bogosum/(5000/HZ))%100); 1350 cpus_clear(cpu_sibling_map[cpu]);
1351
1352 c = &cpu_data(cpu);
1353
1354 c->core_id = 0;
1355 c->proc_id = -1;
1356
1357 spin_lock(&call_lock);
1358 cpu_clear(cpu, cpu_online_map);
1359 spin_unlock(&call_lock);
1360
1361 smp_wmb();
1362
1363 /* Make sure no interrupts point to this cpu. */
1364 fixup_irqs();
1365
1366 local_irq_enable();
1367 mdelay(1);
1368 local_irq_disable();
1369
1370 return 0;
1371}
1372
1373void __cpu_die(unsigned int cpu)
1374{
1375 int i;
1376
1377 for (i = 0; i < 100; i++) {
1378 smp_rmb();
1379 if (!cpu_isset(cpu, smp_commenced_mask))
1380 break;
1381 msleep(100);
1382 }
1383 if (cpu_isset(cpu, smp_commenced_mask)) {
1384 printk(KERN_ERR "CPU %u didn't die...\n", cpu);
1385 } else {
1386#if defined(CONFIG_SUN_LDOMS)
1387 unsigned long hv_err;
1388 int limit = 100;
1389
1390 do {
1391 hv_err = sun4v_cpu_stop(cpu);
1392 if (hv_err == HV_EOK) {
1393 cpu_clear(cpu, cpu_present_map);
1394 break;
1395 }
1396 } while (--limit > 0);
1397 if (limit <= 0) {
1398 printk(KERN_ERR "sun4v_cpu_stop() fails err=%lu\n",
1399 hv_err);
1400 }
1401#endif
1402 }
1403}
1404#endif
1405
1406void __init smp_cpus_done(unsigned int max_cpus)
1407{
1257} 1408}
1258 1409
1259void smp_send_reschedule(int cpu) 1410void smp_send_reschedule(int cpu)