1 /* 2 * pSeries_reconfig.c - support for dynamic reconfiguration (including PCI 3 * Hotplug and Dynamic Logical Partitioning on RPA platforms). 4 * 5 * Copyright (C) 2005 Nathan Lynch 6 * Copyright (C) 2005 IBM Corporation 7 * 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License version 11 * 2 as published by the Free Software Foundation. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/kref.h> 16 #include <linux/notifier.h> 17 #include <linux/proc_fs.h> 18 19 #include <asm/prom.h> 20 #include <asm/machdep.h> 21 #include <asm/uaccess.h> 22 #include <asm/pSeries_reconfig.h> 23 24 25 26 /* 27 * Routines for "runtime" addition and removal of device tree nodes. 28 */ 29 #ifdef CONFIG_PROC_DEVICETREE 30 /* 31 * Add a node to /proc/device-tree. 32 */ 33 static void add_node_proc_entries(struct device_node *np) 34 { 35 struct proc_dir_entry *ent; 36 37 ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde); 38 if (ent) 39 proc_device_tree_add_node(np, ent); 40 } 41 42 static void remove_node_proc_entries(struct device_node *np) 43 { 44 struct property *pp = np->properties; 45 struct device_node *parent = np->parent; 46 47 while (pp) { 48 remove_proc_entry(pp->name, np->pde); 49 pp = pp->next; 50 } 51 if (np->pde) 52 remove_proc_entry(np->pde->name, parent->pde); 53 } 54 #else /* !CONFIG_PROC_DEVICETREE */ 55 static void add_node_proc_entries(struct device_node *np) 56 { 57 return; 58 } 59 60 static void remove_node_proc_entries(struct device_node *np) 61 { 62 return; 63 } 64 #endif /* CONFIG_PROC_DEVICETREE */ 65 66 /** 67 * derive_parent - basically like dirname(1) 68 * @path: the full_name of a node to be added to the tree 69 * 70 * Returns the node which should be the parent of the node 71 * described by path. E.g., for path = "/foo/bar", returns 72 * the node with full_name = "/foo". 73 */ 74 static struct device_node *derive_parent(const char *path) 75 { 76 struct device_node *parent = NULL; 77 char *parent_path = "/"; 78 size_t parent_path_len = strrchr(path, '/') - path + 1; 79 80 /* reject if path is "/" */ 81 if (!strcmp(path, "/")) 82 return ERR_PTR(-EINVAL); 83 84 if (strrchr(path, '/') != path) { 85 parent_path = kmalloc(parent_path_len, GFP_KERNEL); 86 if (!parent_path) 87 return ERR_PTR(-ENOMEM); 88 strlcpy(parent_path, path, parent_path_len); 89 } 90 parent = of_find_node_by_path(parent_path); 91 if (!parent) 92 return ERR_PTR(-EINVAL); 93 if (strcmp(parent_path, "/")) 94 kfree(parent_path); 95 return parent; 96 } 97 98 static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); 99 100 int pSeries_reconfig_notifier_register(struct notifier_block *nb) 101 { 102 return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); 103 } 104 105 void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) 106 { 107 blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); 108 } 109 110 static int pSeries_reconfig_add_node(const char *path, struct property *proplist) 111 { 112 struct device_node *np; 113 int err = -ENOMEM; 114 115 np = kzalloc(sizeof(*np), GFP_KERNEL); 116 if (!np) 117 goto out_err; 118 119 np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); 120 if (!np->full_name) 121 goto out_err; 122 123 strcpy(np->full_name, path); 124 125 np->properties = proplist; 126 of_node_set_flag(np, OF_DYNAMIC); 127 kref_init(&np->kref); 128 129 np->parent = derive_parent(path); 130 if (IS_ERR(np->parent)) { 131 err = PTR_ERR(np->parent); 132 goto out_err; 133 } 134 135 err = blocking_notifier_call_chain(&pSeries_reconfig_chain, 136 PSERIES_RECONFIG_ADD, np); 137 if (err == NOTIFY_BAD) { 138 printk(KERN_ERR "Failed to add device node %s\n", path); 139 err = -ENOMEM; /* For now, safe to assume kmalloc failure */ 140 goto out_err; 141 } 142 143 of_attach_node(np); 144 145 add_node_proc_entries(np); 146 147 of_node_put(np->parent); 148 149 return 0; 150 151 out_err: 152 if (np) { 153 of_node_put(np->parent); 154 kfree(np->full_name); 155 kfree(np); 156 } 157 return err; 158 } 159 160 static int pSeries_reconfig_remove_node(struct device_node *np) 161 { 162 struct device_node *parent, *child; 163 164 parent = of_get_parent(np); 165 if (!parent) 166 return -EINVAL; 167 168 if ((child = of_get_next_child(np, NULL))) { 169 of_node_put(child); 170 of_node_put(parent); 171 return -EBUSY; 172 } 173 174 remove_node_proc_entries(np); 175 176 blocking_notifier_call_chain(&pSeries_reconfig_chain, 177 PSERIES_RECONFIG_REMOVE, np); 178 of_detach_node(np); 179 180 of_node_put(parent); 181 of_node_put(np); /* Must decrement the refcount */ 182 return 0; 183 } 184 185 /* 186 * /proc/ppc64/ofdt - yucky binary interface for adding and removing 187 * OF device nodes. Should be deprecated as soon as we get an 188 * in-kernel wrapper for the RTAS ibm,configure-connector call. 189 */ 190 191 static void release_prop_list(const struct property *prop) 192 { 193 struct property *next; 194 for (; prop; prop = next) { 195 next = prop->next; 196 kfree(prop->name); 197 kfree(prop->value); 198 kfree(prop); 199 } 200 201 } 202 203 /** 204 * parse_next_property - process the next property from raw input buffer 205 * @buf: input buffer, must be nul-terminated 206 * @end: end of the input buffer + 1, for validation 207 * @name: return value; set to property name in buf 208 * @length: return value; set to length of value 209 * @value: return value; set to the property value in buf 210 * 211 * Note that the caller must make copies of the name and value returned, 212 * this function does no allocation or copying of the data. Return value 213 * is set to the next name in buf, or NULL on error. 214 */ 215 static char * parse_next_property(char *buf, char *end, char **name, int *length, 216 unsigned char **value) 217 { 218 char *tmp; 219 220 *name = buf; 221 222 tmp = strchr(buf, ' '); 223 if (!tmp) { 224 printk(KERN_ERR "property parse failed in %s at line %d\n", 225 __FUNCTION__, __LINE__); 226 return NULL; 227 } 228 *tmp = '\0'; 229 230 if (++tmp >= end) { 231 printk(KERN_ERR "property parse failed in %s at line %d\n", 232 __FUNCTION__, __LINE__); 233 return NULL; 234 } 235 236 /* now we're on the length */ 237 *length = -1; 238 *length = simple_strtoul(tmp, &tmp, 10); 239 if (*length == -1) { 240 printk(KERN_ERR "property parse failed in %s at line %d\n", 241 __FUNCTION__, __LINE__); 242 return NULL; 243 } 244 if (*tmp != ' ' || ++tmp >= end) { 245 printk(KERN_ERR "property parse failed in %s at line %d\n", 246 __FUNCTION__, __LINE__); 247 return NULL; 248 } 249 250 /* now we're on the value */ 251 *value = tmp; 252 tmp += *length; 253 if (tmp > end) { 254 printk(KERN_ERR "property parse failed in %s at line %d\n", 255 __FUNCTION__, __LINE__); 256 return NULL; 257 } 258 else if (tmp < end && *tmp != ' ' && *tmp != '\0') { 259 printk(KERN_ERR "property parse failed in %s at line %d\n", 260 __FUNCTION__, __LINE__); 261 return NULL; 262 } 263 tmp++; 264 265 /* and now we should be on the next name, or the end */ 266 return tmp; 267 } 268 269 static struct property *new_property(const char *name, const int length, 270 const unsigned char *value, struct property *last) 271 { 272 struct property *new = kzalloc(sizeof(*new), GFP_KERNEL); 273 274 if (!new) 275 return NULL; 276 277 if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL))) 278 goto cleanup; 279 if (!(new->value = kmalloc(length + 1, GFP_KERNEL))) 280 goto cleanup; 281 282 strcpy(new->name, name); 283 memcpy(new->value, value, length); 284 *(((char *)new->value) + length) = 0; 285 new->length = length; 286 new->next = last; 287 return new; 288 289 cleanup: 290 kfree(new->name); 291 kfree(new->value); 292 kfree(new); 293 return NULL; 294 } 295 296 static int do_add_node(char *buf, size_t bufsize) 297 { 298 char *path, *end, *name; 299 struct device_node *np; 300 struct property *prop = NULL; 301 unsigned char* value; 302 int length, rv = 0; 303 304 end = buf + bufsize; 305 path = buf; 306 buf = strchr(buf, ' '); 307 if (!buf) 308 return -EINVAL; 309 *buf = '\0'; 310 buf++; 311 312 if ((np = of_find_node_by_path(path))) { 313 of_node_put(np); 314 return -EINVAL; 315 } 316 317 /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */ 318 while (buf < end && 319 (buf = parse_next_property(buf, end, &name, &length, &value))) { 320 struct property *last = prop; 321 322 prop = new_property(name, length, value, last); 323 if (!prop) { 324 rv = -ENOMEM; 325 prop = last; 326 goto out; 327 } 328 } 329 if (!buf) { 330 rv = -EINVAL; 331 goto out; 332 } 333 334 rv = pSeries_reconfig_add_node(path, prop); 335 336 out: 337 if (rv) 338 release_prop_list(prop); 339 return rv; 340 } 341 342 static int do_remove_node(char *buf) 343 { 344 struct device_node *node; 345 int rv = -ENODEV; 346 347 if ((node = of_find_node_by_path(buf))) 348 rv = pSeries_reconfig_remove_node(node); 349 350 of_node_put(node); 351 return rv; 352 } 353 354 static char *parse_node(char *buf, size_t bufsize, struct device_node **npp) 355 { 356 char *handle_str; 357 phandle handle; 358 *npp = NULL; 359 360 handle_str = buf; 361 362 buf = strchr(buf, ' '); 363 if (!buf) 364 return NULL; 365 *buf = '\0'; 366 buf++; 367 368 handle = simple_strtoul(handle_str, NULL, 10); 369 370 *npp = of_find_node_by_phandle(handle); 371 return buf; 372 } 373 374 static int do_add_property(char *buf, size_t bufsize) 375 { 376 struct property *prop = NULL; 377 struct device_node *np; 378 unsigned char *value; 379 char *name, *end; 380 int length; 381 end = buf + bufsize; 382 buf = parse_node(buf, bufsize, &np); 383 384 if (!np) 385 return -ENODEV; 386 387 if (parse_next_property(buf, end, &name, &length, &value) == NULL) 388 return -EINVAL; 389 390 prop = new_property(name, length, value, NULL); 391 if (!prop) 392 return -ENOMEM; 393 394 prom_add_property(np, prop); 395 396 return 0; 397 } 398 399 static int do_remove_property(char *buf, size_t bufsize) 400 { 401 struct device_node *np; 402 char *tmp; 403 struct property *prop; 404 buf = parse_node(buf, bufsize, &np); 405 406 if (!np) 407 return -ENODEV; 408 409 tmp = strchr(buf,' '); 410 if (tmp) 411 *tmp = '\0'; 412 413 if (strlen(buf) == 0) 414 return -EINVAL; 415 416 prop = of_find_property(np, buf, NULL); 417 418 return prom_remove_property(np, prop); 419 } 420 421 static int do_update_property(char *buf, size_t bufsize) 422 { 423 struct device_node *np; 424 unsigned char *value; 425 char *name, *end; 426 int length; 427 struct property *newprop, *oldprop; 428 buf = parse_node(buf, bufsize, &np); 429 end = buf + bufsize; 430 431 if (!np) 432 return -ENODEV; 433 434 if (parse_next_property(buf, end, &name, &length, &value) == NULL) 435 return -EINVAL; 436 437 newprop = new_property(name, length, value, NULL); 438 if (!newprop) 439 return -ENOMEM; 440 441 oldprop = of_find_property(np, name,NULL); 442 if (!oldprop) 443 return -ENODEV; 444 445 return prom_update_property(np, newprop, oldprop); 446 } 447 448 /** 449 * ofdt_write - perform operations on the Open Firmware device tree 450 * 451 * @file: not used 452 * @buf: command and arguments 453 * @count: size of the command buffer 454 * @off: not used 455 * 456 * Operations supported at this time are addition and removal of 457 * whole nodes along with their properties. Operations on individual 458 * properties are not implemented (yet). 459 */ 460 static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, 461 loff_t *off) 462 { 463 int rv = 0; 464 char *kbuf; 465 char *tmp; 466 467 if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) { 468 rv = -ENOMEM; 469 goto out; 470 } 471 if (copy_from_user(kbuf, buf, count)) { 472 rv = -EFAULT; 473 goto out; 474 } 475 476 kbuf[count] = '\0'; 477 478 tmp = strchr(kbuf, ' '); 479 if (!tmp) { 480 rv = -EINVAL; 481 goto out; 482 } 483 *tmp = '\0'; 484 tmp++; 485 486 if (!strcmp(kbuf, "add_node")) 487 rv = do_add_node(tmp, count - (tmp - kbuf)); 488 else if (!strcmp(kbuf, "remove_node")) 489 rv = do_remove_node(tmp); 490 else if (!strcmp(kbuf, "add_property")) 491 rv = do_add_property(tmp, count - (tmp - kbuf)); 492 else if (!strcmp(kbuf, "remove_property")) 493 rv = do_remove_property(tmp, count - (tmp - kbuf)); 494 else if (!strcmp(kbuf, "update_property")) 495 rv = do_update_property(tmp, count - (tmp - kbuf)); 496 else 497 rv = -EINVAL; 498 out: 499 kfree(kbuf); 500 return rv ? rv : count; 501 } 502 503 static const struct file_operations ofdt_fops = { 504 .write = ofdt_write 505 }; 506 507 /* create /proc/ppc64/ofdt write-only by root */ 508 static int proc_ppc64_create_ofdt(void) 509 { 510 struct proc_dir_entry *ent; 511 512 if (!machine_is(pseries)) 513 return 0; 514 515 ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); 516 if (ent) { 517 ent->data = NULL; 518 ent->size = 0; 519 ent->proc_fops = &ofdt_fops; 520 } 521 522 return 0; 523 } 524 __initcall(proc_ppc64_create_ofdt); 525