From 414a13c3d236d2116dff36a9c9f974fa06e2e3e5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sjur=20Br=C3=A6ndeland?= Date: Tue, 19 Feb 2013 09:30:52 +1030 Subject: [PATCH] remoteproc: Add support for vringh (Host vrings) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add functions for creating, deleting and kicking host-side virtio rings. The host ring is not integrated with virtiqueues and cannot be managed through virtio-config. Remoteproc must export functions for handling the host-side virtio rings. The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(), rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs() are updated to handle the new vhost rings. Signed-off-by: Sjur Brændeland cc: Ohad Ben-Cohen cc: Rusty Russell cc: Ido Yariv cc: Erwan Yvin Signed-off-by: Rusty Russell --- drivers/remoteproc/Kconfig | 3 + drivers/remoteproc/remoteproc_virtio.c | 127 +++++++++++++++++++++++-- include/linux/remoteproc.h | 14 +++ 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 96ce101b9067..c7d1d362a294 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,9 @@ config REMOTEPROC depends on HAS_DMA select FW_CONFIG select VIRTIO + select VHOST_RING + +source drivers/vhost/Kconfig config OMAP_REMOTEPROC tristate "OMAP remoteproc support" diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index afed9b7731c4..750b21818e27 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid); rvring = idr_find(&rproc->notifyids, notifyid); - if (!rvring || !rvring->vq) + if (!rvring) return IRQ_NONE; - return vring_interrupt(0, rvring->vq); + if (rvring->vringh && rvring->vringh_cb) + return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh); + else if (rvring->vq) + return vring_interrupt(0, rvring->vq); + else + return IRQ_NONE; } EXPORT_SYMBOL(rproc_vq_interrupt); @@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, const char *names[]) { struct rproc *rproc = vdev_to_rproc(vdev); - int i, ret; + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring); + + for (id = 0, rng = 0; rng < nrings; ++rng) { + struct rproc_vring *rvring = &rvdev->vring[rng]; + /* Skip the host side rings */ + if (rvring->vringh) + continue; - 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]); + vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]); + if (IS_ERR(vqs[id])) { + ret = PTR_ERR(vqs[id]); goto error; } + ++id; } /* now that the vqs are all set, boot the remote processor */ @@ -173,6 +186,106 @@ error: return ret; } +/** + * rproc_virtio_new_vringh() - create a reversed virtio ring. + * @vdev: the virtio device + * @index: the virtio ring index + * @cb: callback for the reversed virtio ring + * + * This function should be called by the virtio-driver + * before calling find_vqs(). It returns a struct vringh for + * accessing the virtio ring. + * + * Return: struct vhost, or NULL upon error. + */ +struct vringh * +rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index, + irqreturn_t (*cb)(struct virtio_device *vdev, + struct vringh *vring)) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring; + struct vringh *vrh; + int err; + + if (index > ARRAY_SIZE(rvdev->vring)) { + dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index); + return NULL; + } + + vrh = kzalloc(sizeof(*vrh), GFP_KERNEL); + if (!vrh) + return NULL; + + err = rproc_alloc_vring(rvdev, index); + if (err) + goto free_vring; + + + rvring = &rvdev->vring[index]; + /* zero vring */ + memset(rvring->va, 0, vring_size(rvring->len, rvring->align)); + vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align); + + rvring->vringh_cb = cb; + rvring->vringh = vrh; + + err = vringh_init_kern(vrh, + rvdev->dfeatures, + rvring->len, + false, + vrh->vring.desc, + vrh->vring.avail, + vrh->vring.used); + if (!err) + return vrh; + + dev_err(&vdev->dev, "failed to create vhost: %d\n", err); + rproc_free_vring(rvring); +free_vring: + kfree(vrh); + return NULL; +} +EXPORT_SYMBOL(rproc_virtio_new_vringh); + +/** + * rproc_virtio_del_vringh() - release a reversed virtio ring. + * @vdev: the virtio device + * @index: the virtio ring index + * + * This function release the reversed virtio ring. + */ +void rproc_virtio_del_vringh(struct virtio_device *vdev, unsigned index) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring = &rvdev->vring[index]; + kfree(rvring->vringh); + rproc_free_vring(rvring); + rvring->vringh_cb = NULL; + rvring->vringh = NULL; +} +EXPORT_SYMBOL(rproc_virtio_del_vringh); + +/** + * rproc_virtio_kick_vringh() - kick the remote processor. + * @vdev: the virtio device + * @index: the virtio ring index + * + * kick the remote processor, and let it know which vring to poke at + */ +void rproc_virtio_kick_vringh(struct virtio_device *vdev, unsigned index) +{ + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); + struct rproc_vring *rvring = &rvdev->vring[index]; + struct rproc *rproc = rvring->rvdev->rproc; + int notifyid = rvring->notifyid; + + dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid); + + rproc->ops->kick(rproc, notifyid); +} +EXPORT_SYMBOL(rproc_virtio_kick_vringh); + /* * We don't support yet real virtio status semantics. * diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index faf33324c78f..414a1fda828b 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -39,7 +39,9 @@ #include #include #include +#include #include +#include #include /** @@ -444,6 +446,8 @@ struct rproc { * @notifyid: rproc-specific unique vring index * @rvdev: remote vdev * @vq: the virtqueue of this vring + * @vringh_cb: callback used when device has kicked + * @vringh: the reversed host-side vring */ struct rproc_vring { void *va; @@ -454,6 +458,9 @@ struct rproc_vring { int notifyid; struct rproc_vdev *rvdev; struct virtqueue *vq; + irqreturn_t (*vringh_cb)(struct virtio_device *vdev, + struct vringh *vring); + struct vringh *vringh; }; /** @@ -485,6 +492,13 @@ int rproc_boot(struct rproc *rproc); void rproc_shutdown(struct rproc *rproc); void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); +struct vringh * +rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index, + irqreturn_t (*cb)(struct virtio_device *vdev, + struct vringh *vring)); +void rproc_virtio_del_vringh(struct virtio_device *vdev, unsigned index); +void rproc_virtio_kick_vringh(struct virtio_device *vdev, unsigned index); + static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) { return container_of(vdev, struct rproc_vdev, vdev); -- 2.39.5