1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * pSeries_reconfig.c - support for dynamic reconfiguration (including PCI 4 * Hotplug and Dynamic Logical Partitioning on RPA platforms). 5 * 6 * Copyright (C) 2005 Nathan Lynch 7 * Copyright (C) 2005 IBM Corporation 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/notifier.h> 12 #include <linux/proc_fs.h> 13 #include <linux/security.h> 14 #include <linux/slab.h> 15 #include <linux/of.h> 16 17 #include <asm/machdep.h> 18 #include <linux/uaccess.h> 19 #include <asm/mmu.h> 20 21 #include "of_helpers.h" 22 23 static int pSeries_reconfig_add_node(const char *path, struct property *proplist) 24 { 25 struct device_node *np; 26 int err = -ENOMEM; 27 28 np = kzalloc(sizeof(*np), GFP_KERNEL); 29 if (!np) 30 goto out_err; 31 32 np->full_name = kstrdup(kbasename(path), GFP_KERNEL); 33 if (!np->full_name) 34 goto out_err; 35 36 np->properties = proplist; 37 of_node_set_flag(np, OF_DYNAMIC); 38 of_node_init(np); 39 40 np->parent = pseries_of_derive_parent(path); 41 if (IS_ERR(np->parent)) { 42 err = PTR_ERR(np->parent); 43 goto out_err; 44 } 45 46 err = of_attach_node(np); 47 if (err) { 48 printk(KERN_ERR "Failed to add device node %s\n", path); 49 goto out_err; 50 } 51 52 of_node_put(np->parent); 53 54 return 0; 55 56 out_err: 57 if (np) { 58 of_node_put(np->parent); 59 kfree(np->full_name); 60 kfree(np); 61 } 62 return err; 63 } 64 65 static int pSeries_reconfig_remove_node(struct device_node *np) 66 { 67 struct device_node *parent, *child; 68 69 parent = of_get_parent(np); 70 if (!parent) 71 return -EINVAL; 72 73 if ((child = of_get_next_child(np, NULL))) { 74 of_node_put(child); 75 of_node_put(parent); 76 return -EBUSY; 77 } 78 79 of_detach_node(np); 80 of_node_put(parent); 81 return 0; 82 } 83 84 /* 85 * /proc/powerpc/ofdt - yucky binary interface for adding and removing 86 * OF device nodes. Should be deprecated as soon as we get an 87 * in-kernel wrapper for the RTAS ibm,configure-connector call. 88 */ 89 90 static void release_prop_list(const struct property *prop) 91 { 92 struct property *next; 93 for (; prop; prop = next) { 94 next = prop->next; 95 kfree(prop->name); 96 kfree(prop->value); 97 kfree(prop); 98 } 99 100 } 101 102 /** 103 * parse_next_property - process the next property from raw input buffer 104 * @buf: input buffer, must be nul-terminated 105 * @end: end of the input buffer + 1, for validation 106 * @name: return value; set to property name in buf 107 * @length: return value; set to length of value 108 * @value: return value; set to the property value in buf 109 * 110 * Note that the caller must make copies of the name and value returned, 111 * this function does no allocation or copying of the data. Return value 112 * is set to the next name in buf, or NULL on error. 113 */ 114 static char * parse_next_property(char *buf, char *end, char **name, int *length, 115 unsigned char **value) 116 { 117 char *tmp; 118 119 *name = buf; 120 121 tmp = strchr(buf, ' '); 122 if (!tmp) { 123 printk(KERN_ERR "property parse failed in %s at line %d\n", 124 __func__, __LINE__); 125 return NULL; 126 } 127 *tmp = '\0'; 128 129 if (++tmp >= end) { 130 printk(KERN_ERR "property parse failed in %s at line %d\n", 131 __func__, __LINE__); 132 return NULL; 133 } 134 135 /* now we're on the length */ 136 *length = -1; 137 *length = simple_strtoul(tmp, &tmp, 10); 138 if (*length == -1) { 139 printk(KERN_ERR "property parse failed in %s at line %d\n", 140 __func__, __LINE__); 141 return NULL; 142 } 143 if (*tmp != ' ' || ++tmp >= end) { 144 printk(KERN_ERR "property parse failed in %s at line %d\n", 145 __func__, __LINE__); 146 return NULL; 147 } 148 149 /* now we're on the value */ 150 *value = tmp; 151 tmp += *length; 152 if (tmp > end) { 153 printk(KERN_ERR "property parse failed in %s at line %d\n", 154 __func__, __LINE__); 155 return NULL; 156 } 157 else if (tmp < end && *tmp != ' ' && *tmp != '\0') { 158 printk(KERN_ERR "property parse failed in %s at line %d\n", 159 __func__, __LINE__); 160 return NULL; 161 } 162 tmp++; 163 164 /* and now we should be on the next name, or the end */ 165 return tmp; 166 } 167 168 static struct property *new_property(const char *name, const int length, 169 const unsigned char *value, struct property *last) 170 { 171 struct property *new = kzalloc(sizeof(*new), GFP_KERNEL); 172 173 if (!new) 174 return NULL; 175 176 if (!(new->name = kstrdup(name, GFP_KERNEL))) 177 goto cleanup; 178 if (!(new->value = kmalloc(length + 1, GFP_KERNEL))) 179 goto cleanup; 180 181 memcpy(new->value, value, length); 182 *(((char *)new->value) + length) = 0; 183 new->length = length; 184 new->next = last; 185 return new; 186 187 cleanup: 188 kfree(new->name); 189 kfree(new->value); 190 kfree(new); 191 return NULL; 192 } 193 194 static int do_add_node(char *buf, size_t bufsize) 195 { 196 char *path, *end, *name; 197 struct device_node *np; 198 struct property *prop = NULL; 199 unsigned char* value; 200 int length, rv = 0; 201 202 end = buf + bufsize; 203 path = buf; 204 buf = strchr(buf, ' '); 205 if (!buf) 206 return -EINVAL; 207 *buf = '\0'; 208 buf++; 209 210 if ((np = of_find_node_by_path(path))) { 211 of_node_put(np); 212 return -EINVAL; 213 } 214 215 /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */ 216 while (buf < end && 217 (buf = parse_next_property(buf, end, &name, &length, &value))) { 218 struct property *last = prop; 219 220 prop = new_property(name, length, value, last); 221 if (!prop) { 222 rv = -ENOMEM; 223 prop = last; 224 goto out; 225 } 226 } 227 if (!buf) { 228 rv = -EINVAL; 229 goto out; 230 } 231 232 rv = pSeries_reconfig_add_node(path, prop); 233 234 out: 235 if (rv) 236 release_prop_list(prop); 237 return rv; 238 } 239 240 static int do_remove_node(char *buf) 241 { 242 struct device_node *node; 243 int rv = -ENODEV; 244 245 if ((node = of_find_node_by_path(buf))) 246 rv = pSeries_reconfig_remove_node(node); 247 248 of_node_put(node); 249 return rv; 250 } 251 252 static char *parse_node(char *buf, size_t bufsize, struct device_node **npp) 253 { 254 char *handle_str; 255 phandle handle; 256 *npp = NULL; 257 258 handle_str = buf; 259 260 buf = strchr(buf, ' '); 261 if (!buf) 262 return NULL; 263 *buf = '\0'; 264 buf++; 265 266 handle = simple_strtoul(handle_str, NULL, 0); 267 268 *npp = of_find_node_by_phandle(handle); 269 return buf; 270 } 271 272 static int do_add_property(char *buf, size_t bufsize) 273 { 274 struct property *prop = NULL; 275 struct device_node *np; 276 unsigned char *value; 277 char *name, *end; 278 int length; 279 end = buf + bufsize; 280 buf = parse_node(buf, bufsize, &np); 281 282 if (!np) 283 return -ENODEV; 284 285 if (parse_next_property(buf, end, &name, &length, &value) == NULL) 286 return -EINVAL; 287 288 prop = new_property(name, length, value, NULL); 289 if (!prop) 290 return -ENOMEM; 291 292 of_add_property(np, prop); 293 294 return 0; 295 } 296 297 static int do_remove_property(char *buf, size_t bufsize) 298 { 299 struct device_node *np; 300 char *tmp; 301 buf = parse_node(buf, bufsize, &np); 302 303 if (!np) 304 return -ENODEV; 305 306 tmp = strchr(buf,' '); 307 if (tmp) 308 *tmp = '\0'; 309 310 if (strlen(buf) == 0) 311 return -EINVAL; 312 313 return of_remove_property(np, of_find_property(np, buf, NULL)); 314 } 315 316 static int do_update_property(char *buf, size_t bufsize) 317 { 318 struct device_node *np; 319 unsigned char *value; 320 char *name, *end, *next_prop; 321 int length; 322 struct property *newprop; 323 buf = parse_node(buf, bufsize, &np); 324 end = buf + bufsize; 325 326 if (!np) 327 return -ENODEV; 328 329 next_prop = parse_next_property(buf, end, &name, &length, &value); 330 if (!next_prop) 331 return -EINVAL; 332 333 if (!strlen(name)) 334 return -ENODEV; 335 336 newprop = new_property(name, length, value, NULL); 337 if (!newprop) 338 return -ENOMEM; 339 340 if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) 341 slb_set_size(*(int *)value); 342 343 return of_update_property(np, newprop); 344 } 345 346 /** 347 * ofdt_write - perform operations on the Open Firmware device tree 348 * 349 * @file: not used 350 * @buf: command and arguments 351 * @count: size of the command buffer 352 * @off: not used 353 * 354 * Operations supported at this time are addition and removal of 355 * whole nodes along with their properties. Operations on individual 356 * properties are not implemented (yet). 357 */ 358 static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, 359 loff_t *off) 360 { 361 int rv; 362 char *kbuf; 363 char *tmp; 364 365 rv = security_locked_down(LOCKDOWN_DEVICE_TREE); 366 if (rv) 367 return rv; 368 369 kbuf = memdup_user_nul(buf, count); 370 if (IS_ERR(kbuf)) 371 return PTR_ERR(kbuf); 372 373 tmp = strchr(kbuf, ' '); 374 if (!tmp) { 375 rv = -EINVAL; 376 goto out; 377 } 378 *tmp = '\0'; 379 tmp++; 380 381 if (!strcmp(kbuf, "add_node")) 382 rv = do_add_node(tmp, count - (tmp - kbuf)); 383 else if (!strcmp(kbuf, "remove_node")) 384 rv = do_remove_node(tmp); 385 else if (!strcmp(kbuf, "add_property")) 386 rv = do_add_property(tmp, count - (tmp - kbuf)); 387 else if (!strcmp(kbuf, "remove_property")) 388 rv = do_remove_property(tmp, count - (tmp - kbuf)); 389 else if (!strcmp(kbuf, "update_property")) 390 rv = do_update_property(tmp, count - (tmp - kbuf)); 391 else 392 rv = -EINVAL; 393 out: 394 kfree(kbuf); 395 return rv ? rv : count; 396 } 397 398 static const struct proc_ops ofdt_proc_ops = { 399 .proc_write = ofdt_write, 400 .proc_lseek = noop_llseek, 401 }; 402 403 /* create /proc/powerpc/ofdt write-only by root */ 404 static int proc_ppc64_create_ofdt(void) 405 { 406 struct proc_dir_entry *ent; 407 408 ent = proc_create("powerpc/ofdt", 0200, NULL, &ofdt_proc_ops); 409 if (ent) 410 proc_set_size(ent, 0); 411 412 return 0; 413 } 414 machine_device_initcall(pseries, proc_ppc64_create_ofdt); 415
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.