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 #include <linux/kernel.h> 14 #include <linux/kref.h> 15 #include <linux/notifier.h> 16 #include <linux/proc_fs.h> 17 #include <linux/spinlock.h> 18 #include <linux/cpu.h> 19 #include <linux/slab.h> 20 #include "offline_states.h" 21 22 #include <asm/prom.h> 23 #include <asm/machdep.h> 24 #include <asm/uaccess.h> 25 #include <asm/rtas.h> 26 #include <asm/pSeries_reconfig.h> 27 28 struct cc_workarea { 29 u32 drc_index; 30 u32 zero; 31 u32 name_offset; 32 u32 prop_length; 33 u32 prop_offset; 34 }; 35 36 void dlpar_free_cc_property(struct property *prop) 37 { 38 kfree(prop->name); 39 kfree(prop->value); 40 kfree(prop); 41 } 42 43 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) 44 { 45 struct property *prop; 46 char *name; 47 char *value; 48 49 prop = kzalloc(sizeof(*prop), GFP_KERNEL); 50 if (!prop) 51 return NULL; 52 53 name = (char *)ccwa + ccwa->name_offset; 54 prop->name = kstrdup(name, GFP_KERNEL); 55 56 prop->length = ccwa->prop_length; 57 value = (char *)ccwa + ccwa->prop_offset; 58 prop->value = kmemdup(value, prop->length, GFP_KERNEL); 59 if (!prop->value) { 60 dlpar_free_cc_property(prop); 61 return NULL; 62 } 63 64 return prop; 65 } 66 67 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa) 68 { 69 struct device_node *dn; 70 char *name; 71 72 dn = kzalloc(sizeof(*dn), GFP_KERNEL); 73 if (!dn) 74 return NULL; 75 76 /* The configure connector reported name does not contain a 77 * preceding '/', so we allocate a buffer large enough to 78 * prepend this to the full_name. 79 */ 80 name = (char *)ccwa + ccwa->name_offset; 81 dn->full_name = kasprintf(GFP_KERNEL, "/%s", name); 82 if (!dn->full_name) { 83 kfree(dn); 84 return NULL; 85 } 86 87 return dn; 88 } 89 90 static void dlpar_free_one_cc_node(struct device_node *dn) 91 { 92 struct property *prop; 93 94 while (dn->properties) { 95 prop = dn->properties; 96 dn->properties = prop->next; 97 dlpar_free_cc_property(prop); 98 } 99 100 kfree(dn->full_name); 101 kfree(dn); 102 } 103 104 void dlpar_free_cc_nodes(struct device_node *dn) 105 { 106 if (dn->child) 107 dlpar_free_cc_nodes(dn->child); 108 109 if (dn->sibling) 110 dlpar_free_cc_nodes(dn->sibling); 111 112 dlpar_free_one_cc_node(dn); 113 } 114 115 #define COMPLETE 0 116 #define NEXT_SIBLING 1 117 #define NEXT_CHILD 2 118 #define NEXT_PROPERTY 3 119 #define PREV_PARENT 4 120 #define MORE_MEMORY 5 121 #define CALL_AGAIN -2 122 #define ERR_CFG_USE -9003 123 124 struct device_node *dlpar_configure_connector(u32 drc_index) 125 { 126 struct device_node *dn; 127 struct device_node *first_dn = NULL; 128 struct device_node *last_dn = NULL; 129 struct property *property; 130 struct property *last_property = NULL; 131 struct cc_workarea *ccwa; 132 char *data_buf; 133 int cc_token; 134 int rc = -1; 135 136 cc_token = rtas_token("ibm,configure-connector"); 137 if (cc_token == RTAS_UNKNOWN_SERVICE) 138 return NULL; 139 140 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 141 if (!data_buf) 142 return NULL; 143 144 ccwa = (struct cc_workarea *)&data_buf[0]; 145 ccwa->drc_index = drc_index; 146 ccwa->zero = 0; 147 148 do { 149 /* Since we release the rtas_data_buf lock between configure 150 * connector calls we want to re-populate the rtas_data_buffer 151 * with the contents of the previous call. 152 */ 153 spin_lock(&rtas_data_buf_lock); 154 155 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); 156 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 157 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); 158 159 spin_unlock(&rtas_data_buf_lock); 160 161 switch (rc) { 162 case COMPLETE: 163 break; 164 165 case NEXT_SIBLING: 166 dn = dlpar_parse_cc_node(ccwa); 167 if (!dn) 168 goto cc_error; 169 170 dn->parent = last_dn->parent; 171 last_dn->sibling = dn; 172 last_dn = dn; 173 break; 174 175 case NEXT_CHILD: 176 dn = dlpar_parse_cc_node(ccwa); 177 if (!dn) 178 goto cc_error; 179 180 if (!first_dn) 181 first_dn = dn; 182 else { 183 dn->parent = last_dn; 184 if (last_dn) 185 last_dn->child = dn; 186 } 187 188 last_dn = dn; 189 break; 190 191 case NEXT_PROPERTY: 192 property = dlpar_parse_cc_property(ccwa); 193 if (!property) 194 goto cc_error; 195 196 if (!last_dn->properties) 197 last_dn->properties = property; 198 else 199 last_property->next = property; 200 201 last_property = property; 202 break; 203 204 case PREV_PARENT: 205 last_dn = last_dn->parent; 206 break; 207 208 case CALL_AGAIN: 209 break; 210 211 case MORE_MEMORY: 212 case ERR_CFG_USE: 213 default: 214 printk(KERN_ERR "Unexpected Error (%d) " 215 "returned from configure-connector\n", rc); 216 goto cc_error; 217 } 218 } while (rc); 219 220 cc_error: 221 kfree(data_buf); 222 223 if (rc) { 224 if (first_dn) 225 dlpar_free_cc_nodes(first_dn); 226 227 return NULL; 228 } 229 230 return first_dn; 231 } 232 233 static struct device_node *derive_parent(const char *path) 234 { 235 struct device_node *parent; 236 char *last_slash; 237 238 last_slash = strrchr(path, '/'); 239 if (last_slash == path) { 240 parent = of_find_node_by_path("/"); 241 } else { 242 char *parent_path; 243 int parent_path_len = last_slash - path + 1; 244 parent_path = kmalloc(parent_path_len, GFP_KERNEL); 245 if (!parent_path) 246 return NULL; 247 248 strlcpy(parent_path, path, parent_path_len); 249 parent = of_find_node_by_path(parent_path); 250 kfree(parent_path); 251 } 252 253 return parent; 254 } 255 256 int dlpar_attach_node(struct device_node *dn) 257 { 258 #ifdef CONFIG_PROC_DEVICETREE 259 struct proc_dir_entry *ent; 260 #endif 261 int rc; 262 263 of_node_set_flag(dn, OF_DYNAMIC); 264 kref_init(&dn->kref); 265 dn->parent = derive_parent(dn->full_name); 266 if (!dn->parent) 267 return -ENOMEM; 268 269 rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn); 270 if (rc) { 271 printk(KERN_ERR "Failed to add device node %s\n", 272 dn->full_name); 273 return rc; 274 } 275 276 of_attach_node(dn); 277 278 #ifdef CONFIG_PROC_DEVICETREE 279 ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); 280 if (ent) 281 proc_device_tree_add_node(dn, ent); 282 #endif 283 284 of_node_put(dn->parent); 285 return 0; 286 } 287 288 int dlpar_detach_node(struct device_node *dn) 289 { 290 #ifdef CONFIG_PROC_DEVICETREE 291 struct device_node *parent = dn->parent; 292 struct property *prop = dn->properties; 293 294 while (prop) { 295 remove_proc_entry(prop->name, dn->pde); 296 prop = prop->next; 297 } 298 299 if (dn->pde) 300 remove_proc_entry(dn->pde->name, parent->pde); 301 #endif 302 303 pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn); 304 of_detach_node(dn); 305 of_node_put(dn); /* Must decrement the refcount */ 306 307 return 0; 308 } 309 310 #define DR_ENTITY_SENSE 9003 311 #define DR_ENTITY_PRESENT 1 312 #define DR_ENTITY_UNUSABLE 2 313 #define ALLOCATION_STATE 9003 314 #define ALLOC_UNUSABLE 0 315 #define ALLOC_USABLE 1 316 #define ISOLATION_STATE 9001 317 #define ISOLATE 0 318 #define UNISOLATE 1 319 320 int dlpar_acquire_drc(u32 drc_index) 321 { 322 int dr_status, rc; 323 324 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 325 DR_ENTITY_SENSE, drc_index); 326 if (rc || dr_status != DR_ENTITY_UNUSABLE) 327 return -1; 328 329 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); 330 if (rc) 331 return rc; 332 333 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 334 if (rc) { 335 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 336 return rc; 337 } 338 339 return 0; 340 } 341 342 int dlpar_release_drc(u32 drc_index) 343 { 344 int dr_status, rc; 345 346 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 347 DR_ENTITY_SENSE, drc_index); 348 if (rc || dr_status != DR_ENTITY_PRESENT) 349 return -1; 350 351 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); 352 if (rc) 353 return rc; 354 355 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 356 if (rc) { 357 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 358 return rc; 359 } 360 361 return 0; 362 } 363 364 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 365 366 static int dlpar_online_cpu(struct device_node *dn) 367 { 368 int rc = 0; 369 unsigned int cpu; 370 int len, nthreads, i; 371 const u32 *intserv; 372 373 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 374 if (!intserv) 375 return -EINVAL; 376 377 nthreads = len / sizeof(u32); 378 379 cpu_maps_update_begin(); 380 for (i = 0; i < nthreads; i++) { 381 for_each_present_cpu(cpu) { 382 if (get_hard_smp_processor_id(cpu) != intserv[i]) 383 continue; 384 BUG_ON(get_cpu_current_state(cpu) 385 != CPU_STATE_OFFLINE); 386 cpu_maps_update_done(); 387 rc = cpu_up(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", intserv[i]); 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; 408 unsigned long drc_index; 409 char *cpu_name; 410 int rc; 411 412 cpu_hotplug_driver_lock(); 413 rc = strict_strtoul(buf, 0, &drc_index); 414 if (rc) { 415 rc = -EINVAL; 416 goto out; 417 } 418 419 dn = dlpar_configure_connector(drc_index); 420 if (!dn) { 421 rc = -EINVAL; 422 goto out; 423 } 424 425 /* configure-connector reports cpus as living in the base 426 * directory of the device tree. CPUs actually live in the 427 * cpus directory so we need to fixup the full_name. 428 */ 429 cpu_name = kasprintf(GFP_KERNEL, "/cpus%s", dn->full_name); 430 if (!cpu_name) { 431 dlpar_free_cc_nodes(dn); 432 rc = -ENOMEM; 433 goto out; 434 } 435 436 kfree(dn->full_name); 437 dn->full_name = cpu_name; 438 439 rc = dlpar_acquire_drc(drc_index); 440 if (rc) { 441 dlpar_free_cc_nodes(dn); 442 rc = -EINVAL; 443 goto out; 444 } 445 446 rc = dlpar_attach_node(dn); 447 if (rc) { 448 dlpar_release_drc(drc_index); 449 dlpar_free_cc_nodes(dn); 450 goto out; 451 } 452 453 rc = dlpar_online_cpu(dn); 454 out: 455 cpu_hotplug_driver_unlock(); 456 457 return rc ? rc : count; 458 } 459 460 static int dlpar_offline_cpu(struct device_node *dn) 461 { 462 int rc = 0; 463 unsigned int cpu; 464 int len, nthreads, i; 465 const u32 *intserv; 466 467 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 468 if (!intserv) 469 return -EINVAL; 470 471 nthreads = len / sizeof(u32); 472 473 cpu_maps_update_begin(); 474 for (i = 0; i < nthreads; i++) { 475 for_each_present_cpu(cpu) { 476 if (get_hard_smp_processor_id(cpu) != intserv[i]) 477 continue; 478 479 if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE) 480 break; 481 482 if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { 483 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 484 cpu_maps_update_done(); 485 rc = cpu_down(cpu); 486 if (rc) 487 goto out; 488 cpu_maps_update_begin(); 489 break; 490 491 } 492 493 /* 494 * The cpu is in CPU_STATE_INACTIVE. 495 * Upgrade it's state to CPU_STATE_OFFLINE. 496 */ 497 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 498 BUG_ON(plpar_hcall_norets(H_PROD, intserv[i]) 499 != H_SUCCESS); 500 __cpu_die(cpu); 501 break; 502 } 503 if (cpu == num_possible_cpus()) 504 printk(KERN_WARNING "Could not find cpu to offline " 505 "with physical id 0x%x\n", intserv[i]); 506 } 507 cpu_maps_update_done(); 508 509 out: 510 return rc; 511 512 } 513 514 static ssize_t dlpar_cpu_release(const char *buf, size_t count) 515 { 516 struct device_node *dn; 517 const u32 *drc_index; 518 int rc; 519 520 dn = of_find_node_by_path(buf); 521 if (!dn) 522 return -EINVAL; 523 524 drc_index = of_get_property(dn, "ibm,my-drc-index", NULL); 525 if (!drc_index) { 526 of_node_put(dn); 527 return -EINVAL; 528 } 529 530 cpu_hotplug_driver_lock(); 531 rc = dlpar_offline_cpu(dn); 532 if (rc) { 533 of_node_put(dn); 534 rc = -EINVAL; 535 goto out; 536 } 537 538 rc = dlpar_release_drc(*drc_index); 539 if (rc) { 540 of_node_put(dn); 541 goto out; 542 } 543 544 rc = dlpar_detach_node(dn); 545 if (rc) { 546 dlpar_acquire_drc(*drc_index); 547 goto out; 548 } 549 550 of_node_put(dn); 551 out: 552 cpu_hotplug_driver_unlock(); 553 return rc ? rc : count; 554 } 555 556 static int __init pseries_dlpar_init(void) 557 { 558 ppc_md.cpu_probe = dlpar_cpu_probe; 559 ppc_md.cpu_release = dlpar_cpu_release; 560 561 return 0; 562 } 563 machine_device_initcall(pseries, pseries_dlpar_init); 564 565 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 566