aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/vio.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-12 16:47:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-16 07:04:28 -0400
commit43fdf27470b216ebdef47e09ff83bed2f2894b13 (patch)
tree76b9b838089e5679471026037c93325c228df84a /arch/sparc64/kernel/vio.c
parent133f09a169f3022be3de671b29658b7ecb375022 (diff)
[SPARC64]: Abstract out mdesc accesses for better MD update handling.
Since we have to be able to handle MD updates, having an in-tree set of data structures representing the MD objects actually makes things more painful. The MD itself is easy to parse, and we can implement the existing interfaces using direct parsing of the MD binary image. The MD is now reference counted, so accesses have to now take the form: handle = mdesc_grab(); ... operations on MD ... mdesc_release(handle); The only remaining issue are cases where code holds on to references to MD property values. mdesc_get_property() returns a direct pointer to the property value, most cases just pull in the information they need and discard the pointer, but there are few that use the pointer directly over a long lifetime. Those will be fixed up in a subsequent changeset. A preliminary handler for MD update events from domain services is there, it is rudimentry but it works and handles all of the reference counting. It does not check the generation number of the MDs, and it does not generate a "add/delete" list for notification to interesting parties about MD changes but that will be forthcoming. Signed-off-by: David S. Miller <davem@davemloft.net>
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);