diff options
author | Gautham R Shenoy <ego@in.ibm.com> | 2009-11-26 04:58:55 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-12-09 01:09:35 -0500 |
commit | b6db63d1a7f0138f348ba7a648df35ac6365988e (patch) | |
tree | d5e3aa14ba93f2dac15820bfec9fa2a6ae104206 /arch/powerpc | |
parent | 8389b37dffdc695b4fb363ebe0ed9748bb3b48d0 (diff) |
pseries/pseries: Add code to online/offline CPUs of a DLPAR node
Currently the cpu-allocation/deallocation on pSeries is a
two step process from the Userspace.
- Set the indicators and update the device tree by writing to the sysfs
tunable "probe" during allocation and "release" during deallocation.
- Online / Offline the CPUs of the allocated/would_be_deallocated node by
writing to the sysfs tunable "online".
This patch adds kernel code to online/offline the CPUs soon_after/just_before
they have been allocated/would_be_deallocated. This way, the userspace tool
that performs DLPAR operations would only have to deal with one set of sysfs
tunables namely "probe" and release".
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
Acked-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index fe8d4b3c50cd..642e1b2e5c42 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/proc_fs.h> | 16 | #include <linux/proc_fs.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/cpu.h> | 18 | #include <linux/cpu.h> |
19 | #include "offline_states.h" | ||
19 | 20 | ||
20 | #include <asm/prom.h> | 21 | #include <asm/prom.h> |
21 | #include <asm/machdep.h> | 22 | #include <asm/machdep.h> |
@@ -287,6 +288,98 @@ int dlpar_detach_node(struct device_node *dn) | |||
287 | return 0; | 288 | return 0; |
288 | } | 289 | } |
289 | 290 | ||
291 | int online_node_cpus(struct device_node *dn) | ||
292 | { | ||
293 | int rc = 0; | ||
294 | unsigned int cpu; | ||
295 | int len, nthreads, i; | ||
296 | const u32 *intserv; | ||
297 | |||
298 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); | ||
299 | if (!intserv) | ||
300 | return -EINVAL; | ||
301 | |||
302 | nthreads = len / sizeof(u32); | ||
303 | |||
304 | cpu_maps_update_begin(); | ||
305 | for (i = 0; i < nthreads; i++) { | ||
306 | for_each_present_cpu(cpu) { | ||
307 | if (get_hard_smp_processor_id(cpu) != intserv[i]) | ||
308 | continue; | ||
309 | BUG_ON(get_cpu_current_state(cpu) | ||
310 | != CPU_STATE_OFFLINE); | ||
311 | cpu_maps_update_done(); | ||
312 | rc = cpu_up(cpu); | ||
313 | if (rc) | ||
314 | goto out; | ||
315 | cpu_maps_update_begin(); | ||
316 | |||
317 | break; | ||
318 | } | ||
319 | if (cpu == num_possible_cpus()) | ||
320 | printk(KERN_WARNING "Could not find cpu to online " | ||
321 | "with physical id 0x%x\n", intserv[i]); | ||
322 | } | ||
323 | cpu_maps_update_done(); | ||
324 | |||
325 | out: | ||
326 | return rc; | ||
327 | |||
328 | } | ||
329 | |||
330 | int offline_node_cpus(struct device_node *dn) | ||
331 | { | ||
332 | int rc = 0; | ||
333 | unsigned int cpu; | ||
334 | int len, nthreads, i; | ||
335 | const u32 *intserv; | ||
336 | |||
337 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); | ||
338 | if (!intserv) | ||
339 | return -EINVAL; | ||
340 | |||
341 | nthreads = len / sizeof(u32); | ||
342 | |||
343 | cpu_maps_update_begin(); | ||
344 | for (i = 0; i < nthreads; i++) { | ||
345 | for_each_present_cpu(cpu) { | ||
346 | if (get_hard_smp_processor_id(cpu) != intserv[i]) | ||
347 | continue; | ||
348 | |||
349 | if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE) | ||
350 | break; | ||
351 | |||
352 | if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { | ||
353 | cpu_maps_update_done(); | ||
354 | rc = cpu_down(cpu); | ||
355 | if (rc) | ||
356 | goto out; | ||
357 | cpu_maps_update_begin(); | ||
358 | break; | ||
359 | |||
360 | } | ||
361 | |||
362 | /* | ||
363 | * The cpu is in CPU_STATE_INACTIVE. | ||
364 | * Upgrade it's state to CPU_STATE_OFFLINE. | ||
365 | */ | ||
366 | set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); | ||
367 | BUG_ON(plpar_hcall_norets(H_PROD, intserv[i]) | ||
368 | != H_SUCCESS); | ||
369 | __cpu_die(cpu); | ||
370 | break; | ||
371 | } | ||
372 | if (cpu == num_possible_cpus()) | ||
373 | printk(KERN_WARNING "Could not find cpu to offline " | ||
374 | "with physical id 0x%x\n", intserv[i]); | ||
375 | } | ||
376 | cpu_maps_update_done(); | ||
377 | |||
378 | out: | ||
379 | return rc; | ||
380 | |||
381 | } | ||
382 | |||
290 | #define DR_ENTITY_SENSE 9003 | 383 | #define DR_ENTITY_SENSE 9003 |
291 | #define DR_ENTITY_PRESENT 1 | 384 | #define DR_ENTITY_PRESENT 1 |
292 | #define DR_ENTITY_UNUSABLE 2 | 385 | #define DR_ENTITY_UNUSABLE 2 |
@@ -385,6 +478,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count) | |||
385 | dlpar_free_cc_nodes(dn); | 478 | dlpar_free_cc_nodes(dn); |
386 | } | 479 | } |
387 | 480 | ||
481 | rc = online_node_cpus(dn); | ||
482 | |||
388 | return rc ? rc : count; | 483 | return rc ? rc : count; |
389 | } | 484 | } |
390 | 485 | ||
@@ -404,6 +499,12 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count) | |||
404 | return -EINVAL; | 499 | return -EINVAL; |
405 | } | 500 | } |
406 | 501 | ||
502 | rc = offline_node_cpus(dn); | ||
503 | if (rc) { | ||
504 | of_node_put(dn); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
407 | rc = dlpar_release_drc(*drc_index); | 508 | rc = dlpar_release_drc(*drc_index); |
408 | if (rc) { | 509 | if (rc) { |
409 | of_node_put(dn); | 510 | of_node_put(dn); |