aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/vio.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/vio.c')
-rw-r--r--arch/sparc64/kernel/vio.c143
1 files changed, 76 insertions, 67 deletions
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 7eccc91cd59d..64f082555bcd 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -147,30 +147,6 @@ void vio_unregister_driver(struct vio_driver *viodrv)
147} 147}
148EXPORT_SYMBOL(vio_unregister_driver); 148EXPORT_SYMBOL(vio_unregister_driver);
149 149
150struct mdesc_node *vio_find_endpoint(struct vio_dev *vdev)
151{
152 struct mdesc_node *endp, *mp = vdev->mp;
153 int i;
154
155 endp = NULL;
156 for (i = 0; i < mp->num_arcs; i++) {
157 struct mdesc_node *t;
158
159 if (strcmp(mp->arcs[i].name, "fwd"))
160 continue;
161
162 t = mp->arcs[i].arc;
163 if (strcmp(t->name, "channel-endpoint"))
164 continue;
165
166 endp = t;
167 break;
168 }
169
170 return endp;
171}
172EXPORT_SYMBOL(vio_find_endpoint);
173
174static void __devinit vio_dev_release(struct device *dev) 150static void __devinit vio_dev_release(struct device *dev)
175{ 151{
176 kfree(to_vio_dev(dev)); 152 kfree(to_vio_dev(dev));
@@ -197,22 +173,47 @@ struct device_node *cdev_node;
197static struct vio_dev *root_vdev; 173static struct vio_dev *root_vdev;
198static u64 cdev_cfg_handle; 174static u64 cdev_cfg_handle;
199 175
200static struct vio_dev *vio_create_one(struct mdesc_node *mp, 176static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
177 struct vio_dev *vdev)
178{
179 u64 a;
180
181 mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
182 const u64 *chan_id;
183 const u64 *irq;
184 u64 target;
185
186 target = mdesc_arc_target(hp, a);
187
188 irq = mdesc_get_property(hp, target, "tx-ino", NULL);
189 if (irq)
190 vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
191
192 irq = mdesc_get_property(hp, target, "rx-ino", NULL);
193 if (irq)
194 vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
195
196 chan_id = mdesc_get_property(hp, target, "id", NULL);
197 if (chan_id)
198 vdev->channel_id = *chan_id;
199 }
200}
201
202static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
201 struct device *parent) 203 struct device *parent)
202{ 204{
203 const char *type, *compat; 205 const char *type, *compat;
204 struct device_node *dp; 206 struct device_node *dp;
205 struct vio_dev *vdev; 207 struct vio_dev *vdev;
206 const u64 *irq;
207 int err, clen; 208 int err, clen;
208 209
209 type = md_get_property(mp, "device-type", NULL); 210 type = mdesc_get_property(hp, mp, "device-type", NULL);
210 if (!type) { 211 if (!type) {
211 type = md_get_property(mp, "name", NULL); 212 type = mdesc_get_property(hp, mp, "name", NULL);
212 if (!type) 213 if (!type)
213 type = mp->name; 214 type = mdesc_node_name(hp, mp);
214 } 215 }
215 compat = md_get_property(mp, "device-type", &clen); 216 compat = mdesc_get_property(hp, mp, "device-type", &clen);
216 217
217 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); 218 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
218 if (!vdev) { 219 if (!vdev) {
@@ -225,15 +226,13 @@ static struct vio_dev *vio_create_one(struct mdesc_node *mp,
225 vdev->compat = compat; 226 vdev->compat = compat;
226 vdev->compat_len = clen; 227 vdev->compat_len = clen;
227 228
228 irq = md_get_property(mp, "tx-ino", NULL); 229 vdev->channel_id = ~0UL;
229 if (irq) 230 vdev->tx_irq = ~0;
230 mp->irqs[0] = sun4v_build_virq(cdev_cfg_handle, *irq); 231 vdev->rx_irq = ~0;
231 232
232 irq = md_get_property(mp, "rx-ino", NULL); 233 vio_fill_channel_info(hp, mp, vdev);
233 if (irq)
234 mp->irqs[1] = sun4v_build_virq(cdev_cfg_handle, *irq);
235 234
236 snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp->node); 235 snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
237 vdev->dev.parent = parent; 236 vdev->dev.parent = parent;
238 vdev->dev.bus = &vio_bus_type; 237 vdev->dev.bus = &vio_bus_type;
239 vdev->dev.release = vio_dev_release; 238 vdev->dev.release = vio_dev_release;
@@ -267,46 +266,43 @@ static struct vio_dev *vio_create_one(struct mdesc_node *mp,
267 return vdev; 266 return vdev;
268} 267}
269 268
270static void walk_tree(struct mdesc_node *n, struct vio_dev *parent) 269static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
271{ 270{
272 int i; 271 u64 a;
273 272
274 for (i = 0; i < n->num_arcs; i++) { 273 mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
275 struct mdesc_node *mp;
276 struct vio_dev *vdev; 274 struct vio_dev *vdev;
275 u64 target;
277 276
278 if (strcmp(n->arcs[i].name, "fwd")) 277 target = mdesc_arc_target(hp, a);
279 continue; 278 vdev = vio_create_one(hp, target, &parent->dev);
280 279 if (vdev)
281 mp = n->arcs[i].arc; 280 walk_tree(hp, target, vdev);
282
283 vdev = vio_create_one(mp, &parent->dev);
284 if (vdev && mp->num_arcs)
285 walk_tree(mp, vdev);
286 } 281 }
287} 282}
288 283
289static void create_devices(struct mdesc_node *root) 284static void create_devices(struct mdesc_handle *hp, u64 root)
290{ 285{
291 struct mdesc_node *mp; 286 u64 mp;
292 287
293 root_vdev = vio_create_one(root, NULL); 288 root_vdev = vio_create_one(hp, root, NULL);
294 if (!root_vdev) { 289 if (!root_vdev) {
295 printk(KERN_ERR "VIO: Coult not create root device.\n"); 290 printk(KERN_ERR "VIO: Coult not create root device.\n");
296 return; 291 return;
297 } 292 }
298 293
299 walk_tree(root, root_vdev); 294 walk_tree(hp, root, root_vdev);
300 295
301 /* Domain services is odd as it doesn't sit underneath the 296 /* Domain services is odd as it doesn't sit underneath the
302 * channel-devices node, so we plug it in manually. 297 * channel-devices node, so we plug it in manually.
303 */ 298 */
304 mp = md_find_node_by_name(NULL, "domain-services"); 299 mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
305 if (mp) { 300 if (mp != MDESC_NODE_NULL) {
306 struct vio_dev *parent = vio_create_one(mp, &root_vdev->dev); 301 struct vio_dev *parent = vio_create_one(hp, mp,
302 &root_vdev->dev);
307 303
308 if (parent) 304 if (parent)
309 walk_tree(mp, parent); 305 walk_tree(hp, mp, parent);
310 } 306 }
311} 307}
312 308
@@ -316,40 +312,47 @@ const char *cfg_handle_prop = "cfg-handle";
316 312
317static int __init vio_init(void) 313static int __init vio_init(void)
318{ 314{
319 struct mdesc_node *root; 315 struct mdesc_handle *hp;
320 const char *compat; 316 const char *compat;
321 const u64 *cfg_handle; 317 const u64 *cfg_handle;
322 int err, len; 318 int err, len;
319 u64 root;
320
321 hp = mdesc_grab();
322 if (!hp)
323 return 0;
323 324
324 root = md_find_node_by_name(NULL, channel_devices_node); 325 root = mdesc_node_by_name(hp, MDESC_NODE_NULL, channel_devices_node);
325 if (!root) { 326 if (root == MDESC_NODE_NULL) {
326 printk(KERN_INFO "VIO: No channel-devices MDESC node.\n"); 327 printk(KERN_INFO "VIO: No channel-devices MDESC node.\n");
328 mdesc_release(hp);
327 return 0; 329 return 0;
328 } 330 }
329 331
330 cdev_node = of_find_node_by_name(NULL, "channel-devices"); 332 cdev_node = of_find_node_by_name(NULL, "channel-devices");
333 err = -ENODEV;
331 if (!cdev_node) { 334 if (!cdev_node) {
332 printk(KERN_INFO "VIO: No channel-devices OBP node.\n"); 335 printk(KERN_INFO "VIO: No channel-devices OBP node.\n");
333 return -ENODEV; 336 goto out_release;
334 } 337 }
335 338
336 compat = md_get_property(root, "compatible", &len); 339 compat = mdesc_get_property(hp, root, "compatible", &len);
337 if (!compat) { 340 if (!compat) {
338 printk(KERN_ERR "VIO: Channel devices lacks compatible " 341 printk(KERN_ERR "VIO: Channel devices lacks compatible "
339 "property\n"); 342 "property\n");
340 return -ENODEV; 343 goto out_release;
341 } 344 }
342 if (!find_in_proplist(compat, channel_devices_compat, len)) { 345 if (!find_in_proplist(compat, channel_devices_compat, len)) {
343 printk(KERN_ERR "VIO: Channel devices node lacks (%s) " 346 printk(KERN_ERR "VIO: Channel devices node lacks (%s) "
344 "compat entry.\n", channel_devices_compat); 347 "compat entry.\n", channel_devices_compat);
345 return -ENODEV; 348 goto out_release;
346 } 349 }
347 350
348 cfg_handle = md_get_property(root, cfg_handle_prop, NULL); 351 cfg_handle = mdesc_get_property(hp, root, cfg_handle_prop, NULL);
349 if (!cfg_handle) { 352 if (!cfg_handle) {
350 printk(KERN_ERR "VIO: Channel devices lacks %s property\n", 353 printk(KERN_ERR "VIO: Channel devices lacks %s property\n",
351 cfg_handle_prop); 354 cfg_handle_prop);
352 return -ENODEV; 355 goto out_release;
353 } 356 }
354 357
355 cdev_cfg_handle = *cfg_handle; 358 cdev_cfg_handle = *cfg_handle;
@@ -361,9 +364,15 @@ static int __init vio_init(void)
361 return err; 364 return err;
362 } 365 }
363 366
364 create_devices(root); 367 create_devices(hp, root);
368
369 mdesc_release(hp);
365 370
366 return 0; 371 return 0;
372
373out_release:
374 mdesc_release(hp);
375 return err;
367} 376}
368 377
369postcore_initcall(vio_init); 378postcore_initcall(vio_init);