]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/sparc/kernel/vio.c
sparc: vio: use dev_groups and not dev_attrs for bus_type
[karo-tx-linux.git] / arch / sparc / kernel / vio.c
1 /* vio.c: Virtual I/O channel devices probing infrastructure.
2  *
3  *    Copyright (c) 2003-2005 IBM Corp.
4  *     Dave Engebretsen engebret@us.ibm.com
5  *     Santiago Leon santil@us.ibm.com
6  *     Hollis Blanchard <hollisb@us.ibm.com>
7  *     Stephen Rothwell
8  *
9  * Adapted to sparc64 by David S. Miller davem@davemloft.net
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/irq.h>
15 #include <linux/export.h>
16 #include <linux/init.h>
17
18 #include <asm/mdesc.h>
19 #include <asm/vio.h>
20
21 static const struct vio_device_id *vio_match_device(
22         const struct vio_device_id *matches,
23         const struct vio_dev *dev)
24 {
25         const char *type, *compat;
26         int len;
27
28         type = dev->type;
29         compat = dev->compat;
30         len = dev->compat_len;
31
32         while (matches->type[0] || matches->compat[0]) {
33                 int match = 1;
34                 if (matches->type[0])
35                         match &= !strcmp(matches->type, type);
36
37                 if (matches->compat[0]) {
38                         match &= len &&
39                                 of_find_in_proplist(compat, matches->compat, len);
40                 }
41                 if (match)
42                         return matches;
43                 matches++;
44         }
45         return NULL;
46 }
47
48 static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
49 {
50         const struct vio_dev *vio_dev = to_vio_dev(dev);
51
52         add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, vio_dev->compat);
53         return 0;
54 }
55
56 static int vio_bus_match(struct device *dev, struct device_driver *drv)
57 {
58         struct vio_dev *vio_dev = to_vio_dev(dev);
59         struct vio_driver *vio_drv = to_vio_driver(drv);
60         const struct vio_device_id *matches = vio_drv->id_table;
61
62         if (!matches)
63                 return 0;
64
65         return vio_match_device(matches, vio_dev) != NULL;
66 }
67
68 static int vio_device_probe(struct device *dev)
69 {
70         struct vio_dev *vdev = to_vio_dev(dev);
71         struct vio_driver *drv = to_vio_driver(dev->driver);
72         const struct vio_device_id *id;
73         int error = -ENODEV;
74
75         if (drv->probe) {
76                 id = vio_match_device(drv->id_table, vdev);
77                 if (id)
78                         error = drv->probe(vdev, id);
79         }
80
81         return error;
82 }
83
84 static int vio_device_remove(struct device *dev)
85 {
86         struct vio_dev *vdev = to_vio_dev(dev);
87         struct vio_driver *drv = to_vio_driver(dev->driver);
88
89         if (drv->remove)
90                 return drv->remove(vdev);
91
92         return 1;
93 }
94
95 static ssize_t devspec_show(struct device *dev,
96                 struct device_attribute *attr, char *buf)
97 {
98         struct vio_dev *vdev = to_vio_dev(dev);
99         const char *str = "none";
100
101         if (!strcmp(vdev->type, "vnet-port"))
102                 str = "vnet";
103         else if (!strcmp(vdev->type, "vdc-port"))
104                 str = "vdisk";
105
106         return sprintf(buf, "%s\n", str);
107 }
108 static DEVICE_ATTR_RO(devspec);
109
110 static ssize_t type_show(struct device *dev,
111                 struct device_attribute *attr, char *buf)
112 {
113         struct vio_dev *vdev = to_vio_dev(dev);
114         return sprintf(buf, "%s\n", vdev->type);
115 }
116 static DEVICE_ATTR_RO(type);
117
118 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
119                              char *buf)
120 {
121         const struct vio_dev *vdev = to_vio_dev(dev);
122
123         return sprintf(buf, "vio:T%sS%s\n", vdev->type, vdev->compat);
124 }
125 static DEVICE_ATTR_RO(modalias);
126
127 static struct attribute *vio_dev_attrs[] = {
128         &dev_attr_devspec.attr,
129         &dev_attr_type.attr,
130         &dev_attr_modalias.attr,
131         NULL,
132  };
133 ATTRIBUTE_GROUPS(vio_dev);
134
135 static struct bus_type vio_bus_type = {
136         .name           = "vio",
137         .dev_groups     = vio_dev_groups,
138         .uevent         = vio_hotplug,
139         .match          = vio_bus_match,
140         .probe          = vio_device_probe,
141         .remove         = vio_device_remove,
142 };
143
144 int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
145                         const char *mod_name)
146 {
147         viodrv->driver.bus = &vio_bus_type;
148         viodrv->driver.name = viodrv->name;
149         viodrv->driver.owner = owner;
150         viodrv->driver.mod_name = mod_name;
151
152         return driver_register(&viodrv->driver);
153 }
154 EXPORT_SYMBOL(__vio_register_driver);
155
156 void vio_unregister_driver(struct vio_driver *viodrv)
157 {
158         driver_unregister(&viodrv->driver);
159 }
160 EXPORT_SYMBOL(vio_unregister_driver);
161
162 static void vio_dev_release(struct device *dev)
163 {
164         kfree(to_vio_dev(dev));
165 }
166
167 static ssize_t
168 show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
169                      char *buf)
170 {
171         struct vio_dev *vdev;
172         struct device_node *dp;
173
174         vdev = to_vio_dev(dev);
175         dp = vdev->dp;
176
177         return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
178 }
179
180 static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
181                    show_pciobppath_attr, NULL);
182
183 static struct device_node *cdev_node;
184
185 static struct vio_dev *root_vdev;
186 static u64 cdev_cfg_handle;
187
188 static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
189                                   struct vio_dev *vdev)
190 {
191         u64 a;
192
193         mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
194                 const u64 *chan_id;
195                 const u64 *irq;
196                 u64 target;
197
198                 target = mdesc_arc_target(hp, a);
199
200                 irq = mdesc_get_property(hp, target, "tx-ino", NULL);
201                 if (irq)
202                         vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
203
204                 irq = mdesc_get_property(hp, target, "rx-ino", NULL);
205                 if (irq) {
206                         vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
207                         vdev->rx_ino = *irq;
208                 }
209
210                 chan_id = mdesc_get_property(hp, target, "id", NULL);
211                 if (chan_id)
212                         vdev->channel_id = *chan_id;
213         }
214 }
215
216 int vio_set_intr(unsigned long dev_ino, int state)
217 {
218         int err;
219
220         err = sun4v_vintr_set_valid(cdev_cfg_handle, dev_ino, state);
221         return err;
222 }
223 EXPORT_SYMBOL(vio_set_intr);
224
225 static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
226                                       struct device *parent)
227 {
228         const char *type, *compat, *bus_id_name;
229         struct device_node *dp;
230         struct vio_dev *vdev;
231         int err, tlen, clen;
232         const u64 *id, *cfg_handle;
233         u64 a;
234
235         type = mdesc_get_property(hp, mp, "device-type", &tlen);
236         if (!type) {
237                 type = mdesc_get_property(hp, mp, "name", &tlen);
238                 if (!type) {
239                         type = mdesc_node_name(hp, mp);
240                         tlen = strlen(type) + 1;
241                 }
242         }
243         if (tlen > VIO_MAX_TYPE_LEN) {
244                 printk(KERN_ERR "VIO: Type string [%s] is too long.\n",
245                        type);
246                 return NULL;
247         }
248
249         id = mdesc_get_property(hp, mp, "id", NULL);
250
251         cfg_handle = NULL;
252         mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
253                 u64 target;
254
255                 target = mdesc_arc_target(hp, a);
256                 cfg_handle = mdesc_get_property(hp, target,
257                                                 "cfg-handle", NULL);
258                 if (cfg_handle)
259                         break;
260         }
261
262         bus_id_name = type;
263         if (!strcmp(type, "domain-services-port"))
264                 bus_id_name = "ds";
265
266         /*
267          * 20 char is the old driver-core name size limit, which is no more.
268          * This check can probably be removed after review and possible
269          * adaption of the vio users name length handling.
270          */
271         if (strlen(bus_id_name) >= 20 - 4) {
272                 printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
273                        bus_id_name);
274                 return NULL;
275         }
276
277         compat = mdesc_get_property(hp, mp, "device-type", &clen);
278         if (!compat) {
279                 clen = 0;
280         } else if (clen > VIO_MAX_COMPAT_LEN) {
281                 printk(KERN_ERR "VIO: Compat len %d for [%s] is too long.\n",
282                        clen, type);
283                 return NULL;
284         }
285
286         vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
287         if (!vdev) {
288                 printk(KERN_ERR "VIO: Could not allocate vio_dev\n");
289                 return NULL;
290         }
291
292         vdev->mp = mp;
293         memcpy(vdev->type, type, tlen);
294         if (compat)
295                 memcpy(vdev->compat, compat, clen);
296         else
297                 memset(vdev->compat, 0, sizeof(vdev->compat));
298         vdev->compat_len = clen;
299
300         vdev->channel_id = ~0UL;
301         vdev->tx_irq = ~0;
302         vdev->rx_irq = ~0;
303
304         vio_fill_channel_info(hp, mp, vdev);
305
306         if (!id) {
307                 dev_set_name(&vdev->dev, "%s", bus_id_name);
308                 vdev->dev_no = ~(u64)0;
309         } else if (!cfg_handle) {
310                 dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);
311                 vdev->dev_no = *id;
312         } else {
313                 dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,
314                              *cfg_handle, *id);
315                 vdev->dev_no = *cfg_handle;
316         }
317
318         vdev->dev.parent = parent;
319         vdev->dev.bus = &vio_bus_type;
320         vdev->dev.release = vio_dev_release;
321
322         if (parent == NULL) {
323                 dp = cdev_node;
324         } else if (to_vio_dev(parent) == root_vdev) {
325                 dp = of_get_next_child(cdev_node, NULL);
326                 while (dp) {
327                         if (!strcmp(dp->type, type))
328                                 break;
329
330                         dp = of_get_next_child(cdev_node, dp);
331                 }
332         } else {
333                 dp = to_vio_dev(parent)->dp;
334         }
335         vdev->dp = dp;
336
337         printk(KERN_INFO "VIO: Adding device %s\n", dev_name(&vdev->dev));
338
339         err = device_register(&vdev->dev);
340         if (err) {
341                 printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
342                        dev_name(&vdev->dev), err);
343                 kfree(vdev);
344                 return NULL;
345         }
346         if (vdev->dp)
347                 err = sysfs_create_file(&vdev->dev.kobj,
348                                         &dev_attr_obppath.attr);
349
350         return vdev;
351 }
352
353 static void vio_add(struct mdesc_handle *hp, u64 node)
354 {
355         (void) vio_create_one(hp, node, &root_vdev->dev);
356 }
357
358 static int vio_md_node_match(struct device *dev, void *arg)
359 {
360         struct vio_dev *vdev = to_vio_dev(dev);
361
362         if (vdev->mp == (u64) arg)
363                 return 1;
364
365         return 0;
366 }
367
368 static void vio_remove(struct mdesc_handle *hp, u64 node)
369 {
370         struct device *dev;
371
372         dev = device_find_child(&root_vdev->dev, (void *) node,
373                                 vio_md_node_match);
374         if (dev) {
375                 printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
376
377                 device_unregister(dev);
378                 put_device(dev);
379         }
380 }
381
382 static struct mdesc_notifier_client vio_device_notifier = {
383         .add            = vio_add,
384         .remove         = vio_remove,
385         .node_name      = "virtual-device-port",
386 };
387
388 /* We are only interested in domain service ports under the
389  * "domain-services" node.  On control nodes there is another port
390  * under "openboot" that we should not mess with as aparently that is
391  * reserved exclusively for OBP use.
392  */
393 static void vio_add_ds(struct mdesc_handle *hp, u64 node)
394 {
395         int found;
396         u64 a;
397
398         found = 0;
399         mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
400                 u64 target = mdesc_arc_target(hp, a);
401                 const char *name = mdesc_node_name(hp, target);
402
403                 if (!strcmp(name, "domain-services")) {
404                         found = 1;
405                         break;
406                 }
407         }
408
409         if (found)
410                 (void) vio_create_one(hp, node, &root_vdev->dev);
411 }
412
413 static struct mdesc_notifier_client vio_ds_notifier = {
414         .add            = vio_add_ds,
415         .remove         = vio_remove,
416         .node_name      = "domain-services-port",
417 };
418
419 static const char *channel_devices_node = "channel-devices";
420 static const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
421 static const char *cfg_handle_prop = "cfg-handle";
422
423 static int __init vio_init(void)
424 {
425         struct mdesc_handle *hp;
426         const char *compat;
427         const u64 *cfg_handle;
428         int err, len;
429         u64 root;
430
431         err = bus_register(&vio_bus_type);
432         if (err) {
433                 printk(KERN_ERR "VIO: Could not register bus type err=%d\n",
434                        err);
435                 return err;
436         }
437
438         hp = mdesc_grab();
439         if (!hp)
440                 return 0;
441
442         root = mdesc_node_by_name(hp, MDESC_NODE_NULL, channel_devices_node);
443         if (root == MDESC_NODE_NULL) {
444                 printk(KERN_INFO "VIO: No channel-devices MDESC node.\n");
445                 mdesc_release(hp);
446                 return 0;
447         }
448
449         cdev_node = of_find_node_by_name(NULL, "channel-devices");
450         err = -ENODEV;
451         if (!cdev_node) {
452                 printk(KERN_INFO "VIO: No channel-devices OBP node.\n");
453                 goto out_release;
454         }
455
456         compat = mdesc_get_property(hp, root, "compatible", &len);
457         if (!compat) {
458                 printk(KERN_ERR "VIO: Channel devices lacks compatible "
459                        "property\n");
460                 goto out_release;
461         }
462         if (!of_find_in_proplist(compat, channel_devices_compat, len)) {
463                 printk(KERN_ERR "VIO: Channel devices node lacks (%s) "
464                        "compat entry.\n", channel_devices_compat);
465                 goto out_release;
466         }
467
468         cfg_handle = mdesc_get_property(hp, root, cfg_handle_prop, NULL);
469         if (!cfg_handle) {
470                 printk(KERN_ERR "VIO: Channel devices lacks %s property\n",
471                        cfg_handle_prop);
472                 goto out_release;
473         }
474
475         cdev_cfg_handle = *cfg_handle;
476
477         root_vdev = vio_create_one(hp, root, NULL);
478         err = -ENODEV;
479         if (!root_vdev) {
480                 printk(KERN_ERR "VIO: Could not create root device.\n");
481                 goto out_release;
482         }
483
484         mdesc_register_notifier(&vio_device_notifier);
485         mdesc_register_notifier(&vio_ds_notifier);
486
487         mdesc_release(hp);
488
489         return err;
490
491 out_release:
492         mdesc_release(hp);
493         return err;
494 }
495
496 postcore_initcall(vio_init);