1 /* 2 * Support for dynamic reconfiguration for PCI, Memory, and CPU 3 * Hotplug and Dynamic Logical Partitioning on RPA platforms. 4 * 5 * Copyright (C) 2009 Nathan Fontenot 6 * Copyright (C) 2009 IBM Corporation 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 10 * 2 as published by the Free Software Foundation. 11 */ 12 13 #define pr_fmt(fmt) "dlpar: " fmt 14 15 #include <linux/kernel.h> 16 #include <linux/notifier.h> 17 #include <linux/spinlock.h> 18 #include <linux/cpu.h> 19 #include <linux/slab.h> 20 #include <linux/of.h> 21 #include "offline_states.h" 22 #include "pseries.h" 23 24 #include <asm/prom.h> 25 #include <asm/machdep.h> 26 #include <asm/uaccess.h> 27 #include <asm/rtas.h> 28 29 struct cc_workarea { 30 __be32 drc_index; 31 __be32 zero; 32 __be32 name_offset; 33 __be32 prop_length; 34 __be32 prop_offset; 35 }; 36 37 void dlpar_free_cc_property(struct property *prop) 38 { 39 kfree(prop->name); 40 kfree(prop->value); 41 kfree(prop); 42 } 43 44 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) 45 { 46 struct property *prop; 47 char *name; 48 char *value; 49 50 prop = kzalloc(sizeof(*prop), GFP_KERNEL); 51 if (!prop) 52 return NULL; 53 54 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset); 55 prop->name = kstrdup(name, GFP_KERNEL); 56 57 prop->length = be32_to_cpu(ccwa->prop_length); 58 value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset); 59 prop->value = kmemdup(value, prop->length, GFP_KERNEL); 60 if (!prop->value) { 61 dlpar_free_cc_property(prop); 62 return NULL; 63 } 64 65 return prop; 66 } 67 68 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa, 69 const char *path) 70 { 71 struct device_node *dn; 72 char *name; 73 74 /* If parent node path is "/" advance path to NULL terminator to 75 * prevent double leading slashs in full_name. 76 */ 77 if (!path[1]) 78 path++; 79 80 dn = kzalloc(sizeof(*dn), GFP_KERNEL); 81 if (!dn) 82 return NULL; 83 84 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset); 85 dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name); 86 if (!dn->full_name) { 87 kfree(dn); 88 return NULL; 89 } 90 91 of_node_set_flag(dn, OF_DYNAMIC); 92 of_node_init(dn); 93 94 return dn; 95 } 96 97 static void dlpar_free_one_cc_node(struct device_node *dn) 98 { 99 struct property *prop; 100 101 while (dn->properties) { 102 prop = dn->properties; 103 dn->properties = prop->next; 104 dlpar_free_cc_property(prop); 105 } 106 107 kfree(dn->full_name); 108 kfree(dn); 109 } 110 111 void dlpar_free_cc_nodes(struct device_node *dn) 112 { 113 if (dn->child) 114 dlpar_free_cc_nodes(dn->child); 115 116 if (dn->sibling) 117 dlpar_free_cc_nodes(dn->sibling); 118 119 dlpar_free_one_cc_node(dn); 120 } 121 122 #define COMPLETE 0 123 #define NEXT_SIBLING 1 124 #define NEXT_CHILD 2 125 #define NEXT_PROPERTY 3 126 #define PREV_PARENT 4 127 #define MORE_MEMORY 5 128 #define CALL_AGAIN -2 129 #define ERR_CFG_USE -9003 130 131 struct device_node *dlpar_configure_connector(__be32 drc_index, 132 struct device_node *parent) 133 { 134 struct device_node *dn; 135 struct device_node *first_dn = NULL; 136 struct device_node *last_dn = NULL; 137 struct property *property; 138 struct property *last_property = NULL; 139 struct cc_workarea *ccwa; 140 char *data_buf; 141 const char *parent_path = parent->full_name; 142 int cc_token; 143 int rc = -1; 144 145 cc_token = rtas_token("ibm,configure-connector"); 146 if (cc_token == RTAS_UNKNOWN_SERVICE) 147 return NULL; 148 149 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 150 if (!data_buf) 151 return NULL; 152 153 ccwa = (struct cc_workarea *)&data_buf[0]; 154 ccwa->drc_index = drc_index; 155 ccwa->zero = 0; 156 157 do { 158 /* Since we release the rtas_data_buf lock between configure 159 * connector calls we want to re-populate the rtas_data_buffer 160 * with the contents of the previous call. 161 */ 162 spin_lock(&rtas_data_buf_lock); 163 164 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); 165 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 166 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); 167 168 spin_unlock(&rtas_data_buf_lock); 169 170 switch (rc) { 171 case COMPLETE: 172 break; 173 174 case NEXT_SIBLING: 175 dn = dlpar_parse_cc_node(ccwa, parent_path); 176 if (!dn) 177 goto cc_error; 178 179 dn->parent = last_dn->parent; 180 last_dn->sibling = dn; 181 last_dn = dn; 182 break; 183 184 case NEXT_CHILD: 185 if (first_dn) 186 parent_path = last_dn->full_name; 187 188 dn = dlpar_parse_cc_node(ccwa, parent_path); 189 if (!dn) 190 goto cc_error; 191 192 if (!first_dn) { 193 dn->parent = parent; 194 first_dn = dn; 195 } else { 196 dn->parent = last_dn; 197 if (last_dn) 198 last_dn->child = dn; 199 } 200 201 last_dn = dn; 202 break; 203 204 case NEXT_PROPERTY: 205 property = dlpar_parse_cc_property(ccwa); 206 if (!property) 207 goto cc_error; 208 209 if (!last_dn->properties) 210 last_dn->properties = property; 211 else 212 last_property->next = property; 213 214 last_property = property; 215 break; 216 217 case PREV_PARENT: 218 last_dn = last_dn->parent; 219 parent_path = last_dn->parent->full_name; 220 break; 221 222 case CALL_AGAIN: 223 break; 224 225 case MORE_MEMORY: 226 case ERR_CFG_USE: 227 default: 228 printk(KERN_ERR "Unexpected Error (%d) " 229 "returned from configure-connector\n", rc); 230 goto cc_error; 231 } 232 } while (rc); 233 234 cc_error: 235 kfree(data_buf); 236 237 if (rc) { 238 if (first_dn) 239 dlpar_free_cc_nodes(first_dn); 240 241 return NULL; 242 } 243 244 return first_dn; 245 } 246 247 static struct device_node *derive_parent(const char *path) 248 { 249 struct device_node *parent; 250 char *last_slash; 251 252 last_slash = strrchr(path, '/'); 253 if (last_slash == path) { 254 parent = of_find_node_by_path("/"); 255 } else { 256 char *parent_path; 257 int parent_path_len = last_slash - path + 1; 258 parent_path = kmalloc(parent_path_len, GFP_KERNEL); 259 if (!parent_path) 260 return NULL; 261 262 strlcpy(parent_path, path, parent_path_len); 263 parent = of_find_node_by_path(parent_path); 264 kfree(parent_path); 265 } 266 267 return parent; 268 } 269 270 int dlpar_attach_node(struct device_node *dn) 271 { 272 int rc; 273 274 dn->parent = derive_parent(dn->full_name); 275 if (!dn->parent) 276 return -ENOMEM; 277 278 rc = of_attach_node(dn); 279 if (rc) { 280 printk(KERN_ERR "Failed to add device node %s\n", 281 dn->full_name); 282 return rc; 283 } 284 285 of_node_put(dn->parent); 286 return 0; 287 } 288 289 int dlpar_detach_node(struct device_node *dn) 290 { 291 struct device_node *child; 292 int rc; 293 294 child = of_get_next_child(dn, NULL); 295 while (child) { 296 dlpar_detach_node(child); 297 child = of_get_next_child(dn, child); 298 } 299 300 rc = of_detach_node(dn); 301 if (rc) 302 return rc; 303 304 of_node_put(dn); /* Must decrement the refcount */ 305 return 0; 306 } 307 308 #define DR_ENTITY_SENSE 9003 309 #define DR_ENTITY_PRESENT 1 310 #define DR_ENTITY_UNUSABLE 2 311 #define ALLOCATION_STATE 9003 312 #define ALLOC_UNUSABLE 0 313 #define ALLOC_USABLE 1 314 #define ISOLATION_STATE 9001 315 #define ISOLATE 0 316 #define UNISOLATE 1 317 318 int dlpar_acquire_drc(u32 drc_index) 319 { 320 int dr_status, rc; 321 322 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 323 DR_ENTITY_SENSE, drc_index); 324 if (rc || dr_status != DR_ENTITY_UNUSABLE) 325 return -1; 326 327 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); 328 if (rc) 329 return rc; 330 331 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 332 if (rc) { 333 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 334 return rc; 335 } 336 337 return 0; 338 } 339 340 int dlpar_release_drc(u32 drc_index) 341 { 342 int dr_status, rc; 343 344 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 345 DR_ENTITY_SENSE, drc_index); 346 if (rc || dr_status != DR_ENTITY_PRESENT) 347 return -1; 348 349 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); 350 if (rc) 351 return rc; 352 353 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 354 if (rc) { 355 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 356 return rc; 357 } 358 359 return 0; 360 } 361 362 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 363 364 static int dlpar_online_cpu(struct device_node *dn) 365 { 366 int rc = 0; 367 unsigned int cpu; 368 int len, nthreads, i; 369 const __be32 *intserv; 370 u32 thread; 371 372 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 373 if (!intserv) 374 return -EINVAL; 375 376 nthreads = len / sizeof(u32); 377 378 cpu_maps_update_begin(); 379 for (i = 0; i < nthreads; i++) { 380 thread = be32_to_cpu(intserv[i]); 381 for_each_present_cpu(cpu) { 382 if (get_hard_smp_processor_id(cpu) != thread) 383 continue; 384 BUG_ON(get_cpu_current_state(cpu) 385 != CPU_STATE_OFFLINE); 386 cpu_maps_update_done(); 387 rc = device_online(get_cpu_device(cpu)); 388 if (rc) 389 goto out; 390 cpu_maps_update_begin(); 391 392 break; 393 } 394 if (cpu == num_possible_cpus()) 395 printk(KERN_WARNING "Could not find cpu to online " 396 "with physical id 0x%x\n", thread); 397 } 398 cpu_maps_update_done(); 399 400 out: 401 return rc; 402 403 } 404 405 static ssize_t dlpar_cpu_probe(const char *buf, size_t count) 406 { 407 struct device_node *dn, *parent; 408 u32 drc_index; 409 int rc; 410 411 rc = kstrtou32(buf, 0, &drc_index); 412 if (rc) 413 return -EINVAL; 414 415 rc = dlpar_acquire_drc(drc_index); 416 if (rc) 417 return -EINVAL; 418 419 parent = of_find_node_by_path("/cpus"); 420 if (!parent) 421 return -ENODEV; 422 423 dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent); 424 of_node_put(parent); 425 if (!dn) { 426 dlpar_release_drc(drc_index); 427 return -EINVAL; 428 } 429 430 rc = dlpar_attach_node(dn); 431 if (rc) { 432 dlpar_release_drc(drc_index); 433 dlpar_free_cc_nodes(dn); 434 return rc; 435 } 436 437 rc = dlpar_online_cpu(dn); 438 if (rc) 439 return rc; 440 441 return count; 442 } 443 444 static int dlpar_offline_cpu(struct device_node *dn) 445 { 446 int rc = 0; 447 unsigned int cpu; 448 int len, nthreads, i; 449 const __be32 *intserv; 450 u32 thread; 451 452 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 453 if (!intserv) 454 return -EINVAL; 455 456 nthreads = len / sizeof(u32); 457 458 cpu_maps_update_begin(); 459 for (i = 0; i < nthreads; i++) { 460 thread = be32_to_cpu(intserv[i]); 461 for_each_present_cpu(cpu) { 462 if (get_hard_smp_processor_id(cpu) != thread) 463 continue; 464 465 if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE) 466 break; 467 468 if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { 469 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 470 cpu_maps_update_done(); 471 rc = device_offline(get_cpu_device(cpu)); 472 if (rc) 473 goto out; 474 cpu_maps_update_begin(); 475 break; 476 477 } 478 479 /* 480 * The cpu is in CPU_STATE_INACTIVE. 481 * Upgrade it's state to CPU_STATE_OFFLINE. 482 */ 483 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 484 BUG_ON(plpar_hcall_norets(H_PROD, thread) 485 != H_SUCCESS); 486 __cpu_die(cpu); 487 break; 488 } 489 if (cpu == num_possible_cpus()) 490 printk(KERN_WARNING "Could not find cpu to offline " 491 "with physical id 0x%x\n", thread); 492 } 493 cpu_maps_update_done(); 494 495 out: 496 return rc; 497 498 } 499 500 static ssize_t dlpar_cpu_release(const char *buf, size_t count) 501 { 502 struct device_node *dn; 503 u32 drc_index; 504 int rc; 505 506 dn = of_find_node_by_path(buf); 507 if (!dn) 508 return -EINVAL; 509 510 rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index); 511 if (rc) { 512 of_node_put(dn); 513 return -EINVAL; 514 } 515 516 rc = dlpar_offline_cpu(dn); 517 if (rc) { 518 of_node_put(dn); 519 return -EINVAL; 520 } 521 522 rc = dlpar_release_drc(drc_index); 523 if (rc) { 524 of_node_put(dn); 525 return rc; 526 } 527 528 rc = dlpar_detach_node(dn); 529 if (rc) { 530 dlpar_acquire_drc(drc_index); 531 return rc; 532 } 533 534 of_node_put(dn); 535 536 return count; 537 } 538 539 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 540 541 static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) 542 { 543 int rc; 544 545 /* pseries error logs are in BE format, convert to cpu type */ 546 switch (hp_elog->id_type) { 547 case PSERIES_HP_ELOG_ID_DRC_COUNT: 548 hp_elog->_drc_u.drc_count = 549 be32_to_cpu(hp_elog->_drc_u.drc_count); 550 break; 551 case PSERIES_HP_ELOG_ID_DRC_INDEX: 552 hp_elog->_drc_u.drc_index = 553 be32_to_cpu(hp_elog->_drc_u.drc_index); 554 } 555 556 switch (hp_elog->resource) { 557 case PSERIES_HP_ELOG_RESOURCE_MEM: 558 rc = dlpar_memory(hp_elog); 559 break; 560 default: 561 pr_warn_ratelimited("Invalid resource (%d) specified\n", 562 hp_elog->resource); 563 rc = -EINVAL; 564 } 565 566 return rc; 567 } 568 569 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, 570 const char *buf, size_t count) 571 { 572 struct pseries_hp_errorlog *hp_elog; 573 const char *arg; 574 int rc; 575 576 hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); 577 if (!hp_elog) { 578 rc = -ENOMEM; 579 goto dlpar_store_out; 580 } 581 582 /* Parse out the request from the user, this will be in the form 583 * <resource> <action> <id_type> <id> 584 */ 585 arg = buf; 586 if (!strncmp(arg, "memory", 6)) { 587 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; 588 arg += strlen("memory "); 589 } else { 590 pr_err("Invalid resource specified: \"%s\"\n", buf); 591 rc = -EINVAL; 592 goto dlpar_store_out; 593 } 594 595 if (!strncmp(arg, "add", 3)) { 596 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD; 597 arg += strlen("add "); 598 } else if (!strncmp(arg, "remove", 6)) { 599 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE; 600 arg += strlen("remove "); 601 } else { 602 pr_err("Invalid action specified: \"%s\"\n", buf); 603 rc = -EINVAL; 604 goto dlpar_store_out; 605 } 606 607 if (!strncmp(arg, "index", 5)) { 608 u32 index; 609 610 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; 611 arg += strlen("index "); 612 if (kstrtou32(arg, 0, &index)) { 613 rc = -EINVAL; 614 pr_err("Invalid drc_index specified: \"%s\"\n", buf); 615 goto dlpar_store_out; 616 } 617 618 hp_elog->_drc_u.drc_index = cpu_to_be32(index); 619 } else if (!strncmp(arg, "count", 5)) { 620 u32 count; 621 622 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT; 623 arg += strlen("count "); 624 if (kstrtou32(arg, 0, &count)) { 625 rc = -EINVAL; 626 pr_err("Invalid count specified: \"%s\"\n", buf); 627 goto dlpar_store_out; 628 } 629 630 hp_elog->_drc_u.drc_count = cpu_to_be32(count); 631 } else { 632 pr_err("Invalid id_type specified: \"%s\"\n", buf); 633 rc = -EINVAL; 634 goto dlpar_store_out; 635 } 636 637 rc = handle_dlpar_errorlog(hp_elog); 638 639 dlpar_store_out: 640 kfree(hp_elog); 641 return rc ? rc : count; 642 } 643 644 static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store); 645 646 static int __init pseries_dlpar_init(void) 647 { 648 int rc; 649 650 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 651 ppc_md.cpu_probe = dlpar_cpu_probe; 652 ppc_md.cpu_release = dlpar_cpu_release; 653 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 654 655 rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); 656 657 return rc; 658 } 659 machine_device_initcall(pseries, pseries_dlpar_init); 660 661