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 20 #include <asm/prom.h> 21 #include <asm/machdep.h> 22 #include <asm/uaccess.h> 23 #include <asm/rtas.h> 24 #include <asm/pSeries_reconfig.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 static 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 = kzalloc(prop->length, GFP_KERNEL); 57 if (!prop->value) { 58 dlpar_free_cc_property(prop); 59 return NULL; 60 } 61 62 memcpy(prop->value, value, prop->length); 63 return prop; 64 } 65 66 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa) 67 { 68 struct device_node *dn; 69 char *name; 70 71 dn = kzalloc(sizeof(*dn), GFP_KERNEL); 72 if (!dn) 73 return NULL; 74 75 /* The configure connector reported name does not contain a 76 * preceeding '/', so we allocate a buffer large enough to 77 * prepend this to the full_name. 78 */ 79 name = (char *)ccwa + ccwa->name_offset; 80 dn->full_name = kmalloc(strlen(name) + 2, GFP_KERNEL); 81 if (!dn->full_name) { 82 kfree(dn); 83 return NULL; 84 } 85 86 sprintf(dn->full_name, "/%s", name); 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 static 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 int cc_token; 132 int rc; 133 134 cc_token = rtas_token("ibm,configure-connector"); 135 if (cc_token == RTAS_UNKNOWN_SERVICE) 136 return NULL; 137 138 spin_lock(&rtas_data_buf_lock); 139 ccwa = (struct cc_workarea *)&rtas_data_buf[0]; 140 ccwa->drc_index = drc_index; 141 ccwa->zero = 0; 142 143 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 144 while (rc) { 145 switch (rc) { 146 case NEXT_SIBLING: 147 dn = dlpar_parse_cc_node(ccwa); 148 if (!dn) 149 goto cc_error; 150 151 dn->parent = last_dn->parent; 152 last_dn->sibling = dn; 153 last_dn = dn; 154 break; 155 156 case NEXT_CHILD: 157 dn = dlpar_parse_cc_node(ccwa); 158 if (!dn) 159 goto cc_error; 160 161 if (!first_dn) 162 first_dn = dn; 163 else { 164 dn->parent = last_dn; 165 if (last_dn) 166 last_dn->child = dn; 167 } 168 169 last_dn = dn; 170 break; 171 172 case NEXT_PROPERTY: 173 property = dlpar_parse_cc_property(ccwa); 174 if (!property) 175 goto cc_error; 176 177 if (!last_dn->properties) 178 last_dn->properties = property; 179 else 180 last_property->next = property; 181 182 last_property = property; 183 break; 184 185 case PREV_PARENT: 186 last_dn = last_dn->parent; 187 break; 188 189 case CALL_AGAIN: 190 break; 191 192 case MORE_MEMORY: 193 case ERR_CFG_USE: 194 default: 195 printk(KERN_ERR "Unexpected Error (%d) " 196 "returned from configure-connector\n", rc); 197 goto cc_error; 198 } 199 200 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 201 } 202 203 spin_unlock(&rtas_data_buf_lock); 204 return first_dn; 205 206 cc_error: 207 if (first_dn) 208 dlpar_free_cc_nodes(first_dn); 209 spin_unlock(&rtas_data_buf_lock); 210 return NULL; 211 } 212 213 static struct device_node *derive_parent(const char *path) 214 { 215 struct device_node *parent; 216 char *last_slash; 217 218 last_slash = strrchr(path, '/'); 219 if (last_slash == path) { 220 parent = of_find_node_by_path("/"); 221 } else { 222 char *parent_path; 223 int parent_path_len = last_slash - path + 1; 224 parent_path = kmalloc(parent_path_len, GFP_KERNEL); 225 if (!parent_path) 226 return NULL; 227 228 strlcpy(parent_path, path, parent_path_len); 229 parent = of_find_node_by_path(parent_path); 230 kfree(parent_path); 231 } 232 233 return parent; 234 } 235 236 int dlpar_attach_node(struct device_node *dn) 237 { 238 struct proc_dir_entry *ent; 239 int rc; 240 241 of_node_set_flag(dn, OF_DYNAMIC); 242 kref_init(&dn->kref); 243 dn->parent = derive_parent(dn->full_name); 244 if (!dn->parent) 245 return -ENOMEM; 246 247 rc = blocking_notifier_call_chain(&pSeries_reconfig_chain, 248 PSERIES_RECONFIG_ADD, dn); 249 if (rc == NOTIFY_BAD) { 250 printk(KERN_ERR "Failed to add device node %s\n", 251 dn->full_name); 252 return -ENOMEM; /* For now, safe to assume kmalloc failure */ 253 } 254 255 of_attach_node(dn); 256 257 #ifdef CONFIG_PROC_DEVICETREE 258 ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); 259 if (ent) 260 proc_device_tree_add_node(dn, ent); 261 #endif 262 263 of_node_put(dn->parent); 264 return 0; 265 } 266 267 int dlpar_detach_node(struct device_node *dn) 268 { 269 struct device_node *parent = dn->parent; 270 struct property *prop = dn->properties; 271 272 #ifdef CONFIG_PROC_DEVICETREE 273 while (prop) { 274 remove_proc_entry(prop->name, dn->pde); 275 prop = prop->next; 276 } 277 278 if (dn->pde) 279 remove_proc_entry(dn->pde->name, parent->pde); 280 #endif 281 282 blocking_notifier_call_chain(&pSeries_reconfig_chain, 283 PSERIES_RECONFIG_REMOVE, dn); 284 of_detach_node(dn); 285 of_node_put(dn); /* Must decrement the refcount */ 286 287 return 0; 288 } 289 290 #define DR_ENTITY_SENSE 9003 291 #define DR_ENTITY_PRESENT 1 292 #define DR_ENTITY_UNUSABLE 2 293 #define ALLOCATION_STATE 9003 294 #define ALLOC_UNUSABLE 0 295 #define ALLOC_USABLE 1 296 #define ISOLATION_STATE 9001 297 #define ISOLATE 0 298 #define UNISOLATE 1 299 300 int dlpar_acquire_drc(u32 drc_index) 301 { 302 int dr_status, rc; 303 304 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 305 DR_ENTITY_SENSE, drc_index); 306 if (rc || dr_status != DR_ENTITY_UNUSABLE) 307 return -1; 308 309 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); 310 if (rc) 311 return rc; 312 313 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 314 if (rc) { 315 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 316 return rc; 317 } 318 319 return 0; 320 } 321 322 int dlpar_release_drc(u32 drc_index) 323 { 324 int dr_status, rc; 325 326 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 327 DR_ENTITY_SENSE, drc_index); 328 if (rc || dr_status != DR_ENTITY_PRESENT) 329 return -1; 330 331 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); 332 if (rc) 333 return rc; 334 335 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 336 if (rc) { 337 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 338 return rc; 339 } 340 341 return 0; 342 } 343 344 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 345 346 static ssize_t dlpar_cpu_probe(const char *buf, size_t count) 347 { 348 struct device_node *dn; 349 unsigned long drc_index; 350 char *cpu_name; 351 int rc; 352 353 rc = strict_strtoul(buf, 0, &drc_index); 354 if (rc) 355 return -EINVAL; 356 357 dn = dlpar_configure_connector(drc_index); 358 if (!dn) 359 return -EINVAL; 360 361 /* configure-connector reports cpus as living in the base 362 * directory of the device tree. CPUs actually live in the 363 * cpus directory so we need to fixup the full_name. 364 */ 365 cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus") + 1, 366 GFP_KERNEL); 367 if (!cpu_name) { 368 dlpar_free_cc_nodes(dn); 369 return -ENOMEM; 370 } 371 372 sprintf(cpu_name, "/cpus%s", dn->full_name); 373 kfree(dn->full_name); 374 dn->full_name = cpu_name; 375 376 rc = dlpar_acquire_drc(drc_index); 377 if (rc) { 378 dlpar_free_cc_nodes(dn); 379 return -EINVAL; 380 } 381 382 rc = dlpar_attach_node(dn); 383 if (rc) { 384 dlpar_release_drc(drc_index); 385 dlpar_free_cc_nodes(dn); 386 } 387 388 return rc ? rc : count; 389 } 390 391 static ssize_t dlpar_cpu_release(const char *buf, size_t count) 392 { 393 struct device_node *dn; 394 const u32 *drc_index; 395 int rc; 396 397 dn = of_find_node_by_path(buf); 398 if (!dn) 399 return -EINVAL; 400 401 drc_index = of_get_property(dn, "ibm,my-drc-index", NULL); 402 if (!drc_index) { 403 of_node_put(dn); 404 return -EINVAL; 405 } 406 407 rc = dlpar_release_drc(*drc_index); 408 if (rc) { 409 of_node_put(dn); 410 return -EINVAL; 411 } 412 413 rc = dlpar_detach_node(dn); 414 if (rc) { 415 dlpar_acquire_drc(*drc_index); 416 return rc; 417 } 418 419 of_node_put(dn); 420 return count; 421 } 422 423 static int __init pseries_dlpar_init(void) 424 { 425 ppc_md.cpu_probe = dlpar_cpu_probe; 426 ppc_md.cpu_release = dlpar_cpu_release; 427 428 return 0; 429 } 430 machine_device_initcall(pseries, pseries_dlpar_init); 431 432 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 433