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