diff options
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 61 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_internal.h | 2 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_virtio.c | 14 | ||||
-rw-r--r-- | include/linux/remoteproc.h | 6 |
4 files changed, 51 insertions, 32 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 5abcd27a29f3..f77a42f6a8aa 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -53,6 +53,11 @@ typedef int (*rproc_handle_resources_t)(struct rproc *rproc, | |||
53 | typedef int (*rproc_handle_resource_t)(struct rproc *rproc, | 53 | typedef int (*rproc_handle_resource_t)(struct rproc *rproc, |
54 | void *, int offset, int avail); | 54 | void *, int offset, int avail); |
55 | 55 | ||
56 | static int rproc_alloc_carveout(struct rproc *rproc, | ||
57 | struct rproc_mem_entry *mem); | ||
58 | static int rproc_release_carveout(struct rproc *rproc, | ||
59 | struct rproc_mem_entry *mem); | ||
60 | |||
56 | /* Unique indices for remoteproc devices */ | 61 | /* Unique indices for remoteproc devices */ |
57 | static DEFINE_IDA(rproc_dev_index); | 62 | static DEFINE_IDA(rproc_dev_index); |
58 | 63 | ||
@@ -312,21 +317,33 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) | |||
312 | struct device *dev = &rproc->dev; | 317 | struct device *dev = &rproc->dev; |
313 | struct rproc_vring *rvring = &rvdev->vring[i]; | 318 | struct rproc_vring *rvring = &rvdev->vring[i]; |
314 | struct fw_rsc_vdev *rsc; | 319 | struct fw_rsc_vdev *rsc; |
315 | dma_addr_t dma; | ||
316 | void *va; | ||
317 | int ret, size, notifyid; | 320 | int ret, size, notifyid; |
321 | struct rproc_mem_entry *mem; | ||
318 | 322 | ||
319 | /* actual size of vring (in bytes) */ | 323 | /* actual size of vring (in bytes) */ |
320 | size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); | 324 | size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); |
321 | 325 | ||
322 | /* | 326 | rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; |
323 | * Allocate non-cacheable memory for the vring. In the future | 327 | |
324 | * this call will also configure the IOMMU for us | 328 | /* Search for pre-registered carveout */ |
325 | */ | 329 | mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index, |
326 | va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL); | 330 | i); |
327 | if (!va) { | 331 | if (mem) { |
328 | dev_err(dev->parent, "dma_alloc_coherent failed\n"); | 332 | if (rproc_check_carveout_da(rproc, mem, rsc->vring[i].da, size)) |
329 | return -EINVAL; | 333 | return -ENOMEM; |
334 | } else { | ||
335 | /* Register carveout in in list */ | ||
336 | mem = rproc_mem_entry_init(dev, 0, 0, size, rsc->vring[i].da, | ||
337 | rproc_alloc_carveout, | ||
338 | rproc_release_carveout, | ||
339 | "vdev%dvring%d", | ||
340 | rvdev->index, i); | ||
341 | if (!mem) { | ||
342 | dev_err(dev, "Can't allocate memory entry structure\n"); | ||
343 | return -ENOMEM; | ||
344 | } | ||
345 | |||
346 | rproc_add_carveout(rproc, mem); | ||
330 | } | 347 | } |
331 | 348 | ||
332 | /* | 349 | /* |
@@ -337,7 +354,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) | |||
337 | ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); | 354 | ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL); |
338 | if (ret < 0) { | 355 | if (ret < 0) { |
339 | dev_err(dev, "idr_alloc failed: %d\n", ret); | 356 | dev_err(dev, "idr_alloc failed: %d\n", ret); |
340 | dma_free_coherent(dev->parent, size, va, dma); | ||
341 | return ret; | 357 | return ret; |
342 | } | 358 | } |
343 | notifyid = ret; | 359 | notifyid = ret; |
@@ -346,21 +362,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) | |||
346 | if (notifyid > rproc->max_notifyid) | 362 | if (notifyid > rproc->max_notifyid) |
347 | rproc->max_notifyid = notifyid; | 363 | rproc->max_notifyid = notifyid; |
348 | 364 | ||
349 | dev_dbg(dev, "vring%d: va %pK dma %pad size 0x%x idr %d\n", | ||
350 | i, va, &dma, size, notifyid); | ||
351 | |||
352 | rvring->va = va; | ||
353 | rvring->dma = dma; | ||
354 | rvring->notifyid = notifyid; | 365 | rvring->notifyid = notifyid; |
355 | 366 | ||
356 | /* | 367 | /* Let the rproc know the notifyid of this vring.*/ |
357 | * Let the rproc know the notifyid and da of this vring. | ||
358 | * Not all platforms use dma_alloc_coherent to automatically | ||
359 | * set up the iommu. In this case the device address (da) will | ||
360 | * hold the physical address and not the device address. | ||
361 | */ | ||
362 | rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; | ||
363 | rsc->vring[i].da = dma; | ||
364 | rsc->vring[i].notifyid = notifyid; | 368 | rsc->vring[i].notifyid = notifyid; |
365 | return 0; | 369 | return 0; |
366 | } | 370 | } |
@@ -392,12 +396,10 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) | |||
392 | 396 | ||
393 | void rproc_free_vring(struct rproc_vring *rvring) | 397 | void rproc_free_vring(struct rproc_vring *rvring) |
394 | { | 398 | { |
395 | int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); | ||
396 | struct rproc *rproc = rvring->rvdev->rproc; | 399 | struct rproc *rproc = rvring->rvdev->rproc; |
397 | int idx = rvring->rvdev->vring - rvring; | 400 | int idx = rvring->rvdev->vring - rvring; |
398 | struct fw_rsc_vdev *rsc; | 401 | struct fw_rsc_vdev *rsc; |
399 | 402 | ||
400 | dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); | ||
401 | idr_remove(&rproc->notifyids, rvring->notifyid); | 403 | idr_remove(&rproc->notifyids, rvring->notifyid); |
402 | 404 | ||
403 | /* reset resource entry info */ | 405 | /* reset resource entry info */ |
@@ -484,6 +486,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, | |||
484 | 486 | ||
485 | rvdev->id = rsc->id; | 487 | rvdev->id = rsc->id; |
486 | rvdev->rproc = rproc; | 488 | rvdev->rproc = rproc; |
489 | rvdev->index = rproc->nb_vdev++; | ||
487 | 490 | ||
488 | /* parse the vrings */ | 491 | /* parse the vrings */ |
489 | for (i = 0; i < rsc->num_of_vrings; i++) { | 492 | for (i = 0; i < rsc->num_of_vrings; i++) { |
@@ -528,9 +531,6 @@ void rproc_vdev_release(struct kref *ref) | |||
528 | 531 | ||
529 | for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) { | 532 | for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) { |
530 | rvring = &rvdev->vring[id]; | 533 | rvring = &rvdev->vring[id]; |
531 | if (!rvring->va) | ||
532 | continue; | ||
533 | |||
534 | rproc_free_vring(rvring); | 534 | rproc_free_vring(rvring); |
535 | } | 535 | } |
536 | 536 | ||
@@ -1323,6 +1323,9 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) | |||
1323 | /* reset max_notifyid */ | 1323 | /* reset max_notifyid */ |
1324 | rproc->max_notifyid = -1; | 1324 | rproc->max_notifyid = -1; |
1325 | 1325 | ||
1326 | /* reset handled vdev */ | ||
1327 | rproc->nb_vdev = 0; | ||
1328 | |||
1326 | /* handle fw resources which are required to boot rproc */ | 1329 | /* handle fw resources which are required to boot rproc */ |
1327 | ret = rproc_handle_resources(rproc, rproc_loading_handlers); | 1330 | ret = rproc_handle_resources(rproc, rproc_loading_handlers); |
1328 | if (ret) { | 1331 | if (ret) { |
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 7570beb035b5..f6cad243d7ca 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h | |||
@@ -60,6 +60,8 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw); | |||
60 | int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw); | 60 | int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw); |
61 | struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, | 61 | struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc, |
62 | const struct firmware *fw); | 62 | const struct firmware *fw); |
63 | struct rproc_mem_entry * | ||
64 | rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...); | ||
63 | 65 | ||
64 | static inline | 66 | static inline |
65 | int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) | 67 | int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) |
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index bbecd44df7e8..de21f620b882 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c | |||
@@ -76,7 +76,9 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, | |||
76 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); | 76 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); |
77 | struct rproc *rproc = vdev_to_rproc(vdev); | 77 | struct rproc *rproc = vdev_to_rproc(vdev); |
78 | struct device *dev = &rproc->dev; | 78 | struct device *dev = &rproc->dev; |
79 | struct rproc_mem_entry *mem; | ||
79 | struct rproc_vring *rvring; | 80 | struct rproc_vring *rvring; |
81 | struct fw_rsc_vdev *rsc; | ||
80 | struct virtqueue *vq; | 82 | struct virtqueue *vq; |
81 | void *addr; | 83 | void *addr; |
82 | int len, size; | 84 | int len, size; |
@@ -88,8 +90,14 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, | |||
88 | if (!name) | 90 | if (!name) |
89 | return NULL; | 91 | return NULL; |
90 | 92 | ||
93 | /* Search allocated memory region by name */ | ||
94 | mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index, | ||
95 | id); | ||
96 | if (!mem || !mem->va) | ||
97 | return ERR_PTR(-ENOMEM); | ||
98 | |||
91 | rvring = &rvdev->vring[id]; | 99 | rvring = &rvdev->vring[id]; |
92 | addr = rvring->va; | 100 | addr = mem->va; |
93 | len = rvring->len; | 101 | len = rvring->len; |
94 | 102 | ||
95 | /* zero vring */ | 103 | /* zero vring */ |
@@ -114,6 +122,10 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, | |||
114 | rvring->vq = vq; | 122 | rvring->vq = vq; |
115 | vq->priv = rvring; | 123 | vq->priv = rvring; |
116 | 124 | ||
125 | /* Update vring in resource table */ | ||
126 | rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; | ||
127 | rsc->vring[id].da = mem->da; | ||
128 | |||
117 | return vq; | 129 | return vq; |
118 | } | 130 | } |
119 | 131 | ||
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index d4cabe8da507..8bb0cf0416f1 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h | |||
@@ -454,6 +454,7 @@ struct rproc_dump_segment { | |||
454 | * @has_iommu: flag to indicate if remote processor is behind an MMU | 454 | * @has_iommu: flag to indicate if remote processor is behind an MMU |
455 | * @auto_boot: flag to indicate if remote processor should be auto-started | 455 | * @auto_boot: flag to indicate if remote processor should be auto-started |
456 | * @dump_segments: list of segments in the firmware | 456 | * @dump_segments: list of segments in the firmware |
457 | * @nb_vdev: number of vdev currently handled by rproc | ||
457 | */ | 458 | */ |
458 | struct rproc { | 459 | struct rproc { |
459 | struct list_head node; | 460 | struct list_head node; |
@@ -486,6 +487,7 @@ struct rproc { | |||
486 | bool has_iommu; | 487 | bool has_iommu; |
487 | bool auto_boot; | 488 | bool auto_boot; |
488 | struct list_head dump_segments; | 489 | struct list_head dump_segments; |
490 | int nb_vdev; | ||
489 | }; | 491 | }; |
490 | 492 | ||
491 | /** | 493 | /** |
@@ -513,7 +515,6 @@ struct rproc_subdev { | |||
513 | /** | 515 | /** |
514 | * struct rproc_vring - remoteproc vring state | 516 | * struct rproc_vring - remoteproc vring state |
515 | * @va: virtual address | 517 | * @va: virtual address |
516 | * @dma: dma address | ||
517 | * @len: length, in bytes | 518 | * @len: length, in bytes |
518 | * @da: device address | 519 | * @da: device address |
519 | * @align: vring alignment | 520 | * @align: vring alignment |
@@ -523,7 +524,6 @@ struct rproc_subdev { | |||
523 | */ | 524 | */ |
524 | struct rproc_vring { | 525 | struct rproc_vring { |
525 | void *va; | 526 | void *va; |
526 | dma_addr_t dma; | ||
527 | int len; | 527 | int len; |
528 | u32 da; | 528 | u32 da; |
529 | u32 align; | 529 | u32 align; |
@@ -542,6 +542,7 @@ struct rproc_vring { | |||
542 | * @vdev: the virio device | 542 | * @vdev: the virio device |
543 | * @vring: the vrings for this vdev | 543 | * @vring: the vrings for this vdev |
544 | * @rsc_offset: offset of the vdev's resource entry | 544 | * @rsc_offset: offset of the vdev's resource entry |
545 | * @index: vdev position versus other vdev declared in resource table | ||
545 | */ | 546 | */ |
546 | struct rproc_vdev { | 547 | struct rproc_vdev { |
547 | struct kref refcount; | 548 | struct kref refcount; |
@@ -554,6 +555,7 @@ struct rproc_vdev { | |||
554 | struct virtio_device vdev; | 555 | struct virtio_device vdev; |
555 | struct rproc_vring vring[RVDEV_NUM_VRINGS]; | 556 | struct rproc_vring vring[RVDEV_NUM_VRINGS]; |
556 | u32 rsc_offset; | 557 | u32 rsc_offset; |
558 | u32 index; | ||
557 | }; | 559 | }; |
558 | 560 | ||
559 | struct rproc *rproc_get_by_phandle(phandle phandle); | 561 | struct rproc *rproc_get_by_phandle(phandle phandle); |