From: Erwan YVIN <erwan.y...@stericsson.com>

Refactor code for creating virtio queues and prepare
for accommodating the new host virtio rings.

This refactoring moves all handing of struct virtqueue
to a separate function __create_new_virtqueue().
A more generic function __rproc_virtio_find_rings()
allocates the virtio rings and ring IDs and calls the
virtqueue specific function when a virtio ring and the
ring IDs are allocated. Some type safety is sacrificed,
in order to make the code more generic.

Signed-off-by: Erwan Yvin <erwan.y...@stericsson.com>
---
 drivers/remoteproc/remoteproc_virtio.c |  138 +++++++++++++++++++-------------
 1 file changed, 82 insertions(+), 56 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..ef5ec8a 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -67,50 +67,93 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int 
notifyid)
 }
 EXPORT_SYMBOL(rproc_vq_interrupt);
 
-static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
-                                   unsigned id,
-                                   void (*callback)(struct virtqueue *vq),
-                                   const char *name)
+/*
+ * Allocate and intitialize the virtio rings. We downcast some types here
+ * in order to have common code between virtqueue and vringh.
+ */
+static int __rproc_virtio_find_rings(struct virtio_device *vdev,
+                                       unsigned nrings, void *rings[],
+                                       void *callbacks[], const char *name[],
+                                       void *create(struct rproc_vring *rvring,
+                                                       unsigned int index,
+                                                       void *callbacks,
+                                                       const char *name))
 {
        struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
        struct rproc *rproc = vdev_to_rproc(vdev);
        struct device *dev = &rproc->dev;
        struct rproc_vring *rvring;
-       struct virtqueue *vq;
-       void *addr;
-       int len, size, ret;
+       /* Use resource entry fw_rsc_vdev.num_of_rings instead when available */
+       size_t max = ARRAY_SIZE(rvdev->vring);
+       const char *rng_name;
+       int rng, id, err;
 
        /* we're temporarily limited to two virtqueues per rvdev */
-       if (id >= ARRAY_SIZE(rvdev->vring))
-               return ERR_PTR(-EINVAL);
+       if (nrings > max)
+               return -EINVAL;
 
-       if (!name)
-               return NULL;
+       /*
+        * We have two different arrays here:
+        * rvdev->vring[] holds the virtio rings in shared memory as
+        * specified by the resource table. It uses "rng" as index.
+        *
+        * The parameter rings[] is used for passing the requested
+        * virtio rings back to the caller. nrings is used by the
+        * caller to specify the number of rings to return.
+        */
+       for (id = rng = 0; id < nrings && rng < max; ++rng) {
+               rvring = &rvdev->vring[rng];
+               if (rvring->vq)
+                       continue;
+
+               /* Allocate and initialize the virtio ring */
+               err = rproc_alloc_vring(rvdev, rng);
+               if (err)
+                       return err;
+
+               memset(rvring->va, 0, vring_size(rvring->len, rvring->align));
+               rng_name = name ? name[id] : NULL;
+               rings[id] = create(rvring, id, callbacks[id], rng_name);
+               if (IS_ERR(rings[id])) {
+                       rproc_free_vring(rvring);
+                       return PTR_ERR(rings[id]);
+               }
 
-       ret = rproc_alloc_vring(rvdev, id);
-       if (ret)
-               return ERR_PTR(ret);
+               dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n",
+                       rng, rvring->va, rvring->len, rvring->notifyid);
+               ++id;
+       }
 
-       rvring = &rvdev->vring[id];
-       addr = rvring->va;
-       len = rvring->len;
+       if (id < nrings) {
+               dev_err(dev, "couldn't find the requested rings: %d\n", nrings);
+               return -ENOBUFS;
+       }
 
-       /* zero vring */
-       size = vring_size(len, rvring->align);
-       memset(addr, 0, size);
+       /* now that the rings are all set, boot the remote processor */
+       return rproc_boot(rproc);
+}
 
-       dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n",
-                                       id, addr, len, rvring->notifyid);
+/* Helper function that creates and initializes the virtqueue */
+static void *__create_new_virtqueue(struct rproc_vring *rvring,
+                                       unsigned int id,
+                                       void *callback,
+                                       const char *name)
+{
+       struct virtio_device *vdev = &rvring->rvdev->vdev;
+       struct virtqueue *vq;
+
+       if (!name)
+               return ERR_PTR(-EINVAL);
 
        /*
         * Create the new vq, and tell virtio we're not interested in
         * the 'weak' smp barriers, since we're talking with a real device.
         */
-       vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr,
-                                       rproc_virtio_notify, callback, name);
+       vq = vring_new_virtqueue(id, rvring->len, rvring->align, vdev, false,
+                                rvring->va, rproc_virtio_notify, callback,
+                                name);
        if (!vq) {
-               dev_err(dev, "vring_new_virtqueue %s failed\n", name);
-               rproc_free_vring(rvring);
+               dev_err(&vdev->dev, "vring_new_virtqueue %s failed\n", name);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -133,44 +176,27 @@ static void __rproc_virtio_del_vqs(struct virtio_device 
*vdev)
        }
 }
 
-static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                                       struct virtqueue *vqs[],
+                                       vq_callback_t *callbacks[],
+                                       const char *names[])
 {
-       struct rproc *rproc = vdev_to_rproc(vdev);
-
-       /* power down the remote processor before deleting vqs */
-       rproc_shutdown(rproc);
-
-       __rproc_virtio_del_vqs(vdev);
+       void *cbs = callbacks, *rings = vqs;
+       int err = __rproc_virtio_find_rings(vdev, nvqs, rings, cbs,
+                                               names, __create_new_virtqueue);
+       if (err)
+               __rproc_virtio_del_vqs(vdev);
+       return err;
 }
 
-static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                      struct virtqueue *vqs[],
-                      vq_callback_t *callbacks[],
-                      const char *names[])
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
 {
        struct rproc *rproc = vdev_to_rproc(vdev);
-       int i, ret;
 
-       for (i = 0; i < nvqs; ++i) {
-               vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
-               if (IS_ERR(vqs[i])) {
-                       ret = PTR_ERR(vqs[i]);
-                       goto error;
-               }
-       }
-
-       /* now that the vqs are all set, boot the remote processor */
-       ret = rproc_boot(rproc);
-       if (ret) {
-               dev_err(&rproc->dev, "rproc_boot() failed %d\n", ret);
-               goto error;
-       }
-
-       return 0;
+       /* power down the remote processor before deleting vqs */
+       rproc_shutdown(rproc);
 
-error:
        __rproc_virtio_del_vqs(vdev);
-       return ret;
 }
 
 /*
-- 
1.7.9.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to