Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[linux-block.git] / drivers / virtio / virtio_mmio.c
index 3ff746e3f24aa0306b4ce715acbd3980d6e59908..a46a4a29e9295f7225bfbc631642e0e0a81f92d6 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
@@ -285,6 +286,16 @@ static bool vm_notify(struct virtqueue *vq)
        return true;
 }
 
+static bool vm_notify_with_data(struct virtqueue *vq)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
+       u32 data = vring_notification_data(vq);
+
+       writel(data, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
+
+       return true;
+}
+
 /* Notify all virtqueues on an interrupt. */
 static irqreturn_t vm_interrupt(int irq, void *opaque)
 {
@@ -363,12 +374,18 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
                                  const char *name, bool ctx)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+       bool (*notify)(struct virtqueue *vq);
        struct virtio_mmio_vq_info *info;
        struct virtqueue *vq;
        unsigned long flags;
        unsigned int num;
        int err;
 
+       if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA))
+               notify = vm_notify_with_data;
+       else
+               notify = vm_notify;
+
        if (!name)
                return NULL;
 
@@ -397,7 +414,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
 
        /* Create the vring */
        vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev,
-                                true, true, ctx, vm_notify, callback, name);
+                                true, true, ctx, notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto error_new_virtqueue;