diff options
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 109 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_internal.h | 2 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_virtio.c | 13 |
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 | ||
282 | static int | 282 | int 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], ¬ifyid); | 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, ¬ifyid); | ||
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 | ||
353 | static void __rproc_free_vrings(struct rproc_vdev *rvdev, int i) | 333 | static int |
334 | rproc_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 | |||
364 | void 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 | ||
447 | free_vrings: | 454 | free_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); | |||
1264 | void rproc_release(struct kref *kref) | 1270 | void 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 | */ |
1547 | int rproc_unregister(struct rproc *rproc) | 1546 | int 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); | |||
41 | void rproc_init_debugfs(void); | 41 | void rproc_init_debugfs(void); |
42 | void rproc_exit_debugfs(void); | 42 | void rproc_exit_debugfs(void); |
43 | 43 | ||
44 | void rproc_free_vring(struct rproc_vring *rvring); | ||
45 | int 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 = { | |||
228 | static void rproc_vdev_release(struct device *dev) | 233 | static 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 | ||