Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] ibmebus: dynamic addition/removal of adapters, some code cleanup

This adds two sysfs attributes to /sys/bus/ibmebus which can be used to
notify the ebus driver of added / removed ebus devices in the OF device
tree.

Echoing the device's location code (as found in the OFDT "ibm,loc-code"
property) into the "probe" attribute will notify ebus of addition of the
device and cause the appropriate device driver's probe function to be called
on the device.

Likewise, echoing the location code into the "remove" attribute will cause
the device to be removed from the system.

The writes will block until the respective operation has finished and return
an error code if the operation failed.

In addition, two minor tidbits are fixed:

- The fake root device used to provide a common parent for all ebus devices
is now based on device instead of of_device - it had no associated devtree
node. This saves several checks throughout the ebus driver.

- The sysfs attributes are now generated automagically by device_register()
instead of by the ibmebus code, which saves a few compiler warnings about
unused return codes.

Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Joachim Fenkes and committed by
Paul Mackerras
6bccf755 a8308800

+134 -35
+133 -34
arch/powerpc/kernel/ibmebus.c
··· 2 2 * IBM PowerPC IBM eBus Infrastructure Support. 3 3 * 4 4 * Copyright (c) 2005 IBM Corporation 5 + * Joachim Fenkes <fenkes@de.ibm.com> 5 6 * Heiko J Schick <schickhj@de.ibm.com> 6 7 * 7 8 * All rights reserved. ··· 44 43 #include <asm/ibmebus.h> 45 44 #include <asm/abs_addr.h> 46 45 47 - static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */ 48 - .name = ibmebus_bus_device.ofdev.dev.bus_id, 49 - .ofdev.dev.bus_id = "ibmebus", 50 - .ofdev.dev.bus = &ibmebus_bus_type, 46 + #define MAX_LOC_CODE_LENGTH 80 47 + 48 + static struct device ibmebus_bus_device = { /* fake "parent" device */ 49 + .bus_id = "ibmebus", 51 50 }; 51 + 52 + struct bus_type ibmebus_bus_type; 52 53 53 54 static void *ibmebus_alloc_coherent(struct device *dev, 54 55 size_t size, ··· 161 158 kfree(to_ibmebus_dev(dev)); 162 159 } 163 160 164 - static ssize_t ibmebusdev_show_name(struct device *dev, 165 - struct device_attribute *attr, char *buf) 166 - { 167 - return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name); 168 - } 169 - static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, 170 - NULL); 171 - 172 - static struct ibmebus_dev* __devinit ibmebus_register_device_common( 161 + static int __devinit ibmebus_register_device_common( 173 162 struct ibmebus_dev *dev, const char *name) 174 163 { 175 164 int err = 0; 176 165 177 - dev->name = name; 178 - dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev; 166 + dev->ofdev.dev.parent = &ibmebus_bus_device; 179 167 dev->ofdev.dev.bus = &ibmebus_bus_type; 180 168 dev->ofdev.dev.release = ibmebus_dev_release; 181 169 ··· 180 186 if ((err = of_device_register(&dev->ofdev)) != 0) { 181 187 printk(KERN_ERR "%s: failed to register device (%d).\n", 182 188 __FUNCTION__, err); 183 - return NULL; 189 + return -ENODEV; 184 190 } 185 191 186 - device_create_file(&dev->ofdev.dev, &dev_attr_name); 187 - 188 - return dev; 192 + return 0; 189 193 } 190 194 191 195 static struct ibmebus_dev* __devinit ibmebus_register_device_node( ··· 197 205 if (!loc_code) { 198 206 printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", 199 207 __FUNCTION__, dn->name ? dn->name : "<unknown>"); 200 - return NULL; 208 + return ERR_PTR(-EINVAL); 201 209 } 202 210 203 211 if (strlen(loc_code) == 0) { 204 212 printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", 205 213 __FUNCTION__); 206 - return NULL; 214 + return ERR_PTR(-EINVAL); 207 215 } 208 216 209 217 dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); 210 218 if (!dev) { 211 - return NULL; 219 + return ERR_PTR(-ENOMEM); 212 220 } 213 221 214 222 dev->ofdev.node = of_node_get(dn); ··· 219 227 min(length, BUS_ID_SIZE - 1)); 220 228 221 229 /* Register with generic device framework. */ 222 - if (ibmebus_register_device_common(dev, dn->name) == NULL) { 230 + if (ibmebus_register_device_common(dev, dn->name) != 0) { 223 231 kfree(dev); 224 - return NULL; 232 + return ERR_PTR(-ENODEV); 225 233 } 226 234 227 235 return dev; ··· 232 240 struct device_node *dn = NULL; 233 241 234 242 while ((dn = of_find_node_by_name(dn, name))) { 235 - if (ibmebus_register_device_node(dn) == NULL) { 243 + if (IS_ERR(ibmebus_register_device_node(dn))) { 236 244 of_node_put(dn); 237 - 238 245 return; 239 246 } 240 247 } ··· 253 262 return; 254 263 } 255 264 256 - static int ibmebus_match_helper(struct device *dev, void *data) 265 + static int ibmebus_match_helper_name(struct device *dev, void *data) 257 266 { 258 - if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0) 267 + const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); 268 + char *name; 269 + 270 + name = (char*)get_property( 271 + ebus_dev->ofdev.node, "name", NULL); 272 + 273 + if (name && (strcmp((char*)data, name) == 0)) 259 274 return 1; 260 275 261 276 return 0; ··· 269 272 270 273 static int ibmebus_unregister_device(struct device *dev) 271 274 { 272 - device_remove_file(dev, &dev_attr_name); 273 275 of_device_unregister(to_of_device(dev)); 274 276 275 277 return 0; ··· 281 285 while (strlen(idt->name) > 0) { 282 286 while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 283 287 (void*)idt->name, 284 - ibmebus_match_helper))) { 288 + ibmebus_match_helper_name))) { 285 289 ibmebus_unregister_device(dev); 286 290 } 287 291 idt++; 288 - 289 292 } 290 293 291 294 return; ··· 302 307 if ((err = driver_register(&drv->driver) != 0)) 303 308 return err; 304 309 310 + /* remove all supported devices first, in case someone 311 + * probed them manually before registering the driver */ 312 + ibmebus_remove_devices_by_id(drv->id_table); 305 313 ibmebus_add_devices_by_id(drv->id_table); 306 314 307 315 return 0; ··· 359 361 return 0; 360 362 } 361 363 364 + static ssize_t name_show(struct device *dev, 365 + struct device_attribute *attr, char *buf) 366 + { 367 + struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); 368 + char *name = (char*)get_property(ebus_dev->ofdev.node, "name", NULL); 369 + return sprintf(buf, "%s\n", name); 370 + } 371 + 372 + static struct device_attribute ibmebus_dev_attrs[] = { 373 + __ATTR_RO(name), 374 + __ATTR_NULL 375 + }; 376 + 377 + static int ibmebus_match_helper_loc_code(struct device *dev, void *data) 378 + { 379 + const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); 380 + char *loc_code; 381 + 382 + loc_code = (char*)get_property( 383 + ebus_dev->ofdev.node, "ibm,loc-code", NULL); 384 + 385 + if (loc_code && (strcmp((char*)data, loc_code) == 0)) 386 + return 1; 387 + 388 + return 0; 389 + } 390 + 391 + static ssize_t ibmebus_store_probe(struct bus_type *bus, 392 + const char *buf, size_t count) 393 + { 394 + struct device_node *dn = NULL; 395 + struct ibmebus_dev *dev; 396 + char *loc_code; 397 + char parm[MAX_LOC_CODE_LENGTH]; 398 + 399 + if (count >= MAX_LOC_CODE_LENGTH) 400 + return -EINVAL; 401 + memcpy(parm, buf, count); 402 + parm[count] = '\0'; 403 + if (parm[count-1] == '\n') 404 + parm[count-1] = '\0'; 405 + 406 + if (bus_find_device(&ibmebus_bus_type, NULL, parm, 407 + ibmebus_match_helper_loc_code)) { 408 + printk(KERN_WARNING "%s: loc_code %s has already been probed\n", 409 + __FUNCTION__, parm); 410 + return -EINVAL; 411 + } 412 + 413 + while ((dn = of_find_all_nodes(dn))) { 414 + loc_code = (char *)get_property(dn, "ibm,loc-code", NULL); 415 + if (loc_code && (strncmp(loc_code, parm, count) == 0)) { 416 + dev = ibmebus_register_device_node(dn); 417 + if (IS_ERR(dev)) { 418 + of_node_put(dn); 419 + return PTR_ERR(dev); 420 + } else 421 + return count; /* success */ 422 + } 423 + } 424 + 425 + /* if we drop out of the loop, the loc code was invalid */ 426 + printk(KERN_WARNING "%s: no device with loc_code %s found\n", 427 + __FUNCTION__, parm); 428 + return -ENODEV; 429 + } 430 + 431 + static ssize_t ibmebus_store_remove(struct bus_type *bus, 432 + const char *buf, size_t count) 433 + { 434 + struct device *dev; 435 + char parm[MAX_LOC_CODE_LENGTH]; 436 + 437 + if (count >= MAX_LOC_CODE_LENGTH) 438 + return -EINVAL; 439 + memcpy(parm, buf, count); 440 + parm[count] = '\0'; 441 + if (parm[count-1] == '\n') 442 + parm[count-1] = '\0'; 443 + 444 + /* The location code is unique, so we will find one device at most */ 445 + if ((dev = bus_find_device(&ibmebus_bus_type, NULL, parm, 446 + ibmebus_match_helper_loc_code))) { 447 + ibmebus_unregister_device(dev); 448 + } else { 449 + printk(KERN_WARNING "%s: loc_code %s not on the bus\n", 450 + __FUNCTION__, parm); 451 + return -ENODEV; 452 + } 453 + 454 + return count; 455 + } 456 + 457 + static struct bus_attribute ibmebus_bus_attrs[] = { 458 + __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), 459 + __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), 460 + __ATTR_NULL 461 + }; 462 + 362 463 struct bus_type ibmebus_bus_type = { 363 - .name = "ibmebus", 364 - .match = ibmebus_bus_match, 464 + .name = "ibmebus", 465 + .match = ibmebus_bus_match, 466 + .dev_attrs = ibmebus_dev_attrs, 467 + .bus_attrs = ibmebus_bus_attrs 365 468 }; 366 469 EXPORT_SYMBOL(ibmebus_bus_type); 367 470 ··· 479 380 return err; 480 381 } 481 382 482 - err = device_register(&ibmebus_bus_device.ofdev.dev); 383 + err = device_register(&ibmebus_bus_device); 483 384 if (err) { 484 385 printk(KERN_WARNING "%s: device_register returned %i\n", 485 386 __FUNCTION__, err);
+1 -1
include/asm-powerpc/ibmebus.h
··· 2 2 * IBM PowerPC eBus Infrastructure Support. 3 3 * 4 4 * Copyright (c) 2005 IBM Corporation 5 + * Joachim Fenkes <fenkes@de.ibm.com> 5 6 * Heiko J Schick <schickhj@de.ibm.com> 6 7 * 7 8 * All rights reserved. ··· 48 47 extern struct bus_type ibmebus_bus_type; 49 48 50 49 struct ibmebus_dev { 51 - const char *name; 52 50 struct of_device ofdev; 53 51 }; 54 52