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 | ||
