#include <linux/virtio_config.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
+#include <linux/vringh.h>
#include <linux/err.h>
#include <linux/kref.h>
#include <linux/slab.h>
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);
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 */
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.
*
#include <linux/klist.h>
#include <linux/mutex.h>
#include <linux/virtio.h>
+#include <linux/vringh.h>
#include <linux/completion.h>
+#include <linux/interrupt.h>
#include <linux/idr.h>
/**
* @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;
int notifyid;
struct rproc_vdev *rvdev;
struct virtqueue *vq;
+ irqreturn_t (*vringh_cb)(struct virtio_device *vdev,
+ struct vringh *vring);
+ struct vringh *vringh;
};
/**
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);