1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Support for dynamic reconfiguration for PCI, Memory, and CPU 4 * Hotplug and Dynamic Logical Partitioning on RPA platforms. 5 * 6 * Copyright (C) 2009 Nathan Fontenot 7 * Copyright (C) 2009 IBM Corporation 8 */ 9 10 #define pr_fmt(fmt) "dlpar: " fmt 11 12 #include <linux/kernel.h> 13 #include <linux/notifier.h> 14 #include <linux/spinlock.h> 15 #include <linux/cpu.h> 16 #include <linux/slab.h> 17 #include <linux/sysfs.h> 18 #include <linux/of.h> 19 20 #include "of_helpers.h" 21 #include "pseries.h" 22 23 #include <asm/machdep.h> 24 #include <linux/uaccess.h> 25 #include <asm/rtas.h> 26 #include <asm/rtas-work-area.h> 27 #include <asm/prom.h> 28 29 static struct workqueue_struct *pseries_hp_wq; 30 31 struct pseries_hp_work { 32 struct work_struct work; 33 struct pseries_hp_errorlog *errlog; 34 }; 35 36 struct cc_workarea { 37 __be32 drc_index; 38 __be32 zero; 39 __be32 name_offset; 40 __be32 prop_length; 41 __be32 prop_offset; 42 }; 43 44 void dlpar_free_cc_property(struct property *prop) 45 { 46 kfree(prop->name); 47 kfree(prop->value); 48 kfree(prop); 49 } 50 51 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) 52 { 53 struct property *prop; 54 char *name; 55 char *value; 56 57 prop = kzalloc_obj(*prop); 58 if (!prop) 59 return NULL; 60 61 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset); 62 prop->name = kstrdup(name, GFP_KERNEL); 63 if (!prop->name) { 64 dlpar_free_cc_property(prop); 65 return NULL; 66 } 67 68 prop->length = be32_to_cpu(ccwa->prop_length); 69 value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset); 70 prop->value = kmemdup(value, prop->length, GFP_KERNEL); 71 if (!prop->value) { 72 dlpar_free_cc_property(prop); 73 return NULL; 74 } 75 76 return prop; 77 } 78 79 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa) 80 { 81 struct device_node *dn; 82 const char *name; 83 84 dn = kzalloc_obj(*dn); 85 if (!dn) 86 return NULL; 87 88 name = (const char *)ccwa + be32_to_cpu(ccwa->name_offset); 89 dn->full_name = kstrdup(name, GFP_KERNEL); 90 if (!dn->full_name) { 91 kfree(dn); 92 return NULL; 93 } 94 95 of_node_set_flag(dn, OF_DYNAMIC); 96 of_node_init(dn); 97 98 return dn; 99 } 100 101 static void dlpar_free_one_cc_node(struct device_node *dn) 102 { 103 struct property *prop; 104 105 while (dn->properties) { 106 prop = dn->properties; 107 dn->properties = prop->next; 108 dlpar_free_cc_property(prop); 109 } 110 111 kfree(dn->full_name); 112 kfree(dn); 113 } 114 115 void dlpar_free_cc_nodes(struct device_node *dn) 116 { 117 if (dn->child) 118 dlpar_free_cc_nodes(dn->child); 119 120 if (dn->sibling) 121 dlpar_free_cc_nodes(dn->sibling); 122 123 dlpar_free_one_cc_node(dn); 124 } 125 126 #define COMPLETE 0 127 #define NEXT_SIBLING 1 128 #define NEXT_CHILD 2 129 #define NEXT_PROPERTY 3 130 #define PREV_PARENT 4 131 #define MORE_MEMORY 5 132 #define ERR_CFG_USE -9003 133 134 struct device_node *dlpar_configure_connector(__be32 drc_index, 135 struct device_node *parent) 136 { 137 struct device_node *dn; 138 struct device_node *first_dn = NULL; 139 struct device_node *last_dn = NULL; 140 struct property *property; 141 struct property *last_property = NULL; 142 struct cc_workarea *ccwa; 143 struct rtas_work_area *work_area; 144 char *data_buf; 145 int cc_token; 146 int rc = -1; 147 148 cc_token = rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR); 149 if (cc_token == RTAS_UNKNOWN_SERVICE) 150 return NULL; 151 152 work_area = rtas_work_area_alloc(SZ_4K); 153 data_buf = rtas_work_area_raw_buf(work_area); 154 155 ccwa = (struct cc_workarea *)&data_buf[0]; 156 ccwa->drc_index = drc_index; 157 ccwa->zero = 0; 158 159 do { 160 do { 161 rc = rtas_call(cc_token, 2, 1, NULL, 162 rtas_work_area_phys(work_area), NULL); 163 } while (rtas_busy_delay(rc)); 164 165 switch (rc) { 166 case COMPLETE: 167 break; 168 169 case NEXT_SIBLING: 170 dn = dlpar_parse_cc_node(ccwa); 171 if (!dn) 172 goto cc_error; 173 174 dn->parent = last_dn->parent; 175 last_dn->sibling = dn; 176 last_dn = dn; 177 break; 178 179 case NEXT_CHILD: 180 dn = dlpar_parse_cc_node(ccwa); 181 if (!dn) 182 goto cc_error; 183 184 if (!first_dn) { 185 dn->parent = parent; 186 first_dn = dn; 187 } else { 188 dn->parent = last_dn; 189 if (last_dn) 190 last_dn->child = dn; 191 } 192 193 last_dn = dn; 194 break; 195 196 case NEXT_PROPERTY: 197 property = dlpar_parse_cc_property(ccwa); 198 if (!property) 199 goto cc_error; 200 201 if (!last_dn->properties) 202 last_dn->properties = property; 203 else 204 last_property->next = property; 205 206 last_property = property; 207 break; 208 209 case PREV_PARENT: 210 last_dn = last_dn->parent; 211 break; 212 213 case MORE_MEMORY: 214 case ERR_CFG_USE: 215 default: 216 printk(KERN_ERR "Unexpected Error (%d) " 217 "returned from configure-connector\n", rc); 218 goto cc_error; 219 } 220 } while (rc); 221 222 cc_error: 223 rtas_work_area_free(work_area); 224 225 if (rc) { 226 if (first_dn) 227 dlpar_free_cc_nodes(first_dn); 228 229 return NULL; 230 } 231 232 return first_dn; 233 } 234 235 int dlpar_attach_node(struct device_node *dn, struct device_node *parent) 236 { 237 int rc; 238 239 dn->parent = parent; 240 241 rc = of_attach_node(dn); 242 if (rc) { 243 printk(KERN_ERR "Failed to add device node %pOF\n", dn); 244 return rc; 245 } 246 247 return 0; 248 } 249 250 int dlpar_detach_node(struct device_node *dn) 251 { 252 struct device_node *child; 253 int rc; 254 255 for_each_child_of_node(dn, child) 256 dlpar_detach_node(child); 257 258 rc = of_detach_node(dn); 259 if (rc) 260 return rc; 261 262 of_node_put(dn); 263 264 return 0; 265 } 266 static int dlpar_changeset_attach_cc_nodes(struct of_changeset *ocs, 267 struct device_node *dn) 268 { 269 int rc; 270 271 rc = of_changeset_attach_node(ocs, dn); 272 273 if (!rc && dn->child) 274 rc = dlpar_changeset_attach_cc_nodes(ocs, dn->child); 275 if (!rc && dn->sibling) 276 rc = dlpar_changeset_attach_cc_nodes(ocs, dn->sibling); 277 278 return rc; 279 } 280 281 #define DR_ENTITY_SENSE 9003 282 #define DR_ENTITY_PRESENT 1 283 #define DR_ENTITY_UNUSABLE 2 284 #define ALLOCATION_STATE 9003 285 #define ALLOC_UNUSABLE 0 286 #define ALLOC_USABLE 1 287 #define ISOLATION_STATE 9001 288 #define ISOLATE 0 289 #define UNISOLATE 1 290 291 int dlpar_acquire_drc(u32 drc_index) 292 { 293 int dr_status, rc; 294 295 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status); 296 if (rc || dr_status != DR_ENTITY_UNUSABLE) 297 return -1; 298 299 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); 300 if (rc) 301 return rc; 302 303 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 304 if (rc) { 305 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 306 return rc; 307 } 308 309 return 0; 310 } 311 312 int dlpar_release_drc(u32 drc_index) 313 { 314 int dr_status, rc; 315 316 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status); 317 if (rc || dr_status != DR_ENTITY_PRESENT) 318 return -1; 319 320 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); 321 if (rc) 322 return rc; 323 324 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 325 if (rc) { 326 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 327 return rc; 328 } 329 330 return 0; 331 } 332 333 int dlpar_unisolate_drc(u32 drc_index) 334 { 335 int dr_status, rc; 336 337 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status); 338 if (rc || dr_status != DR_ENTITY_PRESENT) 339 return -1; 340 341 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 342 343 return 0; 344 } 345 346 static struct device_node * 347 get_device_node_with_drc_index(u32 index) 348 { 349 struct device_node *np = NULL; 350 u32 node_index; 351 int rc; 352 353 for_each_node_with_property(np, "ibm,my-drc-index") { 354 rc = of_property_read_u32(np, "ibm,my-drc-index", 355 &node_index); 356 if (rc) { 357 pr_err("%s: %pOF: of_property_read_u32 %s: %d\n", 358 __func__, np, "ibm,my-drc-index", rc); 359 of_node_put(np); 360 return NULL; 361 } 362 363 if (index == node_index) 364 break; 365 } 366 367 return np; 368 } 369 370 static struct device_node * 371 get_device_node_with_drc_info(u32 index) 372 { 373 struct device_node *np = NULL; 374 struct of_drc_info drc; 375 struct property *info; 376 const __be32 *value; 377 u32 node_index; 378 int i, j, count; 379 380 for_each_node_with_property(np, "ibm,drc-info") { 381 info = of_find_property(np, "ibm,drc-info", NULL); 382 if (info == NULL) { 383 /* XXX can this happen? */ 384 of_node_put(np); 385 return NULL; 386 } 387 value = of_prop_next_u32(info, NULL, &count); 388 if (value == NULL) 389 continue; 390 value++; 391 for (i = 0; i < count; i++) { 392 if (of_read_drc_info_cell(&info, &value, &drc)) 393 break; 394 if (index > drc.last_drc_index) 395 continue; 396 node_index = drc.drc_index_start; 397 for (j = 0; j < drc.num_sequential_elems; j++) { 398 if (index == node_index) 399 return np; 400 node_index += drc.sequential_inc; 401 } 402 } 403 } 404 405 return NULL; 406 } 407 408 static struct device_node * 409 get_device_node_with_drc_indexes(u32 drc_index) 410 { 411 struct device_node *np = NULL; 412 u32 nr_indexes, index; 413 int i, rc; 414 415 for_each_node_with_property(np, "ibm,drc-indexes") { 416 /* 417 * First element in the array is the total number of 418 * DRC indexes returned. 419 */ 420 rc = of_property_read_u32_index(np, "ibm,drc-indexes", 421 0, &nr_indexes); 422 if (rc) 423 goto out_put_np; 424 425 /* 426 * Retrieve DRC index from the list and return the 427 * device node if matched with the specified index. 428 */ 429 for (i = 0; i < nr_indexes; i++) { 430 rc = of_property_read_u32_index(np, "ibm,drc-indexes", 431 i+1, &index); 432 if (rc) 433 goto out_put_np; 434 435 if (drc_index == index) 436 return np; 437 } 438 } 439 440 return NULL; 441 442 out_put_np: 443 of_node_put(np); 444 return NULL; 445 } 446 447 static int dlpar_hp_dt_add(u32 index) 448 { 449 struct device_node *np, *nodes; 450 struct of_changeset ocs; 451 int rc; 452 453 /* 454 * Do not add device node(s) if already exists in the 455 * device tree. 456 */ 457 np = get_device_node_with_drc_index(index); 458 if (np) { 459 pr_err("%s: Adding device node for index (%d), but " 460 "already exists in the device tree\n", 461 __func__, index); 462 rc = -EINVAL; 463 goto out; 464 } 465 466 /* 467 * Recent FW provides ibm,drc-info property. So search 468 * for the user specified DRC index from ibm,drc-info 469 * property. If this property is not available, search 470 * in the indexes array from ibm,drc-indexes property. 471 */ 472 np = get_device_node_with_drc_info(index); 473 474 if (!np) { 475 np = get_device_node_with_drc_indexes(index); 476 if (!np) 477 return -EIO; 478 } 479 480 /* Next, configure the connector. */ 481 nodes = dlpar_configure_connector(cpu_to_be32(index), np); 482 if (!nodes) { 483 rc = -EIO; 484 goto out; 485 } 486 487 /* 488 * Add the new nodes from dlpar_configure_connector() onto 489 * the device-tree. 490 */ 491 of_changeset_init(&ocs); 492 rc = dlpar_changeset_attach_cc_nodes(&ocs, nodes); 493 494 if (!rc) 495 rc = of_changeset_apply(&ocs); 496 else 497 dlpar_free_cc_nodes(nodes); 498 499 of_changeset_destroy(&ocs); 500 501 out: 502 of_node_put(np); 503 return rc; 504 } 505 506 static int changeset_detach_node_recursive(struct of_changeset *ocs, 507 struct device_node *node) 508 { 509 struct device_node *child; 510 int rc; 511 512 for_each_child_of_node(node, child) { 513 rc = changeset_detach_node_recursive(ocs, child); 514 if (rc) { 515 of_node_put(child); 516 return rc; 517 } 518 } 519 520 return of_changeset_detach_node(ocs, node); 521 } 522 523 static int dlpar_hp_dt_remove(u32 drc_index) 524 { 525 struct device_node *np; 526 struct of_changeset ocs; 527 u32 index; 528 int rc = 0; 529 530 /* 531 * Prune all nodes with a matching index. 532 */ 533 of_changeset_init(&ocs); 534 535 for_each_node_with_property(np, "ibm,my-drc-index") { 536 rc = of_property_read_u32(np, "ibm,my-drc-index", &index); 537 if (rc) { 538 pr_err("%s: %pOF: of_property_read_u32 %s: %d\n", 539 __func__, np, "ibm,my-drc-index", rc); 540 of_node_put(np); 541 goto out; 542 } 543 544 if (index == drc_index) { 545 rc = changeset_detach_node_recursive(&ocs, np); 546 if (rc) { 547 of_node_put(np); 548 goto out; 549 } 550 } 551 } 552 553 rc = of_changeset_apply(&ocs); 554 555 out: 556 of_changeset_destroy(&ocs); 557 return rc; 558 } 559 560 static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe) 561 { 562 u32 drc_index; 563 int rc; 564 565 if (phpe->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX) 566 return -EINVAL; 567 568 drc_index = be32_to_cpu(phpe->_drc_u.drc_index); 569 570 lock_device_hotplug(); 571 572 switch (phpe->action) { 573 case PSERIES_HP_ELOG_ACTION_ADD: 574 rc = dlpar_hp_dt_add(drc_index); 575 break; 576 case PSERIES_HP_ELOG_ACTION_REMOVE: 577 rc = dlpar_hp_dt_remove(drc_index); 578 break; 579 default: 580 pr_err("Invalid action (%d) specified\n", phpe->action); 581 rc = -EINVAL; 582 break; 583 } 584 585 unlock_device_hotplug(); 586 587 return rc; 588 } 589 590 int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) 591 { 592 int rc; 593 594 switch (hp_elog->resource) { 595 case PSERIES_HP_ELOG_RESOURCE_MEM: 596 rc = dlpar_memory(hp_elog); 597 break; 598 case PSERIES_HP_ELOG_RESOURCE_CPU: 599 rc = dlpar_cpu(hp_elog); 600 break; 601 case PSERIES_HP_ELOG_RESOURCE_PMEM: 602 rc = dlpar_hp_pmem(hp_elog); 603 break; 604 case PSERIES_HP_ELOG_RESOURCE_DT: 605 rc = dlpar_hp_dt(hp_elog); 606 break; 607 608 default: 609 pr_warn_ratelimited("Invalid resource (%d) specified\n", 610 hp_elog->resource); 611 rc = -EINVAL; 612 } 613 614 return rc; 615 } 616 617 static void pseries_hp_work_fn(struct work_struct *work) 618 { 619 struct pseries_hp_work *hp_work = 620 container_of(work, struct pseries_hp_work, work); 621 622 handle_dlpar_errorlog(hp_work->errlog); 623 624 kfree(hp_work->errlog); 625 kfree(work); 626 } 627 628 void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog) 629 { 630 struct pseries_hp_work *work; 631 struct pseries_hp_errorlog *hp_errlog_copy; 632 633 hp_errlog_copy = kmemdup(hp_errlog, sizeof(*hp_errlog), GFP_ATOMIC); 634 if (!hp_errlog_copy) 635 return; 636 637 work = kmalloc_obj(struct pseries_hp_work, GFP_ATOMIC); 638 if (work) { 639 INIT_WORK((struct work_struct *)work, pseries_hp_work_fn); 640 work->errlog = hp_errlog_copy; 641 queue_work(pseries_hp_wq, (struct work_struct *)work); 642 } else { 643 kfree(hp_errlog_copy); 644 } 645 } 646 647 static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog) 648 { 649 char *arg; 650 651 arg = strsep(cmd, " "); 652 if (!arg) 653 return -EINVAL; 654 655 if (sysfs_streq(arg, "memory")) { 656 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; 657 } else if (sysfs_streq(arg, "cpu")) { 658 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU; 659 } else if (sysfs_streq(arg, "dt")) { 660 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_DT; 661 } else { 662 pr_err("Invalid resource specified.\n"); 663 return -EINVAL; 664 } 665 666 return 0; 667 } 668 669 static int dlpar_parse_action(char **cmd, struct pseries_hp_errorlog *hp_elog) 670 { 671 char *arg; 672 673 arg = strsep(cmd, " "); 674 if (!arg) 675 return -EINVAL; 676 677 if (sysfs_streq(arg, "add")) { 678 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD; 679 } else if (sysfs_streq(arg, "remove")) { 680 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE; 681 } else { 682 pr_err("Invalid action specified.\n"); 683 return -EINVAL; 684 } 685 686 return 0; 687 } 688 689 static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog) 690 { 691 char *arg; 692 u32 count, index; 693 694 arg = strsep(cmd, " "); 695 if (!arg) 696 return -EINVAL; 697 698 if (sysfs_streq(arg, "indexed-count")) { 699 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC; 700 arg = strsep(cmd, " "); 701 if (!arg) { 702 pr_err("No DRC count specified.\n"); 703 return -EINVAL; 704 } 705 706 if (kstrtou32(arg, 0, &count)) { 707 pr_err("Invalid DRC count specified.\n"); 708 return -EINVAL; 709 } 710 711 arg = strsep(cmd, " "); 712 if (!arg) { 713 pr_err("No DRC Index specified.\n"); 714 return -EINVAL; 715 } 716 717 if (kstrtou32(arg, 0, &index)) { 718 pr_err("Invalid DRC Index specified.\n"); 719 return -EINVAL; 720 } 721 722 hp_elog->_drc_u.ic.count = cpu_to_be32(count); 723 hp_elog->_drc_u.ic.index = cpu_to_be32(index); 724 } else if (sysfs_streq(arg, "index")) { 725 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; 726 arg = strsep(cmd, " "); 727 if (!arg) { 728 pr_err("No DRC Index specified.\n"); 729 return -EINVAL; 730 } 731 732 if (kstrtou32(arg, 0, &index)) { 733 pr_err("Invalid DRC Index specified.\n"); 734 return -EINVAL; 735 } 736 737 hp_elog->_drc_u.drc_index = cpu_to_be32(index); 738 } else if (sysfs_streq(arg, "count")) { 739 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT; 740 arg = strsep(cmd, " "); 741 if (!arg) { 742 pr_err("No DRC count specified.\n"); 743 return -EINVAL; 744 } 745 746 if (kstrtou32(arg, 0, &count)) { 747 pr_err("Invalid DRC count specified.\n"); 748 return -EINVAL; 749 } 750 751 hp_elog->_drc_u.drc_count = cpu_to_be32(count); 752 } else { 753 pr_err("Invalid id_type specified.\n"); 754 return -EINVAL; 755 } 756 757 return 0; 758 } 759 760 static ssize_t dlpar_store(const struct class *class, const struct class_attribute *attr, 761 const char *buf, size_t count) 762 { 763 struct pseries_hp_errorlog hp_elog; 764 char *argbuf; 765 char *args; 766 int rc; 767 768 args = argbuf = kstrdup(buf, GFP_KERNEL); 769 if (!argbuf) 770 return -ENOMEM; 771 772 /* 773 * Parse out the request from the user, this will be in the form: 774 * <resource> <action> <id_type> <id> 775 */ 776 rc = dlpar_parse_resource(&args, &hp_elog); 777 if (rc) 778 goto dlpar_store_out; 779 780 rc = dlpar_parse_action(&args, &hp_elog); 781 if (rc) 782 goto dlpar_store_out; 783 784 rc = dlpar_parse_id_type(&args, &hp_elog); 785 if (rc) 786 goto dlpar_store_out; 787 788 rc = handle_dlpar_errorlog(&hp_elog); 789 790 dlpar_store_out: 791 kfree(argbuf); 792 793 if (rc) 794 pr_err("Could not handle DLPAR request \"%s\"\n", buf); 795 796 return rc ? rc : count; 797 } 798 799 static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr, 800 char *buf) 801 { 802 return sysfs_emit(buf, "%s\n", "memory,cpu,dt"); 803 } 804 805 static CLASS_ATTR_RW(dlpar); 806 807 int __init dlpar_workqueue_init(void) 808 { 809 if (pseries_hp_wq) 810 return 0; 811 812 pseries_hp_wq = alloc_ordered_workqueue("pseries hotplug workqueue", 0); 813 814 return pseries_hp_wq ? 0 : -ENOMEM; 815 } 816 817 static int __init dlpar_sysfs_init(void) 818 { 819 int rc; 820 821 rc = dlpar_workqueue_init(); 822 if (rc) 823 return rc; 824 825 return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); 826 } 827 machine_device_initcall(pseries, dlpar_sysfs_init); 828 829