diff options
Diffstat (limited to 'arch/sparc64/kernel/vio.c')
-rw-r--r-- | arch/sparc64/kernel/vio.c | 143 |
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 | } |
148 | EXPORT_SYMBOL(vio_unregister_driver); | 148 | EXPORT_SYMBOL(vio_unregister_driver); |
149 | 149 | ||
150 | struct 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 | } | ||
172 | EXPORT_SYMBOL(vio_find_endpoint); | ||
173 | |||
174 | static void __devinit vio_dev_release(struct device *dev) | 150 | static 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; | |||
197 | static struct vio_dev *root_vdev; | 173 | static struct vio_dev *root_vdev; |
198 | static u64 cdev_cfg_handle; | 174 | static u64 cdev_cfg_handle; |
199 | 175 | ||
200 | static struct vio_dev *vio_create_one(struct mdesc_node *mp, | 176 | static 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 | |||
202 | static 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 | ||
270 | static void walk_tree(struct mdesc_node *n, struct vio_dev *parent) | 269 | static 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 | ||
289 | static void create_devices(struct mdesc_node *root) | 284 | static 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 | ||
317 | static int __init vio_init(void) | 313 | static 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 | |||
373 | out_release: | ||
374 | mdesc_release(hp); | ||
375 | return err; | ||
367 | } | 376 | } |
368 | 377 | ||
369 | postcore_initcall(vio_init); | 378 | postcore_initcall(vio_init); |