aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/vio.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-18 02:03:47 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-18 04:20:04 -0400
commit6160f63518406485c7009cb0f2e1588ea3abccc1 (patch)
treed0adeedae350dc4829e7eacbf198627a107f393f /arch/sparc64/kernel/vio.c
parent9184a046328d2dfc9f2cf0f831e649a108492124 (diff)
[SPARC64]: Massively simplify VIO device layer and support hot add/remove.
Create and destroy VIO devices in response to MD update events. These run synchronously inside of the MD update mutex so the VIO layer doesn't need to do internal locking of any sort. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/vio.c')
-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);