diff options
| -rw-r--r-- | arch/sparc/include/asm/vio.h | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/vio.c | 68 |
2 files changed, 65 insertions, 4 deletions
diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 8174f6cdbbbb..9dca7a892978 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h | |||
| @@ -327,6 +327,7 @@ struct vio_dev { | |||
| 327 | int compat_len; | 327 | int compat_len; |
| 328 | 328 | ||
| 329 | u64 dev_no; | 329 | u64 dev_no; |
| 330 | u64 id; | ||
| 330 | 331 | ||
| 331 | unsigned long channel_id; | 332 | unsigned long channel_id; |
| 332 | 333 | ||
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index f6bb857254fc..075d38980dee 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c | |||
| @@ -302,13 +302,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | |||
| 302 | if (!id) { | 302 | if (!id) { |
| 303 | dev_set_name(&vdev->dev, "%s", bus_id_name); | 303 | dev_set_name(&vdev->dev, "%s", bus_id_name); |
| 304 | vdev->dev_no = ~(u64)0; | 304 | vdev->dev_no = ~(u64)0; |
| 305 | vdev->id = ~(u64)0; | ||
| 305 | } else if (!cfg_handle) { | 306 | } else if (!cfg_handle) { |
| 306 | dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id); | 307 | dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id); |
| 307 | vdev->dev_no = *id; | 308 | vdev->dev_no = *id; |
| 309 | vdev->id = ~(u64)0; | ||
| 308 | } else { | 310 | } else { |
| 309 | dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name, | 311 | dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name, |
| 310 | *cfg_handle, *id); | 312 | *cfg_handle, *id); |
| 311 | vdev->dev_no = *cfg_handle; | 313 | vdev->dev_no = *cfg_handle; |
| 314 | vdev->id = *id; | ||
| 312 | } | 315 | } |
| 313 | 316 | ||
| 314 | vdev->dev.parent = parent; | 317 | vdev->dev.parent = parent; |
| @@ -351,27 +354,84 @@ static void vio_add(struct mdesc_handle *hp, u64 node) | |||
| 351 | (void) vio_create_one(hp, node, &root_vdev->dev); | 354 | (void) vio_create_one(hp, node, &root_vdev->dev); |
| 352 | } | 355 | } |
| 353 | 356 | ||
| 357 | struct vio_md_node_query { | ||
| 358 | const char *type; | ||
| 359 | u64 dev_no; | ||
| 360 | u64 id; | ||
| 361 | }; | ||
| 362 | |||
| 354 | static int vio_md_node_match(struct device *dev, void *arg) | 363 | static int vio_md_node_match(struct device *dev, void *arg) |
| 355 | { | 364 | { |
| 365 | struct vio_md_node_query *query = (struct vio_md_node_query *) arg; | ||
| 356 | struct vio_dev *vdev = to_vio_dev(dev); | 366 | struct vio_dev *vdev = to_vio_dev(dev); |
| 357 | 367 | ||
| 358 | if (vdev->mp == (u64) arg) | 368 | if (vdev->dev_no != query->dev_no) |
| 359 | return 1; | 369 | return 0; |
| 370 | if (vdev->id != query->id) | ||
| 371 | return 0; | ||
| 372 | if (strcmp(vdev->type, query->type)) | ||
| 373 | return 0; | ||
| 360 | 374 | ||
| 361 | return 0; | 375 | return 1; |
| 362 | } | 376 | } |
| 363 | 377 | ||
| 364 | static void vio_remove(struct mdesc_handle *hp, u64 node) | 378 | static void vio_remove(struct mdesc_handle *hp, u64 node) |
| 365 | { | 379 | { |
| 380 | const char *type; | ||
| 381 | const u64 *id, *cfg_handle; | ||
| 382 | u64 a; | ||
| 383 | struct vio_md_node_query query; | ||
| 366 | struct device *dev; | 384 | struct device *dev; |
| 367 | 385 | ||
| 368 | dev = device_find_child(&root_vdev->dev, (void *) node, | 386 | type = mdesc_get_property(hp, node, "device-type", NULL); |
| 387 | if (!type) { | ||
| 388 | type = mdesc_get_property(hp, node, "name", NULL); | ||
| 389 | if (!type) | ||
| 390 | type = mdesc_node_name(hp, node); | ||
| 391 | } | ||
| 392 | |||
| 393 | query.type = type; | ||
| 394 | |||
| 395 | id = mdesc_get_property(hp, node, "id", NULL); | ||
| 396 | cfg_handle = NULL; | ||
| 397 | mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { | ||
| 398 | u64 target; | ||
| 399 | |||
| 400 | target = mdesc_arc_target(hp, a); | ||
| 401 | cfg_handle = mdesc_get_property(hp, target, | ||
| 402 | "cfg-handle", NULL); | ||
| 403 | if (cfg_handle) | ||
| 404 | break; | ||
| 405 | } | ||
| 406 | |||
| 407 | if (!id) { | ||
| 408 | query.dev_no = ~(u64)0; | ||
| 409 | query.id = ~(u64)0; | ||
| 410 | } else if (!cfg_handle) { | ||
| 411 | query.dev_no = *id; | ||
| 412 | query.id = ~(u64)0; | ||
| 413 | } else { | ||
| 414 | query.dev_no = *cfg_handle; | ||
| 415 | query.id = *id; | ||
| 416 | } | ||
| 417 | |||
| 418 | dev = device_find_child(&root_vdev->dev, &query, | ||
| 369 | vio_md_node_match); | 419 | vio_md_node_match); |
| 370 | if (dev) { | 420 | if (dev) { |
| 371 | printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); | 421 | printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); |
| 372 | 422 | ||
| 373 | device_unregister(dev); | 423 | device_unregister(dev); |
| 374 | put_device(dev); | 424 | put_device(dev); |
| 425 | } else { | ||
| 426 | if (!id) | ||
| 427 | printk(KERN_ERR "VIO: Removed unknown %s node.\n", | ||
| 428 | type); | ||
| 429 | else if (!cfg_handle) | ||
| 430 | printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n", | ||
| 431 | type, *id); | ||
| 432 | else | ||
| 433 | printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n", | ||
| 434 | type, *cfg_handle, *id); | ||
| 375 | } | 435 | } |
| 376 | } | 436 | } |
| 377 | 437 | ||
