diff options
author | Nathan Fontenot <nfont@linux.vnet.ibm.com> | 2015-12-16 15:52:39 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-12-17 06:41:02 -0500 |
commit | e666ae0b10aaa1c961c928558bafc28bc049ac87 (patch) | |
tree | 8e552eff4c6eff53ffb6df9454b02b2121d84adb | |
parent | d98389f375329b7a37d0e9211a1216d9141d7a5f (diff) |
powerpc/pseries: Update CPU hotplug error recovery
Update the cpu dlpar add/remove paths to do better error recovery when
a failure occurs during the add/remove operation.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-cpu.c | 76 |
1 files changed, 63 insertions, 13 deletions
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 6fb28cf229e7..a54aee982589 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c | |||
@@ -18,6 +18,8 @@ | |||
18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define pr_fmt(fmt) "pseries-hotplug-cpu: " fmt | ||
22 | |||
21 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
22 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
23 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
@@ -405,38 +407,67 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index) | |||
405 | static ssize_t dlpar_cpu_add(u32 drc_index) | 407 | static ssize_t dlpar_cpu_add(u32 drc_index) |
406 | { | 408 | { |
407 | struct device_node *dn, *parent; | 409 | struct device_node *dn, *parent; |
408 | int rc; | 410 | int rc, saved_rc; |
411 | |||
412 | pr_debug("Attempting to add CPU, drc index: %x\n", drc_index); | ||
409 | 413 | ||
410 | parent = of_find_node_by_path("/cpus"); | 414 | parent = of_find_node_by_path("/cpus"); |
411 | if (!parent) | 415 | if (!parent) { |
416 | pr_warn("Failed to find CPU root node \"/cpus\"\n"); | ||
412 | return -ENODEV; | 417 | return -ENODEV; |
418 | } | ||
413 | 419 | ||
414 | if (dlpar_cpu_exists(parent, drc_index)) { | 420 | if (dlpar_cpu_exists(parent, drc_index)) { |
415 | of_node_put(parent); | 421 | of_node_put(parent); |
416 | printk(KERN_WARNING "CPU with drc index %x already exists\n", | 422 | pr_warn("CPU with drc index %x already exists\n", drc_index); |
417 | drc_index); | ||
418 | return -EINVAL; | 423 | return -EINVAL; |
419 | } | 424 | } |
420 | 425 | ||
421 | rc = dlpar_acquire_drc(drc_index); | 426 | rc = dlpar_acquire_drc(drc_index); |
422 | if (rc) { | 427 | if (rc) { |
428 | pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n", | ||
429 | rc, drc_index); | ||
423 | of_node_put(parent); | 430 | of_node_put(parent); |
424 | return -EINVAL; | 431 | return -EINVAL; |
425 | } | 432 | } |
426 | 433 | ||
427 | dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent); | 434 | dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent); |
428 | of_node_put(parent); | 435 | of_node_put(parent); |
429 | if (!dn) | 436 | if (!dn) { |
437 | pr_warn("Failed call to configure-connector, drc index: %x\n", | ||
438 | drc_index); | ||
439 | dlpar_release_drc(drc_index); | ||
430 | return -EINVAL; | 440 | return -EINVAL; |
441 | } | ||
431 | 442 | ||
432 | rc = dlpar_attach_node(dn); | 443 | rc = dlpar_attach_node(dn); |
433 | if (rc) { | 444 | if (rc) { |
434 | dlpar_release_drc(drc_index); | 445 | saved_rc = rc; |
435 | dlpar_free_cc_nodes(dn); | 446 | pr_warn("Failed to attach node %s, rc: %d, drc index: %x\n", |
436 | return rc; | 447 | dn->name, rc, drc_index); |
448 | |||
449 | rc = dlpar_release_drc(drc_index); | ||
450 | if (!rc) | ||
451 | dlpar_free_cc_nodes(dn); | ||
452 | |||
453 | return saved_rc; | ||
437 | } | 454 | } |
438 | 455 | ||
439 | rc = dlpar_online_cpu(dn); | 456 | rc = dlpar_online_cpu(dn); |
457 | if (rc) { | ||
458 | saved_rc = rc; | ||
459 | pr_warn("Failed to online cpu %s, rc: %d, drc index: %x\n", | ||
460 | dn->name, rc, drc_index); | ||
461 | |||
462 | rc = dlpar_detach_node(dn); | ||
463 | if (!rc) | ||
464 | dlpar_release_drc(drc_index); | ||
465 | |||
466 | return saved_rc; | ||
467 | } | ||
468 | |||
469 | pr_debug("Successfully added CPU %s, drc index: %x\n", dn->name, | ||
470 | drc_index); | ||
440 | return rc; | 471 | return rc; |
441 | } | 472 | } |
442 | 473 | ||
@@ -500,19 +531,38 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index) | |||
500 | { | 531 | { |
501 | int rc; | 532 | int rc; |
502 | 533 | ||
534 | pr_debug("Attemping to remove CPU %s, drc index: %x\n", | ||
535 | dn->name, drc_index); | ||
536 | |||
503 | rc = dlpar_offline_cpu(dn); | 537 | rc = dlpar_offline_cpu(dn); |
504 | if (rc) | 538 | if (rc) { |
539 | pr_warn("Failed to offline CPU %s, rc: %d\n", dn->name, rc); | ||
505 | return -EINVAL; | 540 | return -EINVAL; |
541 | } | ||
506 | 542 | ||
507 | rc = dlpar_release_drc(drc_index); | 543 | rc = dlpar_release_drc(drc_index); |
508 | if (rc) | 544 | if (rc) { |
545 | pr_warn("Failed to release drc (%x) for CPU %s, rc: %d\n", | ||
546 | drc_index, dn->name, rc); | ||
547 | dlpar_online_cpu(dn); | ||
509 | return rc; | 548 | return rc; |
549 | } | ||
510 | 550 | ||
511 | rc = dlpar_detach_node(dn); | 551 | rc = dlpar_detach_node(dn); |
512 | if (rc) | 552 | if (rc) { |
513 | dlpar_acquire_drc(drc_index); | 553 | int saved_rc = rc; |
514 | 554 | ||
515 | return rc; | 555 | pr_warn("Failed to detach CPU %s, rc: %d", dn->name, rc); |
556 | |||
557 | rc = dlpar_acquire_drc(drc_index); | ||
558 | if (!rc) | ||
559 | dlpar_online_cpu(dn); | ||
560 | |||
561 | return saved_rc; | ||
562 | } | ||
563 | |||
564 | pr_debug("Successfully removed CPU, drc index: %x\n", drc_index); | ||
565 | return 0; | ||
516 | } | 566 | } |
517 | 567 | ||
518 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | 568 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE |