diff options
Diffstat (limited to 'arch/sparc64/kernel/vio.c')
-rw-r--r-- | arch/sparc64/kernel/vio.c | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c index 49569b44ea1f..8d3cc4fdb557 100644 --- a/arch/sparc64/kernel/vio.c +++ b/arch/sparc64/kernel/vio.c | |||
@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, | |||
201 | static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | 201 | static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, |
202 | struct device *parent) | 202 | struct device *parent) |
203 | { | 203 | { |
204 | const char *type, *compat; | 204 | const char *type, *compat, *bus_id_name; |
205 | struct device_node *dp; | 205 | struct device_node *dp; |
206 | struct vio_dev *vdev; | 206 | struct vio_dev *vdev; |
207 | int err, tlen, clen; | 207 | int err, tlen, clen; |
208 | const u64 *id; | ||
208 | 209 | ||
209 | type = mdesc_get_property(hp, mp, "device-type", &tlen); | 210 | type = mdesc_get_property(hp, mp, "device-type", &tlen); |
210 | if (!type) { | 211 | if (!type) { |
@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | |||
220 | return NULL; | 221 | return NULL; |
221 | } | 222 | } |
222 | 223 | ||
224 | bus_id_name = type; | ||
225 | if (!strcmp(type, "domain-services-port")) | ||
226 | bus_id_name = "ds"; | ||
227 | |||
228 | if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) { | ||
229 | printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n", | ||
230 | bus_id_name); | ||
231 | return NULL; | ||
232 | } | ||
233 | |||
223 | compat = mdesc_get_property(hp, mp, "device-type", &clen); | 234 | compat = mdesc_get_property(hp, mp, "device-type", &clen); |
224 | if (!compat) { | 235 | if (!compat) { |
225 | clen = 0; | 236 | clen = 0; |
@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | |||
249 | 260 | ||
250 | vio_fill_channel_info(hp, mp, vdev); | 261 | vio_fill_channel_info(hp, mp, vdev); |
251 | 262 | ||
252 | snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp); | 263 | id = mdesc_get_property(hp, mp, "id", NULL); |
264 | if (!id) | ||
265 | snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s", | ||
266 | bus_id_name); | ||
267 | else | ||
268 | snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu", | ||
269 | bus_id_name, *id); | ||
270 | |||
253 | vdev->dev.parent = parent; | 271 | vdev->dev.parent = parent; |
254 | vdev->dev.bus = &vio_bus_type; | 272 | vdev->dev.bus = &vio_bus_type; |
255 | vdev->dev.release = vio_dev_release; | 273 | vdev->dev.release = vio_dev_release; |
@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | |||
269 | } | 287 | } |
270 | vdev->dp = dp; | 288 | vdev->dp = dp; |
271 | 289 | ||
290 | printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id); | ||
291 | |||
272 | err = device_register(&vdev->dev); | 292 | err = device_register(&vdev->dev); |
273 | if (err) { | 293 | if (err) { |
274 | printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", | 294 | printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", |
@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, | |||
283 | return vdev; | 303 | return vdev; |
284 | } | 304 | } |
285 | 305 | ||
286 | static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent) | 306 | static void vio_add(struct mdesc_handle *hp, u64 node) |
287 | { | 307 | { |
288 | u64 a; | 308 | (void) vio_create_one(hp, node, &root_vdev->dev); |
289 | |||
290 | mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) { | ||
291 | struct vio_dev *vdev; | ||
292 | u64 target; | ||
293 | |||
294 | target = mdesc_arc_target(hp, a); | ||
295 | vdev = vio_create_one(hp, target, &parent->dev); | ||
296 | if (vdev) | ||
297 | walk_tree(hp, target, vdev); | ||
298 | } | ||
299 | } | 309 | } |
300 | 310 | ||
301 | static void create_devices(struct mdesc_handle *hp, u64 root) | 311 | static int vio_md_node_match(struct device *dev, void *arg) |
302 | { | 312 | { |
303 | u64 mp; | 313 | struct vio_dev *vdev = to_vio_dev(dev); |
304 | 314 | ||
305 | root_vdev = vio_create_one(hp, root, NULL); | 315 | if (vdev->mp == (u64) arg) |
306 | if (!root_vdev) { | 316 | return 1; |
307 | printk(KERN_ERR "VIO: Coult not create root device.\n"); | ||
308 | return; | ||
309 | } | ||
310 | 317 | ||
311 | walk_tree(hp, root, root_vdev); | 318 | return 0; |
319 | } | ||
320 | |||
321 | static void vio_remove(struct mdesc_handle *hp, u64 node) | ||
322 | { | ||
323 | struct device *dev; | ||
312 | 324 | ||
313 | /* Domain services is odd as it doesn't sit underneath the | 325 | dev = device_find_child(&root_vdev->dev, (void *) node, |
314 | * channel-devices node, so we plug it in manually. | 326 | vio_md_node_match); |
315 | */ | 327 | if (dev) { |
316 | mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services"); | 328 | printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id); |
317 | if (mp != MDESC_NODE_NULL) { | ||
318 | struct vio_dev *parent = vio_create_one(hp, mp, | ||
319 | &root_vdev->dev); | ||
320 | 329 | ||
321 | if (parent) | 330 | device_unregister(dev); |
322 | walk_tree(hp, mp, parent); | ||
323 | } | 331 | } |
324 | } | 332 | } |
325 | 333 | ||
334 | static struct mdesc_notifier_client vio_device_notifier = { | ||
335 | .add = vio_add, | ||
336 | .remove = vio_remove, | ||
337 | .node_name = "virtual-device-port", | ||
338 | }; | ||
339 | |||
340 | static struct mdesc_notifier_client vio_ds_notifier = { | ||
341 | .add = vio_add, | ||
342 | .remove = vio_remove, | ||
343 | .node_name = "domain-services-port", | ||
344 | }; | ||
345 | |||
326 | const char *channel_devices_node = "channel-devices"; | 346 | const char *channel_devices_node = "channel-devices"; |
327 | const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; | 347 | const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; |
328 | const char *cfg_handle_prop = "cfg-handle"; | 348 | const char *cfg_handle_prop = "cfg-handle"; |
@@ -381,11 +401,19 @@ static int __init vio_init(void) | |||
381 | 401 | ||
382 | cdev_cfg_handle = *cfg_handle; | 402 | cdev_cfg_handle = *cfg_handle; |
383 | 403 | ||
384 | create_devices(hp, root); | 404 | root_vdev = vio_create_one(hp, root, NULL); |
405 | err = -ENODEV; | ||
406 | if (!root_vdev) { | ||
407 | printk(KERN_ERR "VIO: Coult not create root device.\n"); | ||
408 | goto out_release; | ||
409 | } | ||
410 | |||
411 | mdesc_register_notifier(&vio_device_notifier); | ||
412 | mdesc_register_notifier(&vio_ds_notifier); | ||
385 | 413 | ||
386 | mdesc_release(hp); | 414 | mdesc_release(hp); |
387 | 415 | ||
388 | return 0; | 416 | return err; |
389 | 417 | ||
390 | out_release: | 418 | out_release: |
391 | mdesc_release(hp); | 419 | mdesc_release(hp); |