aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2012-05-17 07:23:59 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2012-07-04 06:27:04 -0400
commit6db20ea8d85064175c7ef594c433c6c2e6bbab83 (patch)
tree6087ffde8501059bdfd578758fb05c53aba3d620 /drivers/remoteproc
parent485802a6c524e62b5924849dd727ddbb1497cc71 (diff)
remoteproc: allocate vrings on demand, free when not needed
Dynamically allocate the vrings' DMA when the remote processor is about to be powered on (i.e. when ->find_vqs() is invoked), and release them as soon as it is powered off (i.e. when ->del_vqs() is invoked). The obvious and immediate benefit is better memory utilization, since memory for the vrings is now only allocated when the relevant remote processor is used. Additionally, this approach also makes recovery of a (crashing) remote processor easier: one just needs to remove the relevant vdevs, and the entire vrings cleanup takes place automagically. Tested-by: Fernando Guzman Lugo <fernando.lugo@ti.com> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/remoteproc_core.c109
-rw-r--r--drivers/remoteproc/remoteproc_internal.h2
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c13
3 files changed, 67 insertions, 57 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 8ea7bccc7100..288d4175bbf6 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -279,34 +279,17 @@ rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len)
279 return ret; 279 return ret;
280} 280}
281 281
282static int 282int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
283__rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
284{ 283{
285 struct rproc *rproc = rvdev->rproc; 284 struct rproc *rproc = rvdev->rproc;
286 struct device *dev = rproc->dev; 285 struct device *dev = rproc->dev;
287 struct fw_rsc_vdev_vring *vring = &rsc->vring[i]; 286 struct rproc_vring *rvring = &rvdev->vring[i];
288 dma_addr_t dma; 287 dma_addr_t dma;
289 void *va; 288 void *va;
290 int ret, size, notifyid; 289 int ret, size, notifyid;
291 290
292 dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
293 i, vring->da, vring->num, vring->align);
294
295 /* make sure reserved bytes are zeroes */
296 if (vring->reserved) {
297 dev_err(dev, "vring rsc has non zero reserved bytes\n");
298 return -EINVAL;
299 }
300
301 /* verify queue size and vring alignment are sane */
302 if (!vring->num || !vring->align) {
303 dev_err(dev, "invalid qsz (%d) or alignment (%d)\n",
304 vring->num, vring->align);
305 return -EINVAL;
306 }
307
308 /* actual size of vring (in bytes) */ 291 /* actual size of vring (in bytes) */
309 size = PAGE_ALIGN(vring_size(vring->num, vring->align)); 292 size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
310 293
311 if (!idr_pre_get(&rproc->notifyids, GFP_KERNEL)) { 294 if (!idr_pre_get(&rproc->notifyids, GFP_KERNEL)) {
312 dev_err(dev, "idr_pre_get failed\n"); 295 dev_err(dev, "idr_pre_get failed\n");
@@ -316,6 +299,7 @@ __rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
316 /* 299 /*
317 * Allocate non-cacheable memory for the vring. In the future 300 * Allocate non-cacheable memory for the vring. In the future
318 * this call will also configure the IOMMU for us 301 * this call will also configure the IOMMU for us
302 * TODO: let the rproc know the da of this vring
319 */ 303 */
320 va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL); 304 va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
321 if (!va) { 305 if (!va) {
@@ -323,44 +307,67 @@ __rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
323 return -EINVAL; 307 return -EINVAL;
324 } 308 }
325 309
326 /* assign an rproc-wide unique index for this vring */ 310 /*
327 /* TODO: assign a notifyid for rvdev updates as well */ 311 * Assign an rproc-wide unique index for this vring
328 ret = idr_get_new(&rproc->notifyids, &rvdev->vring[i], &notifyid); 312 * TODO: assign a notifyid for rvdev updates as well
313 * TODO: let the rproc know the notifyid of this vring
314 * TODO: support predefined notifyids (via resource table)
315 */
316 ret = idr_get_new(&rproc->notifyids, rvring, &notifyid);
329 if (ret) { 317 if (ret) {
330 dev_err(dev, "idr_get_new failed: %d\n", ret); 318 dev_err(dev, "idr_get_new failed: %d\n", ret);
331 dma_free_coherent(dev, size, va, dma); 319 dma_free_coherent(dev, size, va, dma);
332 return ret; 320 return ret;
333 } 321 }
334 322
335 /* let the rproc know the da and notifyid of this vring */
336 /* TODO: expose this to remote processor */
337 vring->da = dma;
338 vring->notifyid = notifyid;
339
340 dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va, 323 dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
341 dma, size, notifyid); 324 dma, size, notifyid);
342 325
343 rvdev->vring[i].len = vring->num; 326 rvring->va = va;
344 rvdev->vring[i].align = vring->align; 327 rvring->dma = dma;
345 rvdev->vring[i].va = va; 328 rvring->notifyid = notifyid;
346 rvdev->vring[i].dma = dma;
347 rvdev->vring[i].notifyid = notifyid;
348 rvdev->vring[i].rvdev = rvdev;
349 329
350 return 0; 330 return 0;
351} 331}
352 332
353static void __rproc_free_vrings(struct rproc_vdev *rvdev, int i) 333static int
334rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
354{ 335{
355 struct rproc *rproc = rvdev->rproc; 336 struct rproc *rproc = rvdev->rproc;
337 struct device *dev = rproc->dev;
338 struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
339 struct rproc_vring *rvring = &rvdev->vring[i];
356 340
357 for (i--; i >= 0; i--) { 341 dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
358 struct rproc_vring *rvring = &rvdev->vring[i]; 342 i, vring->da, vring->num, vring->align);
359 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); 343
344 /* make sure reserved bytes are zeroes */
345 if (vring->reserved) {
346 dev_err(dev, "vring rsc has non zero reserved bytes\n");
347 return -EINVAL;
348 }
360 349
361 dma_free_coherent(rproc->dev, size, rvring->va, rvring->dma); 350 /* verify queue size and vring alignment are sane */
362 idr_remove(&rproc->notifyids, rvring->notifyid); 351 if (!vring->num || !vring->align) {
352 dev_err(dev, "invalid qsz (%d) or alignment (%d)\n",
353 vring->num, vring->align);
354 return -EINVAL;
363 } 355 }
356
357 rvring->len = vring->num;
358 rvring->align = vring->align;
359 rvring->rvdev = rvdev;
360
361 return 0;
362}
363
364void rproc_free_vring(struct rproc_vring *rvring)
365{
366 int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
367 struct rproc *rproc = rvring->rvdev->rproc;
368
369 dma_free_coherent(rproc->dev, size, rvring->va, rvring->dma);
370 idr_remove(&rproc->notifyids, rvring->notifyid);
364} 371}
365 372
366/** 373/**
@@ -425,11 +432,11 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
425 432
426 rvdev->rproc = rproc; 433 rvdev->rproc = rproc;
427 434
428 /* allocate the vrings */ 435 /* parse the vrings */
429 for (i = 0; i < rsc->num_of_vrings; i++) { 436 for (i = 0; i < rsc->num_of_vrings; i++) {
430 ret = __rproc_handle_vring(rvdev, rsc, i); 437 ret = rproc_parse_vring(rvdev, rsc, i);
431 if (ret) 438 if (ret)
432 goto free_vrings; 439 goto free_rvdev;
433 } 440 }
434 441
435 /* remember the device features */ 442 /* remember the device features */
@@ -440,12 +447,11 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
440 /* it is now safe to add the virtio device */ 447 /* it is now safe to add the virtio device */
441 ret = rproc_add_virtio_dev(rvdev, rsc->id); 448 ret = rproc_add_virtio_dev(rvdev, rsc->id);
442 if (ret) 449 if (ret)
443 goto free_vrings; 450 goto free_rvdev;
444 451
445 return 0; 452 return 0;
446 453
447free_vrings: 454free_rvdev:
448 __rproc_free_vrings(rvdev, i);
449 kfree(rvdev); 455 kfree(rvdev);
450 return ret; 456 return ret;
451} 457}
@@ -1264,18 +1270,11 @@ EXPORT_SYMBOL(rproc_shutdown);
1264void rproc_release(struct kref *kref) 1270void rproc_release(struct kref *kref)
1265{ 1271{
1266 struct rproc *rproc = container_of(kref, struct rproc, refcount); 1272 struct rproc *rproc = container_of(kref, struct rproc, refcount);
1267 struct rproc_vdev *rvdev, *rvtmp;
1268 1273
1269 dev_info(rproc->dev, "removing %s\n", rproc->name); 1274 dev_info(rproc->dev, "removing %s\n", rproc->name);
1270 1275
1271 rproc_delete_debug_dir(rproc); 1276 rproc_delete_debug_dir(rproc);
1272 1277
1273 /* clean up remote vdev entries */
1274 list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) {
1275 __rproc_free_vrings(rvdev, RVDEV_NUM_VRINGS);
1276 list_del(&rvdev->node);
1277 }
1278
1279 /* 1278 /*
1280 * At this point no one holds a reference to rproc anymore, 1279 * At this point no one holds a reference to rproc anymore,
1281 * so we can directly unroll rproc_alloc() 1280 * so we can directly unroll rproc_alloc()
@@ -1546,7 +1545,7 @@ EXPORT_SYMBOL(rproc_free);
1546 */ 1545 */
1547int rproc_unregister(struct rproc *rproc) 1546int rproc_unregister(struct rproc *rproc)
1548{ 1547{
1549 struct rproc_vdev *rvdev; 1548 struct rproc_vdev *rvdev, *tmp;
1550 1549
1551 if (!rproc) 1550 if (!rproc)
1552 return -EINVAL; 1551 return -EINVAL;
@@ -1555,7 +1554,7 @@ int rproc_unregister(struct rproc *rproc)
1555 wait_for_completion(&rproc->firmware_loading_complete); 1554 wait_for_completion(&rproc->firmware_loading_complete);
1556 1555
1557 /* clean up remote vdev entries */ 1556 /* clean up remote vdev entries */
1558 list_for_each_entry(rvdev, &rproc->rvdevs, node) 1557 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
1559 rproc_remove_virtio_dev(rvdev); 1558 rproc_remove_virtio_dev(rvdev);
1560 1559
1561 /* the rproc is downref'ed as soon as it's removed from the klist */ 1560 /* the rproc is downref'ed as soon as it's removed from the klist */
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 9f336d6bdef3..f4957cfa0883 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -41,4 +41,6 @@ void rproc_create_debug_dir(struct rproc *rproc);
41void rproc_init_debugfs(void); 41void rproc_init_debugfs(void);
42void rproc_exit_debugfs(void); 42void rproc_exit_debugfs(void);
43 43
44void rproc_free_vring(struct rproc_vring *rvring);
45int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
44#endif /* REMOTEPROC_INTERNAL_H */ 46#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index ecf612130750..26a7144e7f3b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -77,14 +77,17 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
77 struct rproc_vring *rvring; 77 struct rproc_vring *rvring;
78 struct virtqueue *vq; 78 struct virtqueue *vq;
79 void *addr; 79 void *addr;
80 int len, size; 80 int len, size, ret;
81 81
82 /* we're temporarily limited to two virtqueues per rvdev */ 82 /* we're temporarily limited to two virtqueues per rvdev */
83 if (id >= ARRAY_SIZE(rvdev->vring)) 83 if (id >= ARRAY_SIZE(rvdev->vring))
84 return ERR_PTR(-EINVAL); 84 return ERR_PTR(-EINVAL);
85 85
86 rvring = &rvdev->vring[id]; 86 ret = rproc_alloc_vring(rvdev, id);
87 if (ret)
88 return ERR_PTR(ret);
87 89
90 rvring = &rvdev->vring[id];
88 addr = rvring->va; 91 addr = rvring->va;
89 len = rvring->len; 92 len = rvring->len;
90 93
@@ -103,6 +106,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
103 rproc_virtio_notify, callback, name); 106 rproc_virtio_notify, callback, name);
104 if (!vq) { 107 if (!vq) {
105 dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name); 108 dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name);
109 rproc_free_vring(rvring);
106 return ERR_PTR(-ENOMEM); 110 return ERR_PTR(-ENOMEM);
107 } 111 }
108 112
@@ -125,6 +129,7 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev)
125 rvring = vq->priv; 129 rvring = vq->priv;
126 rvring->vq = NULL; 130 rvring->vq = NULL;
127 vring_del_virtqueue(vq); 131 vring_del_virtqueue(vq);
132 rproc_free_vring(rvring);
128 } 133 }
129} 134}
130 135
@@ -228,8 +233,12 @@ static struct virtio_config_ops rproc_virtio_config_ops = {
228static void rproc_vdev_release(struct device *dev) 233static void rproc_vdev_release(struct device *dev)
229{ 234{
230 struct virtio_device *vdev = dev_to_virtio(dev); 235 struct virtio_device *vdev = dev_to_virtio(dev);
236 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
231 struct rproc *rproc = vdev_to_rproc(vdev); 237 struct rproc *rproc = vdev_to_rproc(vdev);
232 238
239 list_del(&rvdev->node);
240 kfree(rvdev);
241
233 kref_put(&rproc->refcount, rproc_release); 242 kref_put(&rproc->refcount, rproc_release);
234} 243}
235 244