diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/vio.c | 123 |
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; | |||
172 | static struct vio_dev *root_vdev; | 172 | static struct vio_dev *root_vdev; |
173 | static u64 cdev_cfg_handle; | 173 | static u64 cdev_cfg_handle; |
174 | 174 | ||
175 | static 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 | |||
184 | static 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 | |||
193 | static struct mdesc_notifier_client vio_device_notifier = { | ||
194 | .add = vio_add, | ||
195 | .remove = vio_remove, | ||
196 | .node_name = "virtual-device-port", | ||
197 | }; | ||
198 | |||
199 | static struct mdesc_notifier_client vio_ds_notifier = { | ||
200 | .add = vio_add, | ||
201 | .remove = vio_remove, | ||
202 | .node_name = "domain-services-port", | ||
203 | }; | ||
204 | |||
205 | static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, | 175 | static 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, | |||
231 | 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, |
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 | ||
316 | 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) |
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 | ||
331 | static void create_devices(struct mdesc_handle *hp, u64 root) | 311 | static 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 | 321 | static 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 | ||
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 | |||
356 | const char *channel_devices_node = "channel-devices"; | 346 | const char *channel_devices_node = "channel-devices"; |
357 | const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; | 347 | const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; |
358 | const char *cfg_handle_prop = "cfg-handle"; | 348 | const 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 | ||
423 | out_release: | 418 | out_release: |
424 | mdesc_release(hp); | 419 | mdesc_release(hp); |