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 * preceeding '/', 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 NEXT_SIBLING 1 116 #define NEXT_CHILD 2 117 #define NEXT_PROPERTY 3 118 #define PREV_PARENT 4 119 #define MORE_MEMORY 5 120 #define CALL_AGAIN -2 121 #define ERR_CFG_USE -9003 122 123 struct device_node *dlpar_configure_connector(u32 drc_index) 124 { 125 struct device_node *dn; 126 struct device_node *first_dn = NULL; 127 struct device_node *last_dn = NULL; 128 struct property *property; 129 struct property *last_property = NULL; 130 struct cc_workarea *ccwa; 131 char *data_buf; 132 int cc_token; 133 int rc = -1; 134 135 cc_token = rtas_token("ibm,configure-connector"); 136 if (cc_token == RTAS_UNKNOWN_SERVICE) 137 return NULL; 138 139 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 140 if (!data_buf) 141 return NULL; 142 143 ccwa = (struct cc_workarea *)&data_buf[0]; 144 ccwa->drc_index = drc_index; 145 ccwa->zero = 0; 146 147 do { 148 /* Since we release the rtas_data_buf lock between configure 149 * connector calls we want to re-populate the rtas_data_buffer 150 * with the contents of the previous call. 151 */ 152 spin_lock(&rtas_data_buf_lock); 153 154 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); 155 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 156 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); 157 158 spin_unlock(&rtas_data_buf_lock); 159 160 switch (rc) { 161 case NEXT_SIBLING: 162 dn = dlpar_parse_cc_node(ccwa); 163 if (!dn) 164 goto cc_error; 165 166 dn->parent = last_dn->parent; 167 last_dn->sibling = dn; 168 last_dn = dn; 169 break; 170 171 case NEXT_CHILD: 172 dn = dlpar_parse_cc_node(ccwa); 173 if (!dn) 174 goto cc_error; 175 176 if (!first_dn) 177 first_dn = dn; 178 else { 179 dn->parent = last_dn; 180 if (last_dn) 181 last_dn->child = dn; 182 } 183 184 last_dn = dn; 185 break; 186 187 case NEXT_PROPERTY: 188 property = dlpar_parse_cc_property(ccwa); 189 if (!property) 190 goto cc_error; 191 192 if (!last_dn->properties) 193 last_dn->properties = property; 194 else 195 last_property->next = property; 196 197 last_property = property; 198 break; 199 200 case PREV_PARENT: 201 last_dn = last_dn->parent; 202 break; 203 204 case CALL_AGAIN: 205 break; 206 207 case MORE_MEMORY: 208 case ERR_CFG_USE: 209 default: 210 printk(KERN_ERR "Unexpected Error (%d) " 211 "returned from configure-connector\n", rc); 212 goto cc_error; 213 } 214 } while (rc); 215 216 cc_error: 217 kfree(data_buf); 218 219 if (rc) { 220 if (first_dn) 221 dlpar_free_cc_nodes(first_dn); 222 223 return NULL; 224 } 225 226 return first_dn; 227 } 228 229 static struct device_node *derive_parent(const char *path) 230 { 231 struct device_node *parent; 232 char *last_slash; 233 234 last_slash = strrchr(path, '/'); 235 if (last_slash == path) { 236 parent = of_find_node_by_path("/"); 237 } else { 238 char *parent_path; 239 int parent_path_len = last_slash - path + 1; 240 parent_path = kmalloc(parent_path_len, GFP_KERNEL); 241 if (!parent_path) 242 return NULL; 243 244 strlcpy(parent_path, path, parent_path_len); 245 parent = of_find_node_by_path(parent_path); 246 kfree(parent_path); 247 } 248 249 return parent; 250 } 251 252 int dlpar_attach_node(struct device_node *dn) 253 { 254 #ifdef CONFIG_PROC_DEVICETREE 255 struct proc_dir_entry *ent; 256 #endif 257 int rc; 258 259 of_node_set_flag(dn, OF_DYNAMIC); 260 kref_init(&dn->kref); 261 dn->parent = derive_parent(dn->full_name); 262 if (!dn->parent) 263 return -ENOMEM; 264 265 rc = blocking_notifier_call_chain(&pSeries_reconfig_chain, 266 PSERIES_RECONFIG_ADD, dn); 267 if (rc == NOTIFY_BAD) { 268 printk(KERN_ERR "Failed to add device node %s\n", 269 dn->full_name); 270 return -ENOMEM; /* For now, safe to assume kmalloc failure */ 271 } 272 273 of_attach_node(dn); 274 275 #ifdef CONFIG_PROC_DEVICETREE 276 ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); 277 if (ent) 278 proc_device_tree_add_node(dn, ent); 279 #endif 280 281 of_node_put(dn->parent); 282 return 0; 283 } 284 285 int dlpar_detach_node(struct device_node *dn) 286 { 287 #ifdef CONFIG_PROC_DEVICETREE 288 struct device_node *parent = dn->parent; 289 struct property *prop = dn->properties; 290 291 while (prop) { 292 remove_proc_entry(prop->name, dn->pde); 293 prop = prop->next; 294 } 295 296 if (dn->pde) 297 remove_proc_entry(dn->pde->name, parent->pde); 298 #endif 299 300 blocking_notifier_call_chain(&pSeries_reconfig_chain, 301 PSERIES_RECONFIG_REMOVE, dn); 302 of_detach_node(dn); 303 of_node_put(dn); /* Must decrement the refcount */ 304 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 u32 *intserv; 370 371 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 372 if (!intserv) 373 return -EINVAL; 374 375 nthreads = len / sizeof(u32); 376 377 cpu_maps_update_begin(); 378 for (i = 0; i < nthreads; i++) { 379 for_each_present_cpu(cpu) { 380 if (get_hard_smp_processor_id(cpu) != intserv[i]) 381 continue; 382 BUG_ON(get_cpu_current_state(cpu) 383 != CPU_STATE_OFFLINE); 384 cpu_maps_update_done(); 385 rc = cpu_up(cpu); 386 if (rc) 387 goto out; 388 cpu_maps_update_begin(); 389 390 break; 391 } 392 if (cpu == num_possible_cpus()) 393 printk(KERN_WARNING "Could not find cpu to online " 394 "with physical id 0x%x\n", intserv[i]); 395 } 396 cpu_maps_update_done(); 397 398 out: 399 return rc; 400 401 } 402 403 static ssize_t dlpar_cpu_probe(const char *buf, size_t count) 404 { 405 struct device_node *dn; 406 unsigned long drc_index; 407 char *cpu_name; 408 int rc; 409 410 cpu_hotplug_driver_lock(); 411 rc = strict_strtoul(buf, 0, &drc_index); 412 if (rc) { 413 rc = -EINVAL; 414 goto out; 415 } 416 417 dn = dlpar_configure_connector(drc_index); 418 if (!dn) { 419 rc = -EINVAL; 420 goto out; 421 } 422 423 /* configure-connector reports cpus as living in the base 424 * directory of the device tree. CPUs actually live in the 425 * cpus directory so we need to fixup the full_name. 426 */ 427 cpu_name = kasprintf(GFP_KERNEL, "/cpus%s", dn->full_name); 428 if (!cpu_name) { 429 dlpar_free_cc_nodes(dn); 430 rc = -ENOMEM; 431 goto out; 432 } 433 434 kfree(dn->full_name); 435 dn->full_name = cpu_name; 436 437 rc = dlpar_acquire_drc(drc_index); 438 if (rc) { 439 dlpar_free_cc_nodes(dn); 440 rc = -EINVAL; 441 goto out; 442 } 443 444 rc = dlpar_attach_node(dn); 445 if (rc) { 446 dlpar_release_drc(drc_index); 447 dlpar_free_cc_nodes(dn); 448 goto out; 449 } 450 451 rc = dlpar_online_cpu(dn); 452 out: 453 cpu_hotplug_driver_unlock(); 454 455 return rc ? rc : count; 456 } 457 458 static int dlpar_offline_cpu(struct device_node *dn) 459 { 460 int rc = 0; 461 unsigned int cpu; 462 int len, nthreads, i; 463 const u32 *intserv; 464 465 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); 466 if (!intserv) 467 return -EINVAL; 468 469 nthreads = len / sizeof(u32); 470 471 cpu_maps_update_begin(); 472 for (i = 0; i < nthreads; i++) { 473 for_each_present_cpu(cpu) { 474 if (get_hard_smp_processor_id(cpu) != intserv[i]) 475 continue; 476 477 if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE) 478 break; 479 480 if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { 481 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 482 cpu_maps_update_done(); 483 rc = cpu_down(cpu); 484 if (rc) 485 goto out; 486 cpu_maps_update_begin(); 487 break; 488 489 } 490 491 /* 492 * The cpu is in CPU_STATE_INACTIVE. 493 * Upgrade it's state to CPU_STATE_OFFLINE. 494 */ 495 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); 496 BUG_ON(plpar_hcall_norets(H_PROD, intserv[i]) 497 != H_SUCCESS); 498 __cpu_die(cpu); 499 break; 500 } 501 if (cpu == num_possible_cpus()) 502 printk(KERN_WARNING "Could not find cpu to offline " 503 "with physical id 0x%x\n", intserv[i]); 504 } 505 cpu_maps_update_done(); 506 507 out: 508 return rc; 509 510 } 511 512 static ssize_t dlpar_cpu_release(const char *buf, size_t count) 513 { 514 struct device_node *dn; 515 const u32 *drc_index; 516 int rc; 517 518 dn = of_find_node_by_path(buf); 519 if (!dn) 520 return -EINVAL; 521 522 drc_index = of_get_property(dn, "ibm,my-drc-index", NULL); 523 if (!drc_index) { 524 of_node_put(dn); 525 return -EINVAL; 526 } 527 528 cpu_hotplug_driver_lock(); 529 rc = dlpar_offline_cpu(dn); 530 if (rc) { 531 of_node_put(dn); 532 rc = -EINVAL; 533 goto out; 534 } 535 536 rc = dlpar_release_drc(*drc_index); 537 if (rc) { 538 of_node_put(dn); 539 goto out; 540 } 541 542 rc = dlpar_detach_node(dn); 543 if (rc) { 544 dlpar_acquire_drc(*drc_index); 545 goto out; 546 } 547 548 of_node_put(dn); 549 out: 550 cpu_hotplug_driver_unlock(); 551 return rc ? rc : count; 552 } 553 554 static int __init pseries_dlpar_init(void) 555 { 556 ppc_md.cpu_probe = dlpar_cpu_probe; 557 ppc_md.cpu_release = dlpar_cpu_release; 558 559 return 0; 560 } 561 machine_device_initcall(pseries, pseries_dlpar_init); 562 563 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 564