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