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