aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/kernel/vio.c123
1 files changed, 59 insertions, 64 deletions
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index d487be093b4a..8d3cc4fdb557 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -172,36 +172,6 @@ struct device_node *cdev_node;
172static struct vio_dev *root_vdev; 172static struct vio_dev *root_vdev;
173static u64 cdev_cfg_handle; 173static u64 cdev_cfg_handle;
174 174
175static void vio_add(struct mdesc_handle *hp, u64 node)
176{
177 const char *name = mdesc_get_property(hp, node, "name", NULL);
178 const u64 *id = mdesc_get_property(hp, node, "id", NULL);
179
180 printk(KERN_ERR "VIO: Device add (%s) ID[%lx]\n",
181 name, *id);
182}
183
184static void vio_remove(struct mdesc_handle *hp, u64 node)
185{
186 const char *name = mdesc_get_property(hp, node, "name", NULL);
187 const u64 *id = mdesc_get_property(hp, node, "id", NULL);
188
189 printk(KERN_ERR "VIO: Device remove (%s) ID[%lx]\n",
190 name, *id);
191}
192
193static struct mdesc_notifier_client vio_device_notifier = {
194 .add = vio_add,
195 .remove = vio_remove,
196 .node_name = "virtual-device-port",
197};
198
199static struct mdesc_notifier_client vio_ds_notifier = {
200 .add = vio_add,
201 .remove = vio_remove,
202 .node_name = "domain-services-port",
203};
204
205static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, 175static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
206 struct vio_dev *vdev) 176 struct vio_dev *vdev)
207{ 177{
@@ -231,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
231static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, 201static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
232 struct device *parent) 202 struct device *parent)
233{ 203{
234 const char *type, *compat; 204 const char *type, *compat, *bus_id_name;
235 struct device_node *dp; 205 struct device_node *dp;
236 struct vio_dev *vdev; 206 struct vio_dev *vdev;
237 int err, tlen, clen; 207 int err, tlen, clen;
208 const u64 *id;
238 209
239 type = mdesc_get_property(hp, mp, "device-type", &tlen); 210 type = mdesc_get_property(hp, mp, "device-type", &tlen);
240 if (!type) { 211 if (!type) {
@@ -250,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
250 return NULL; 221 return NULL;
251 } 222 }
252 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
253 compat = mdesc_get_property(hp, mp, "device-type", &clen); 234 compat = mdesc_get_property(hp, mp, "device-type", &clen);
254 if (!compat) { 235 if (!compat) {
255 clen = 0; 236 clen = 0;
@@ -279,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
279 260
280 vio_fill_channel_info(hp, mp, vdev); 261 vio_fill_channel_info(hp, mp, vdev);
281 262
282 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
283 vdev->dev.parent = parent; 271 vdev->dev.parent = parent;
284 vdev->dev.bus = &vio_bus_type; 272 vdev->dev.bus = &vio_bus_type;
285 vdev->dev.release = vio_dev_release; 273 vdev->dev.release = vio_dev_release;
@@ -299,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
299 } 287 }
300 vdev->dp = dp; 288 vdev->dp = dp;
301 289
290 printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
291
302 err = device_register(&vdev->dev); 292 err = device_register(&vdev->dev);
303 if (err) { 293 if (err) {
304 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",
@@ -313,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
313 return vdev; 303 return vdev;
314} 304}
315 305
316static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent) 306static void vio_add(struct mdesc_handle *hp, u64 node)
317{ 307{
318 u64 a; 308 (void) vio_create_one(hp, node, &root_vdev->dev);
319
320 mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
321 struct vio_dev *vdev;
322 u64 target;
323
324 target = mdesc_arc_target(hp, a);
325 vdev = vio_create_one(hp, target, &parent->dev);
326 if (vdev)
327 walk_tree(hp, target, vdev);
328 }
329} 309}
330 310
331static void create_devices(struct mdesc_handle *hp, u64 root) 311static int vio_md_node_match(struct device *dev, void *arg)
332{ 312{
333 u64 mp; 313 struct vio_dev *vdev = to_vio_dev(dev);
334 314
335 root_vdev = vio_create_one(hp, root, NULL); 315 if (vdev->mp == (u64) arg)
336 if (!root_vdev) { 316 return 1;
337 printk(KERN_ERR "VIO: Coult not create root device.\n");
338 return;
339 }
340 317
341 walk_tree(hp, root, root_vdev); 318 return 0;
319}
342 320
343 /* Domain services is odd as it doesn't sit underneath the 321static void vio_remove(struct mdesc_handle *hp, u64 node)
344 * channel-devices node, so we plug it in manually. 322{
345 */ 323 struct device *dev;
346 mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
347 if (mp != MDESC_NODE_NULL) {
348 struct vio_dev *parent = vio_create_one(hp, mp,
349 &root_vdev->dev);
350 324
351 if (parent) 325 dev = device_find_child(&root_vdev->dev, (void *) node,
352 walk_tree(hp, mp, parent); 326 vio_md_node_match);
327 if (dev) {
328 printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
329
330 device_unregister(dev);
353 } 331 }
354} 332}
355 333
334static struct mdesc_notifier_client vio_device_notifier = {
335 .add = vio_add,
336 .remove = vio_remove,
337 .node_name = "virtual-device-port",
338};
339
340static struct mdesc_notifier_client vio_ds_notifier = {
341 .add = vio_add,
342 .remove = vio_remove,
343 .node_name = "domain-services-port",
344};
345
356const char *channel_devices_node = "channel-devices"; 346const char *channel_devices_node = "channel-devices";
357const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; 347const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
358const char *cfg_handle_prop = "cfg-handle"; 348const char *cfg_handle_prop = "cfg-handle";
@@ -411,14 +401,19 @@ static int __init vio_init(void)
411 401
412 cdev_cfg_handle = *cfg_handle; 402 cdev_cfg_handle = *cfg_handle;
413 403
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
414 mdesc_register_notifier(&vio_device_notifier); 411 mdesc_register_notifier(&vio_device_notifier);
415 mdesc_register_notifier(&vio_ds_notifier); 412 mdesc_register_notifier(&vio_ds_notifier);
416 413
417 create_devices(hp, root);
418
419 mdesc_release(hp); 414 mdesc_release(hp);
420 415
421 return 0; 416 return err;
422 417
423out_release: 418out_release:
424 mdesc_release(hp); 419 mdesc_release(hp);