aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2012-02-13 16:30:39 -0500
committerOhad Ben-Cohen <ohad@wizery.com>2012-03-06 12:14:12 -0500
commit7a186941626d19f668b08108db158379b32e6e02 (patch)
treed478210fa3ae45ef8b3eaf6a6432eadc49cbb55a
parent41a6ee09ee8dd7ac3a6ac12a24e26279b5d93385 (diff)
remoteproc: remove the single rpmsg vdev limitation
Now that the resource table supports publishing a virtio device in a single resource entry, firmware images can start supporting more than a single vdev. This patch removes the single vdev limitation of the remoteproc framework so multi-vdev firmwares can be leveraged: VDEV resource entries are parsed when the rproc is registered, and as a result their vrings are set up and the virtio devices are registered (and they go away when the rproc goes away). Moreover, we no longer only support VIRTIO_ID_RPMSG vdevs; any virtio device type goes now. As a result, there's no more any rpmsg-specific APIs or code in remoteproc: it all becomes generic virtio handling. Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com> Cc: Brian Swetland <swetland@google.com> Cc: Iliyan Malchev <malchev@google.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Mark Grosen <mgrosen@ti.com> Cc: John Williams <john.williams@petalogix.com> Cc: Michal Simek <monstr@monstr.eu> Cc: Loic PALLARDY <loic.pallardy@stericsson.com> Cc: Ludovic BARRE <ludovic.barre@stericsson.com> Cc: Omar Ramirez Luna <omar.luna@linaro.org> Cc: Guzman Lugo Fernando <fernando.lugo@ti.com> Cc: Anna Suman <s-anna@ti.com> Cc: Clark Rob <rob@ti.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Saravana Kannan <skannan@codeaurora.org> Cc: David Brown <davidb@codeaurora.org> Cc: Kieran Bingham <kieranbingham@gmail.com> Cc: Tony Lindgren <tony@atomide.com>
-rw-r--r--Documentation/remoteproc.txt9
-rw-r--r--drivers/remoteproc/remoteproc_core.c292
-rw-r--r--drivers/remoteproc/remoteproc_internal.h6
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c140
-rw-r--r--include/linux/remoteproc.h41
5 files changed, 260 insertions, 228 deletions
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 07057cacfeae..70a048cd3fa3 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -20,6 +20,11 @@ platform-specific remoteproc drivers only need to provide a few low-level
20handlers, and then all rpmsg drivers will then just work 20handlers, and then all rpmsg drivers will then just work
21(for more information about the virtio-based rpmsg bus and its drivers, 21(for more information about the virtio-based rpmsg bus and its drivers,
22please read Documentation/rpmsg.txt). 22please read Documentation/rpmsg.txt).
23Registration of other types of virtio devices is now also possible. Firmwares
24just need to publish what kind of virtio devices do they support, and then
25remoteproc will add those devices. This makes it possible to reuse the
26existing virtio drivers with remote processor backends at a minimal development
27cost.
23 28
242. User API 292. User API
25 30
@@ -136,8 +141,6 @@ int dummy_rproc_example(struct rproc *my_rproc)
136 If found, those virtio devices will be created and added, so as a result 141 If found, those virtio devices will be created and added, so as a result
137 of registering this remote processor, additional virtio drivers might get 142 of registering this remote processor, additional virtio drivers might get
138 probed. 143 probed.
139 Currently, though, we only support a single RPMSG virtio vdev per remote
140 processor.
141 144
142 int rproc_unregister(struct rproc *rproc) 145 int rproc_unregister(struct rproc *rproc)
143 - Unregister a remote processor, and decrement its refcount. 146 - Unregister a remote processor, and decrement its refcount.
@@ -174,7 +177,7 @@ struct rproc_ops {
174}; 177};
175 178
176Every remoteproc implementation should at least provide the ->start and ->stop 179Every remoteproc implementation should at least provide the ->start and ->stop
177handlers. If rpmsg functionality is also desired, then the ->kick handler 180handlers. If rpmsg/virtio functionality is also desired, then the ->kick handler
178should be provided as well. 181should be provided as well.
179 182
180The ->start() handler takes an rproc handle and should then power on the 183The ->start() handler takes an rproc handle and should then power on the
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 10348451c6c9..ca02f128b435 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -52,8 +52,8 @@ static void klist_rproc_put(struct klist_node *n);
52 * We need this in order to support name-based lookups (needed by the 52 * We need this in order to support name-based lookups (needed by the
53 * rproc_get_by_name()). 53 * rproc_get_by_name()).
54 * 54 *
55 * That said, we don't use rproc_get_by_name() anymore within the rpmsg 55 * That said, we don't use rproc_get_by_name() at this point.
56 * framework. The use cases that do require its existence should be 56 * The use cases that do require its existence should be
57 * scrutinized, and hopefully migrated to rproc_boot() using device-based 57 * scrutinized, and hopefully migrated to rproc_boot() using device-based
58 * binding. 58 * binding.
59 * 59 *
@@ -279,80 +279,112 @@ rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len)
279 return ret; 279 return ret;
280} 280}
281 281
282/** 282static int
283 * rproc_handle_early_vdev() - early handle a virtio header resource 283__rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
284 * @rproc: the remote processor
285 * @rsc: the resource descriptor
286 * @avail: size of available data (for sanity checking the image)
287 *
288 * The existence of this virtio hdr resource entry means that the firmware
289 * of this @rproc supports this virtio device.
290 *
291 * Currently we support only a single virtio device of type VIRTIO_ID_RPMSG,
292 * but the plan is to remove this limitation and support any number
293 * of virtio devices (and of any type). We'll also add support for dynamically
294 * adding (and removing) virtio devices over the rpmsg bus, but simple
295 * firmwares that doesn't want to get involved with rpmsg will be able
296 * to simply use the resource table for this.
297 *
298 * Returns 0 on success, or an appropriate error code otherwise
299 */
300static int rproc_handle_early_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
301 int avail)
302{ 284{
303 struct rproc_vdev *rvdev; 285 struct rproc *rproc = rvdev->rproc;
286 struct device *dev = rproc->dev;
287 struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
288 dma_addr_t dma;
289 void *va;
290 int ret, size, notifyid;
304 291
305 /* make sure resource isn't truncated */ 292 dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
306 if (sizeof(*rsc) > avail) { 293 i, vring->da, vring->num, vring->align);
307 dev_err(rproc->dev, "vdev rsc is truncated\n"); 294
295 /* make sure reserved bytes are zeroes */
296 if (vring->reserved) {
297 dev_err(dev, "vring rsc has non zero reserved bytes\n");
308 return -EINVAL; 298 return -EINVAL;
309 } 299 }
310 300
311 /* we only support VIRTIO_ID_RPMSG devices for now */ 301 /* the firmware must provide the expected queue size */
312 if (rsc->id != VIRTIO_ID_RPMSG) { 302 if (!vring->num) {
313 dev_warn(rproc->dev, "unsupported vdev: %d\n", rsc->id); 303 dev_err(dev, "invalid qsz (%d)\n", vring->num);
314 return -EINVAL; 304 return -EINVAL;
315 } 305 }
316 306
317 /* we only support a single vdev per rproc for now */ 307 /* actual size of vring (in bytes) */
318 if (rproc->rvdev) { 308 size = PAGE_ALIGN(vring_size(vring->num, AMP_VRING_ALIGN));
319 dev_warn(rproc->dev, "redundant vdev entry\n"); 309
310 if (!idr_pre_get(&rproc->notifyids, GFP_KERNEL)) {
311 dev_err(dev, "idr_pre_get failed\n");
312 return -ENOMEM;
313 }
314
315 /*
316 * Allocate non-cacheable memory for the vring. In the future
317 * this call will also configure the IOMMU for us
318 */
319 va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
320 if (!va) {
321 dev_err(dev, "dma_alloc_coherent failed\n");
320 return -EINVAL; 322 return -EINVAL;
321 } 323 }
322 324
323 rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL); 325 /* assign an rproc-wide unique index for this vring */
324 if (!rvdev) 326 /* TODO: assign a notifyid for rvdev updates as well */
325 return -ENOMEM; 327 ret = idr_get_new(&rproc->notifyids, &rvdev->vring[i], &notifyid);
328 if (ret) {
329 dev_err(dev, "idr_get_new failed: %d\n", ret);
330 dma_free_coherent(dev, size, va, dma);
331 return ret;
332 }
326 333
327 /* remember the device features */ 334 /* let the rproc know the da and notifyid of this vring */
328 rvdev->dfeatures = rsc->dfeatures; 335 /* TODO: expose this to remote processor */
336 vring->da = dma;
337 vring->notifyid = notifyid;
329 338
330 rproc->rvdev = rvdev; 339 dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
331 rvdev->rproc = rproc; 340 dma, size, notifyid);
341
342 rvdev->vring[i].len = vring->num;
343 rvdev->vring[i].va = va;
344 rvdev->vring[i].dma = dma;
345 rvdev->vring[i].notifyid = notifyid;
346 rvdev->vring[i].rvdev = rvdev;
332 347
333 return 0; 348 return 0;
334} 349}
335 350
351static void __rproc_free_vrings(struct rproc_vdev *rvdev, int i)
352{
353 struct rproc *rproc = rvdev->rproc;
354
355 for (i--; i > 0; i--) {
356 struct rproc_vring *rvring = &rvdev->vring[i];
357 int size = PAGE_ALIGN(vring_size(rvring->len, AMP_VRING_ALIGN));
358
359 dma_free_coherent(rproc->dev, size, rvring->va, rvring->dma);
360 idr_remove(&rproc->notifyids, rvring->notifyid);
361 }
362}
363
336/** 364/**
337 * rproc_handle_vdev() - handle a vdev fw resource 365 * rproc_handle_vdev() - handle a vdev fw resource
338 * @rproc: the remote processor 366 * @rproc: the remote processor
339 * @rsc: the vring resource descriptor 367 * @rsc: the vring resource descriptor
340 * @avail: size of available data (for sanity checking the image) 368 * @avail: size of available data (for sanity checking the image)
341 * 369 *
342 * This resource entry requires allocation of non-cacheable memory 370 * This resource entry requests the host to statically register a virtio
343 * for a virtio vring. Currently we only support two vrings per remote 371 * device (vdev), and setup everything needed to support it. It contains
344 * processor, required for the virtio rpmsg device. 372 * everything needed to make it possible: the virtio device id, virtio
345 * 373 * device features, vrings information, virtio config space, etc...
346 * The 'len' member of @rsc should contain the number of buffers this vring 374 *
347 * support and 'da' should either contain the device address where 375 * Before registering the vdev, the vrings are allocated from non-cacheable
348 * the remote processor is expecting the vring, or indicate that 376 * physically contiguous memory. Currently we only support two vrings per
349 * dynamically allocation of the vring's device address is supported. 377 * remote processor (temporary limitation). We might also want to consider
350 * 378 * doing the vring allocation only later when ->find_vqs() is invoked, and
351 * Note: 'da' is currently not handled. This will be revised when the generic 379 * then release them upon ->del_vqs().
352 * iommu-based DMA API will arrive, or a dynanic & non-iommu use case show 380 *
353 * up. Meanwhile, statically-addressed iommu-based images should use 381 * Note: @da is currently not really handled correctly: we dynamically
354 * RSC_DEVMEM resource entries to map their require 'da' to the physical 382 * allocate it using the DMA API, ignoring requested hard coded addresses,
355 * address of their base CMA region. 383 * and we don't take care of any required IOMMU programming. This is all
384 * going to be taken care of when the generic iommu-based DMA API will be
385 * merged. Meanwhile, statically-addressed iommu-based firmware images should
386 * use RSC_DEVMEM resource entries to map their required @da to the physical
387 * address of their base CMA region (ouch, hacky!).
356 * 388 *
357 * Returns 0 on success, or an appropriate error code otherwise 389 * Returns 0 on success, or an appropriate error code otherwise
358 */ 390 */
@@ -360,8 +392,8 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
360 int avail) 392 int avail)
361{ 393{
362 struct device *dev = rproc->dev; 394 struct device *dev = rproc->dev;
363 struct rproc_vdev *rvdev = rproc->rvdev; 395 struct rproc_vdev *rvdev;
364 int i; 396 int i, ret;
365 397
366 /* make sure resource isn't truncated */ 398 /* make sure resource isn't truncated */
367 if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring) 399 if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
@@ -379,61 +411,41 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
379 dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n", 411 dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
380 rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings); 412 rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
381 413
382 /* no vdev is in place ? */ 414 /* we currently support only two vrings per rvdev */
383 if (!rvdev) { 415 if (rsc->num_of_vrings > ARRAY_SIZE(rvdev->vring)) {
384 dev_err(dev, "vring requested without a virtio dev entry\n");
385 return -EINVAL;
386 }
387
388 /* we currently support two vrings per rproc (for rx and tx) */
389 if (rsc->num_of_vrings != ARRAY_SIZE(rvdev->vring)) {
390 dev_err(dev, "too many vrings: %d\n", rsc->num_of_vrings); 416 dev_err(dev, "too many vrings: %d\n", rsc->num_of_vrings);
391 return -EINVAL; 417 return -EINVAL;
392 } 418 }
393 419
394 /* initialize the vrings */ 420 rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL);
395 for (i = 0; i < rsc->num_of_vrings; i++) { 421 if (!rvdev)
396 struct fw_rsc_vdev_vring *vring = &rsc->vring[i]; 422 return -ENOMEM;
397 dma_addr_t dma;
398 int size;
399 void *va;
400
401 /* make sure reserved bytes are zeroes */
402 if (vring->reserved) {
403 dev_err(dev, "vring rsc has non zero reserved bytes\n");
404 return -EINVAL;
405 }
406 423
407 /* the firmware must provide the expected queue size */ 424 rvdev->rproc = rproc;
408 if (!vring->num) {
409 dev_err(dev, "missing expected queue size\n");
410 /* potential cleanups are taken care of later on */
411 return -EINVAL;
412 }
413 425
414 /* actual size of vring (in bytes) */ 426 /* allocate the vrings */
415 size = PAGE_ALIGN(vring_size(vring->num, AMP_VRING_ALIGN)); 427 for (i = 0; i < rsc->num_of_vrings; i++) {
428 ret = __rproc_handle_vring(rvdev, rsc, i);
429 if (ret)
430 goto free_vrings;
431 }
416 432
417 /* 433 /* remember the device features */
418 * Allocate non-cacheable memory for the vring. In the future 434 rvdev->dfeatures = rsc->dfeatures;
419 * this call will also configure the IOMMU for us
420 */
421 va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
422 if (!va) {
423 dev_err(dev, "dma_alloc_coherent failed\n");
424 /* potential cleanups are taken care of later on */
425 return -EINVAL;
426 }
427 435
428 dev_dbg(dev, "vring%d: va %p dma %x qsz %d ring size %x\n", i, 436 list_add_tail(&rvdev->node, &rproc->rvdevs);
429 va, dma, vring->num, size);
430 437
431 rvdev->vring[i].len = vring->num; 438 /* it is now safe to add the virtio device */
432 rvdev->vring[i].va = va; 439 ret = rproc_add_virtio_dev(rvdev, rsc->id);
433 rvdev->vring[i].dma = dma; 440 if (ret)
434 } 441 goto free_vrings;
435 442
436 return 0; 443 return 0;
444
445free_vrings:
446 __rproc_free_vrings(rvdev, i);
447 kfree(rvdev);
448 return ret;
437} 449}
438 450
439/** 451/**
@@ -731,7 +743,7 @@ static rproc_handle_resource_t rproc_handle_rsc[] = {
731 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, 743 [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
732 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, 744 [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
733 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, 745 [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
734 [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, 746 [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
735}; 747};
736 748
737/* handle firmware resource entries before booting the remote processor */ 749/* handle firmware resource entries before booting the remote processor */
@@ -784,6 +796,7 @@ rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int l
784 int offset = table->offset[i]; 796 int offset = table->offset[i];
785 struct fw_rsc_hdr *hdr = (void *)table + offset; 797 struct fw_rsc_hdr *hdr = (void *)table + offset;
786 int avail = len - offset - sizeof(*hdr); 798 int avail = len - offset - sizeof(*hdr);
799 struct fw_rsc_vdev *vrsc;
787 800
788 /* make sure table isn't truncated */ 801 /* make sure table isn't truncated */
789 if (avail < 0) { 802 if (avail < 0) {
@@ -793,12 +806,14 @@ rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int l
793 806
794 dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type); 807 dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
795 808
796 if (hdr->type == RSC_VDEV) { 809 if (hdr->type != RSC_VDEV)
797 struct fw_rsc_vdev *vrsc = 810 continue;
798 (struct fw_rsc_vdev *)hdr->data; 811
799 ret = rproc_handle_early_vdev(rproc, vrsc, avail); 812 vrsc = (struct fw_rsc_vdev *)hdr->data;
813
814 ret = rproc_handle_vdev(rproc, vrsc, avail);
815 if (ret)
800 break; 816 break;
801 }
802 } 817 }
803 818
804 return ret; 819 return ret;
@@ -889,14 +904,12 @@ static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data,
889 * @rproc: rproc handle 904 * @rproc: rproc handle
890 * 905 *
891 * This function will free all resources acquired for @rproc, and it 906 * This function will free all resources acquired for @rproc, and it
892 * is called when @rproc shuts down, or just failed booting. 907 * is called whenever @rproc either shuts down or fails to boot.
893 */ 908 */
894static void rproc_resource_cleanup(struct rproc *rproc) 909static void rproc_resource_cleanup(struct rproc *rproc)
895{ 910{
896 struct rproc_mem_entry *entry, *tmp; 911 struct rproc_mem_entry *entry, *tmp;
897 struct device *dev = rproc->dev; 912 struct device *dev = rproc->dev;
898 struct rproc_vdev *rvdev = rproc->rvdev;
899 int i;
900 913
901 /* clean up debugfs trace entries */ 914 /* clean up debugfs trace entries */
902 list_for_each_entry_safe(entry, tmp, &rproc->traces, node) { 915 list_for_each_entry_safe(entry, tmp, &rproc->traces, node) {
@@ -906,23 +919,6 @@ static void rproc_resource_cleanup(struct rproc *rproc)
906 kfree(entry); 919 kfree(entry);
907 } 920 }
908 921
909 /* free the coherent memory allocated for the vrings */
910 for (i = 0; rvdev && i < ARRAY_SIZE(rvdev->vring); i++) {
911 int qsz = rvdev->vring[i].len;
912 void *va = rvdev->vring[i].va;
913 int dma = rvdev->vring[i].dma;
914
915 /* virtqueue size is expressed in number of buffers supported */
916 if (qsz) {
917 /* how many bytes does this vring really occupy ? */
918 int size = PAGE_ALIGN(vring_size(qsz, AMP_VRING_ALIGN));
919
920 dma_free_coherent(rproc->dev, size, va, dma);
921
922 rvdev->vring[i].len = 0;
923 }
924 }
925
926 /* clean up carveout allocations */ 922 /* clean up carveout allocations */
927 list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { 923 list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
928 dma_free_coherent(dev, entry->len, entry->va, entry->dma); 924 dma_free_coherent(dev, entry->len, entry->va, entry->dma);
@@ -1100,11 +1096,6 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
1100 goto out; 1096 goto out;
1101 } 1097 }
1102 1098
1103 /* add the virtio device (currently only rpmsg vdevs are supported) */
1104 ret = rproc_add_rpmsg_vdev(rproc);
1105 if (ret)
1106 goto out;
1107
1108out: 1099out:
1109 if (fw) 1100 if (fw)
1110 release_firmware(fw); 1101 release_firmware(fw);
@@ -1266,13 +1257,23 @@ EXPORT_SYMBOL(rproc_shutdown);
1266void rproc_release(struct kref *kref) 1257void rproc_release(struct kref *kref)
1267{ 1258{
1268 struct rproc *rproc = container_of(kref, struct rproc, refcount); 1259 struct rproc *rproc = container_of(kref, struct rproc, refcount);
1260 struct rproc_vdev *rvdev, *rvtmp;
1269 1261
1270 dev_info(rproc->dev, "removing %s\n", rproc->name); 1262 dev_info(rproc->dev, "removing %s\n", rproc->name);
1271 1263
1272 rproc_delete_debug_dir(rproc); 1264 rproc_delete_debug_dir(rproc);
1273 1265
1274 /* at this point no one holds a reference to rproc anymore */ 1266 /* clean up remote vdev entries */
1275 kfree(rproc); 1267 list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) {
1268 __rproc_free_vrings(rvdev, RVDEV_NUM_VRINGS);
1269 list_del(&rvdev->node);
1270 }
1271
1272 /*
1273 * At this point no one holds a reference to rproc anymore,
1274 * so we can directly unroll rproc_alloc()
1275 */
1276 rproc_free(rproc);
1276} 1277}
1277 1278
1278/* will be called when an rproc is added to the rprocs klist */ 1279/* will be called when an rproc is added to the rprocs klist */
@@ -1316,7 +1317,7 @@ static struct rproc *next_rproc(struct klist_iter *i)
1316 * use rproc_put() to decrement it back once rproc isn't needed anymore. 1317 * use rproc_put() to decrement it back once rproc isn't needed anymore.
1317 * 1318 *
1318 * Note: currently this function (and its counterpart rproc_put()) are not 1319 * Note: currently this function (and its counterpart rproc_put()) are not
1319 * used anymore by the rpmsg subsystem. We need to scrutinize the use cases 1320 * being used. We need to scrutinize the use cases
1320 * that still need them, and see if we can migrate them to use the non 1321 * that still need them, and see if we can migrate them to use the non
1321 * name-based boot/shutdown interface. 1322 * name-based boot/shutdown interface.
1322 */ 1323 */
@@ -1391,11 +1392,8 @@ EXPORT_SYMBOL(rproc_put);
1391 * firmware. 1392 * firmware.
1392 * 1393 *
1393 * If found, those virtio devices will be created and added, so as a result 1394 * If found, those virtio devices will be created and added, so as a result
1394 * of registering this remote processor, additional virtio drivers will be 1395 * of registering this remote processor, additional virtio drivers might be
1395 * probed. 1396 * probed.
1396 *
1397 * Currently, though, we only support a single RPMSG virtio vdev per remote
1398 * processor.
1399 */ 1397 */
1400int rproc_register(struct rproc *rproc) 1398int rproc_register(struct rproc *rproc)
1401{ 1399{
@@ -1418,7 +1416,7 @@ int rproc_register(struct rproc *rproc)
1418 1416
1419 /* 1417 /*
1420 * We must retrieve early virtio configuration info from 1418 * We must retrieve early virtio configuration info from
1421 * the firmware (e.g. whether to register a virtio rpmsg device, 1419 * the firmware (e.g. whether to register a virtio device,
1422 * what virtio features does it support, ...). 1420 * what virtio features does it support, ...).
1423 * 1421 *
1424 * We're initiating an asynchronous firmware loading, so we can 1422 * We're initiating an asynchronous firmware loading, so we can
@@ -1487,9 +1485,12 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1487 1485
1488 mutex_init(&rproc->lock); 1486 mutex_init(&rproc->lock);
1489 1487
1488 idr_init(&rproc->notifyids);
1489
1490 INIT_LIST_HEAD(&rproc->carveouts); 1490 INIT_LIST_HEAD(&rproc->carveouts);
1491 INIT_LIST_HEAD(&rproc->mappings); 1491 INIT_LIST_HEAD(&rproc->mappings);
1492 INIT_LIST_HEAD(&rproc->traces); 1492 INIT_LIST_HEAD(&rproc->traces);
1493 INIT_LIST_HEAD(&rproc->rvdevs);
1493 1494
1494 rproc->state = RPROC_OFFLINE; 1495 rproc->state = RPROC_OFFLINE;
1495 1496
@@ -1509,6 +1510,9 @@ EXPORT_SYMBOL(rproc_alloc);
1509 */ 1510 */
1510void rproc_free(struct rproc *rproc) 1511void rproc_free(struct rproc *rproc)
1511{ 1512{
1513 idr_remove_all(&rproc->notifyids);
1514 idr_destroy(&rproc->notifyids);
1515
1512 kfree(rproc); 1516 kfree(rproc);
1513} 1517}
1514EXPORT_SYMBOL(rproc_free); 1518EXPORT_SYMBOL(rproc_free);
@@ -1535,18 +1539,22 @@ EXPORT_SYMBOL(rproc_free);
1535 */ 1539 */
1536int rproc_unregister(struct rproc *rproc) 1540int rproc_unregister(struct rproc *rproc)
1537{ 1541{
1542 struct rproc_vdev *rvdev;
1543
1538 if (!rproc) 1544 if (!rproc)
1539 return -EINVAL; 1545 return -EINVAL;
1540 1546
1541 /* if rproc is just being registered, wait */ 1547 /* if rproc is just being registered, wait */
1542 wait_for_completion(&rproc->firmware_loading_complete); 1548 wait_for_completion(&rproc->firmware_loading_complete);
1543 1549
1544 /* was an rpmsg vdev created ? */ 1550 /* clean up remote vdev entries */
1545 if (rproc->rvdev) 1551 list_for_each_entry(rvdev, &rproc->rvdevs, node)
1546 rproc_remove_rpmsg_vdev(rproc); 1552 rproc_remove_virtio_dev(rvdev);
1547 1553
1548 klist_remove(&rproc->node); 1554 /* the rproc is downref'ed as soon as it's removed from the klist */
1555 klist_del(&rproc->node);
1549 1556
1557 /* the rproc will only be released after its refcount drops to zero */
1550 kref_put(&rproc->refcount, rproc_release); 1558 kref_put(&rproc->refcount, rproc_release);
1551 1559
1552 return 0; 1560 return 0;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 8b2fc40e92d0..9f336d6bdef3 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -28,9 +28,9 @@ struct rproc;
28void rproc_release(struct kref *kref); 28void rproc_release(struct kref *kref);
29irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id); 29irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
30 30
31/* from remoteproc_rpmsg.c */ 31/* from remoteproc_virtio.c */
32int rproc_add_rpmsg_vdev(struct rproc *); 32int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id);
33void rproc_remove_rpmsg_vdev(struct rproc *rproc); 33void rproc_remove_virtio_dev(struct rproc_vdev *rvdev);
34 34
35/* from remoteproc_debugfs.c */ 35/* from remoteproc_debugfs.c */
36void rproc_remove_trace_file(struct dentry *tfile); 36void rproc_remove_trace_file(struct dentry *tfile);
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 78d8527a8fec..07004106c954 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -19,7 +19,6 @@
19 19
20#include <linux/export.h> 20#include <linux/export.h>
21#include <linux/remoteproc.h> 21#include <linux/remoteproc.h>
22#include <linux/rpmsg.h>
23#include <linux/virtio.h> 22#include <linux/virtio.h>
24#include <linux/virtio_config.h> 23#include <linux/virtio_config.h>
25#include <linux/virtio_ids.h> 24#include <linux/virtio_ids.h>
@@ -30,45 +29,41 @@
30 29
31#include "remoteproc_internal.h" 30#include "remoteproc_internal.h"
32 31
33/**
34 * struct rproc_virtio_vq_info - virtqueue state
35 * @vq_id: a unique index of this virtqueue (unique for this @rproc)
36 * @rproc: handle to the remote processor
37 *
38 * Such a struct will be maintained for every virtqueue we're
39 * using to communicate with the remote processor
40 */
41struct rproc_virtio_vq_info {
42 __u16 vq_id;
43 struct rproc *rproc;
44};
45
46/* kick the remote processor, and let it know which virtqueue to poke at */ 32/* kick the remote processor, and let it know which virtqueue to poke at */
47static void rproc_virtio_notify(struct virtqueue *vq) 33static void rproc_virtio_notify(struct virtqueue *vq)
48{ 34{
49 struct rproc_virtio_vq_info *rpvq = vq->priv; 35 struct rproc_vring *rvring = vq->priv;
50 struct rproc *rproc = rpvq->rproc; 36 struct rproc *rproc = rvring->rvdev->rproc;
37 int notifyid = rvring->notifyid;
51 38
52 dev_dbg(rproc->dev, "kicking vq id: %d\n", rpvq->vq_id); 39 dev_dbg(rproc->dev, "kicking vq index: %d\n", notifyid);
53 40
54 rproc->ops->kick(rproc, rpvq->vq_id); 41 rproc->ops->kick(rproc, notifyid);
55} 42}
56 43
57/** 44/**
58 * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted 45 * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
59 * @rproc: handle to the remote processor 46 * @rproc: handle to the remote processor
60 * @vq_id: index of the signalled virtqueue 47 * @notifyid: index of the signalled virtqueue (unique per this @rproc)
61 * 48 *
62 * This function should be called by the platform-specific rproc driver, 49 * This function should be called by the platform-specific rproc driver,
63 * when the remote processor signals that a specific virtqueue has pending 50 * when the remote processor signals that a specific virtqueue has pending
64 * messages available. 51 * messages available.
65 * 52 *
66 * Returns IRQ_NONE if no message was found in the @vq_id virtqueue, 53 * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
67 * and otherwise returns IRQ_HANDLED. 54 * and otherwise returns IRQ_HANDLED.
68 */ 55 */
69irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id) 56irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
70{ 57{
71 return vring_interrupt(0, rproc->rvdev->vq[vq_id]); 58 struct rproc_vring *rvring;
59
60 dev_dbg(rproc->dev, "vq index %d is interrupted\n", notifyid);
61
62 rvring = idr_find(&rproc->notifyids, notifyid);
63 if (!rvring || !rvring->vq)
64 return IRQ_NONE;
65
66 return vring_interrupt(0, rvring->vq);
72} 67}
73EXPORT_SYMBOL(rproc_vq_interrupt); 68EXPORT_SYMBOL(rproc_vq_interrupt);
74 69
@@ -77,24 +72,28 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
77 void (*callback)(struct virtqueue *vq), 72 void (*callback)(struct virtqueue *vq),
78 const char *name) 73 const char *name)
79{ 74{
75 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
80 struct rproc *rproc = vdev_to_rproc(vdev); 76 struct rproc *rproc = vdev_to_rproc(vdev);
81 struct rproc_vdev *rvdev = rproc->rvdev; 77 struct rproc_vring *rvring;
82 struct rproc_virtio_vq_info *rpvq;
83 struct virtqueue *vq; 78 struct virtqueue *vq;
84 void *addr; 79 void *addr;
85 int ret, len; 80 int len, size;
86 81
87 rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); 82 /* we're temporarily limited to two virtqueues per rvdev */
88 if (!rpvq) 83 if (id >= ARRAY_SIZE(rvdev->vring))
89 return ERR_PTR(-ENOMEM); 84 return ERR_PTR(-EINVAL);
85
86 rvring = &rvdev->vring[id];
90 87
91 rpvq->rproc = rproc; 88 addr = rvring->va;
92 rpvq->vq_id = id; 89 len = rvring->len;
93 90
94 addr = rvdev->vring[id].va; 91 /* zero vring */
95 len = rvdev->vring[id].len; 92 size = vring_size(len, rvring->align);
93 memset(addr, 0, size);
96 94
97 dev_dbg(rproc->dev, "vring%d: va %p qsz %d\n", id, addr, len); 95 dev_dbg(rproc->dev, "vring%d: va %p qsz %d notifyid %d\n",
96 id, addr, len, rvring->notifyid);
98 97
99 /* 98 /*
100 * Create the new vq, and tell virtio we're not interested in 99 * Create the new vq, and tell virtio we're not interested in
@@ -104,32 +103,28 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
104 rproc_virtio_notify, callback, name); 103 rproc_virtio_notify, callback, name);
105 if (!vq) { 104 if (!vq) {
106 dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name); 105 dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name);
107 ret = -ENOMEM; 106 return ERR_PTR(-ENOMEM);
108 goto free_rpvq;
109 } 107 }
110 108
111 rvdev->vq[id] = vq; 109 rvring->vq = vq;
112 vq->priv = rpvq; 110 vq->priv = rvring;
113 111
114 return vq; 112 return vq;
115
116free_rpvq:
117 kfree(rpvq);
118 return ERR_PTR(ret);
119} 113}
120 114
121static void rproc_virtio_del_vqs(struct virtio_device *vdev) 115static void rproc_virtio_del_vqs(struct virtio_device *vdev)
122{ 116{
123 struct virtqueue *vq, *n; 117 struct virtqueue *vq, *n;
124 struct rproc *rproc = vdev_to_rproc(vdev); 118 struct rproc *rproc = vdev_to_rproc(vdev);
119 struct rproc_vring *rvring;
125 120
126 /* power down the remote processor before deleting vqs */ 121 /* power down the remote processor before deleting vqs */
127 rproc_shutdown(rproc); 122 rproc_shutdown(rproc);
128 123
129 list_for_each_entry_safe(vq, n, &vdev->vqs, list) { 124 list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
130 struct rproc_virtio_vq_info *rpvq = vq->priv; 125 rvring = vq->priv;
126 rvring->vq = NULL;
131 vring_del_virtqueue(vq); 127 vring_del_virtqueue(vq);
132 kfree(rpvq);
133 } 128 }
134} 129}
135 130
@@ -141,10 +136,6 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
141 struct rproc *rproc = vdev_to_rproc(vdev); 136 struct rproc *rproc = vdev_to_rproc(vdev);
142 int i, ret; 137 int i, ret;
143 138
144 /* we maintain two virtqueues per remote processor (for RX and TX) */
145 if (nvqs != 2)
146 return -EINVAL;
147
148 for (i = 0; i < nvqs; ++i) { 139 for (i = 0; i < nvqs; ++i) {
149 vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); 140 vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
150 if (IS_ERR(vqs[i])) { 141 if (IS_ERR(vqs[i])) {
@@ -170,7 +161,7 @@ error:
170/* 161/*
171 * We don't support yet real virtio status semantics. 162 * We don't support yet real virtio status semantics.
172 * 163 *
173 * The plan is to provide this via the VIRTIO HDR resource entry 164 * The plan is to provide this via the VDEV resource entry
174 * which is part of the firmware: this way the remote processor 165 * which is part of the firmware: this way the remote processor
175 * will be able to access the status values as set by us. 166 * will be able to access the status values as set by us.
176 */ 167 */
@@ -181,7 +172,7 @@ static u8 rproc_virtio_get_status(struct virtio_device *vdev)
181 172
182static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status) 173static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
183{ 174{
184 dev_dbg(&vdev->dev, "new status: %d\n", status); 175 dev_dbg(&vdev->dev, "status: %d\n", status);
185} 176}
186 177
187static void rproc_virtio_reset(struct virtio_device *vdev) 178static void rproc_virtio_reset(struct virtio_device *vdev)
@@ -192,15 +183,14 @@ static void rproc_virtio_reset(struct virtio_device *vdev)
192/* provide the vdev features as retrieved from the firmware */ 183/* provide the vdev features as retrieved from the firmware */
193static u32 rproc_virtio_get_features(struct virtio_device *vdev) 184static u32 rproc_virtio_get_features(struct virtio_device *vdev)
194{ 185{
195 struct rproc *rproc = vdev_to_rproc(vdev); 186 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
196 187
197 /* we only support a single vdev device for now */ 188 return rvdev->dfeatures;
198 return rproc->rvdev->dfeatures;
199} 189}
200 190
201static void rproc_virtio_finalize_features(struct virtio_device *vdev) 191static void rproc_virtio_finalize_features(struct virtio_device *vdev)
202{ 192{
203 struct rproc *rproc = vdev_to_rproc(vdev); 193 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
204 194
205 /* Give virtio_ring a chance to accept features */ 195 /* Give virtio_ring a chance to accept features */
206 vring_transport_features(vdev); 196 vring_transport_features(vdev);
@@ -214,7 +204,7 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev)
214 * fixed as part of a small resource table overhaul and then an 204 * fixed as part of a small resource table overhaul and then an
215 * extension of the virtio resource entries. 205 * extension of the virtio resource entries.
216 */ 206 */
217 rproc->rvdev->gfeatures = vdev->features[0]; 207 rvdev->gfeatures = vdev->features[0];
218} 208}
219 209
220static struct virtio_config_ops rproc_virtio_config_ops = { 210static struct virtio_config_ops rproc_virtio_config_ops = {
@@ -244,26 +234,25 @@ static void rproc_vdev_release(struct device *dev)
244} 234}
245 235
246/** 236/**
247 * rproc_add_rpmsg_vdev() - create an rpmsg virtio device 237 * rproc_add_virtio_dev() - register an rproc-induced virtio device
248 * @rproc: the rproc handle 238 * @rvdev: the remote vdev
249 * 239 *
250 * This function is called if virtio rpmsg support was found in the 240 * This function registers a virtio device. This vdev's partent is
251 * firmware of the remote processor. 241 * the rproc device.
252 * 242 *
253 * Today we only support creating a single rpmsg vdev (virtio device), 243 * Returns 0 on success or an appropriate error value otherwise.
254 * but the plan is to remove this limitation. At that point this interface
255 * will be revised/extended.
256 */ 244 */
257int rproc_add_rpmsg_vdev(struct rproc *rproc) 245int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
258{ 246{
247 struct rproc *rproc = rvdev->rproc;
259 struct device *dev = rproc->dev; 248 struct device *dev = rproc->dev;
260 struct rproc_vdev *rvdev = rproc->rvdev; 249 struct virtio_device *vdev = &rvdev->vdev;
261 int ret; 250 int ret;
262 251
263 rvdev->vdev.id.device = VIRTIO_ID_RPMSG, 252 vdev->id.device = id,
264 rvdev->vdev.config = &rproc_virtio_config_ops, 253 vdev->config = &rproc_virtio_config_ops,
265 rvdev->vdev.dev.parent = dev; 254 vdev->dev.parent = dev;
266 rvdev->vdev.dev.release = rproc_vdev_release; 255 vdev->dev.release = rproc_vdev_release;
267 256
268 /* 257 /*
269 * We're indirectly making a non-temporary copy of the rproc pointer 258 * We're indirectly making a non-temporary copy of the rproc pointer
@@ -275,25 +264,26 @@ int rproc_add_rpmsg_vdev(struct rproc *rproc)
275 */ 264 */
276 kref_get(&rproc->refcount); 265 kref_get(&rproc->refcount);
277 266
278 ret = register_virtio_device(&rvdev->vdev); 267 ret = register_virtio_device(vdev);
279 if (ret) { 268 if (ret) {
280 kref_put(&rproc->refcount, rproc_release); 269 kref_put(&rproc->refcount, rproc_release);
281 dev_err(dev, "failed to register vdev: %d\n", ret); 270 dev_err(dev, "failed to register vdev: %d\n", ret);
271 goto out;
282 } 272 }
283 273
274 dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
275
276out:
284 return ret; 277 return ret;
285} 278}
286 279
287/** 280/**
288 * rproc_remove_rpmsg_vdev() - remove an rpmsg vdev device 281 * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
289 * @rproc: the rproc handle 282 * @rvdev: the remote vdev
290 * 283 *
291 * This function is called whenever @rproc is removed _iff_ an rpmsg 284 * This function unregisters an existing virtio device.
292 * vdev was created beforehand.
293 */ 285 */
294void rproc_remove_rpmsg_vdev(struct rproc *rproc) 286void rproc_remove_virtio_dev(struct rproc_vdev *rvdev)
295{ 287{
296 struct rproc_vdev *rvdev = rproc->rvdev;
297
298 unregister_virtio_device(&rvdev->vdev); 288 unregister_virtio_device(&rvdev->vdev);
299} 289}
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 6040f831f626..7750d8a30933 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -41,6 +41,7 @@
41#include <linux/mutex.h> 41#include <linux/mutex.h>
42#include <linux/virtio.h> 42#include <linux/virtio.h>
43#include <linux/completion.h> 43#include <linux/completion.h>
44#include <linux/idr.h>
44 45
45/* 46/*
46 * The alignment between the consumer and producer parts of the vring. 47 * The alignment between the consumer and producer parts of the vring.
@@ -387,7 +388,8 @@ enum rproc_state {
387 * @mappings: list of iommu mappings we initiated, needed on shutdown 388 * @mappings: list of iommu mappings we initiated, needed on shutdown
388 * @firmware_loading_complete: marks e/o asynchronous firmware loading 389 * @firmware_loading_complete: marks e/o asynchronous firmware loading
389 * @bootaddr: address of first instruction to boot rproc with (optional) 390 * @bootaddr: address of first instruction to boot rproc with (optional)
390 * @rvdev: virtio device (we only support a single rpmsg virtio device for now) 391 * @rvdevs: list of remote virtio devices
392 * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
391 */ 393 */
392struct rproc { 394struct rproc {
393 struct klist_node node; 395 struct klist_node node;
@@ -408,23 +410,47 @@ struct rproc {
408 struct list_head mappings; 410 struct list_head mappings;
409 struct completion firmware_loading_complete; 411 struct completion firmware_loading_complete;
410 u32 bootaddr; 412 u32 bootaddr;
413 struct list_head rvdevs;
414 struct idr notifyids;
415};
416
417/* we currently support only two vrings per rvdev */
418#define RVDEV_NUM_VRINGS 2
419
420/**
421 * struct rproc_vring - remoteproc vring state
422 * @va: virtual address
423 * @dma: dma address
424 * @len: length, in bytes
425 * @da: device address
426 * @notifyid: rproc-specific unique vring index
427 * @rvdev: remote vdev
428 * @vq: the virtqueue of this vring
429 */
430struct rproc_vring {
431 void *va;
432 dma_addr_t dma;
433 int len;
434 u32 da;
435 int notifyid;
411 struct rproc_vdev *rvdev; 436 struct rproc_vdev *rvdev;
437 struct virtqueue *vq;
412}; 438};
413 439
414/** 440/**
415 * struct rproc_vdev - remoteproc state for a supported virtio device 441 * struct rproc_vdev - remoteproc state for a supported virtio device
442 * @node: list node
416 * @rproc: the rproc handle 443 * @rproc: the rproc handle
417 * @vdev: the virio device 444 * @vdev: the virio device
418 * @vq: the virtqueues for this vdev
419 * @vring: the vrings for this vdev 445 * @vring: the vrings for this vdev
420 * @dfeatures: virtio device features 446 * @dfeatures: virtio device features
421 * @gfeatures: virtio guest features 447 * @gfeatures: virtio guest features
422 */ 448 */
423struct rproc_vdev { 449struct rproc_vdev {
450 struct list_head node;
424 struct rproc *rproc; 451 struct rproc *rproc;
425 struct virtio_device vdev; 452 struct virtio_device vdev;
426 struct virtqueue *vq[2]; 453 struct rproc_vring vring[RVDEV_NUM_VRINGS];
427 struct rproc_mem_entry vring[2];
428 unsigned long dfeatures; 454 unsigned long dfeatures;
429 unsigned long gfeatures; 455 unsigned long gfeatures;
430}; 456};
@@ -442,9 +468,14 @@ int rproc_unregister(struct rproc *rproc);
442int rproc_boot(struct rproc *rproc); 468int rproc_boot(struct rproc *rproc);
443void rproc_shutdown(struct rproc *rproc); 469void rproc_shutdown(struct rproc *rproc);
444 470
471static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
472{
473 return container_of(vdev, struct rproc_vdev, vdev);
474}
475
445static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) 476static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
446{ 477{
447 struct rproc_vdev *rvdev = container_of(vdev, struct rproc_vdev, vdev); 478 struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
448 479
449 return rvdev->rproc; 480 return rvdev->rproc;
450} 481}