[PATCH v2 09/11] vduse: Add enable_irq_wq sysfs interface for virtqueues

From: Xie Yongji
Date: Mon Dec 05 2022 - 04:04:18 EST


Add enable_irq_wq sysfs interface to control whether
use workqueue to inject irq or not. The vhost-vdpa case
can benefit from it.

Signed-off-by: Xie Yongji <xieyongji@xxxxxxxxxxxxx>
---
drivers/vdpa/vdpa_user/vduse_dev.c | 50 +++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index c65f84100e30..ed06c7afd484 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -62,6 +62,7 @@ struct vduse_virtqueue {
struct cpumask irq_affinity;
spinlock_t irq_affinity_lock;
struct kobject kobj;
+ bool enable_irq_wq;
};

struct vduse_dev;
@@ -1013,6 +1014,26 @@ static int vduse_dev_queue_irq_work(struct vduse_dev *dev,
return ret;
}

+static int vduse_dev_inject_vq_irq(struct vduse_dev *dev,
+ struct vduse_virtqueue *vq)
+{
+ int ret = -EINVAL;
+
+ down_read(&dev->rwsem);
+ if (!(dev->status & VIRTIO_CONFIG_S_DRIVER_OK))
+ goto unlock;
+
+ ret = 0;
+ spin_lock_irq(&vq->irq_lock);
+ if (vq->ready && vq->cb.callback)
+ vq->cb.callback(vq->cb.private);
+ spin_unlock_irq(&vq->irq_lock);
+unlock:
+ up_read(&dev->rwsem);
+
+ return ret;
+}
+
static int vduse_dev_dereg_umem(struct vduse_dev *dev,
u64 iova, u64 size)
{
@@ -1278,8 +1299,12 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd,
break;

index = array_index_nospec(index, dev->vq_num);
- ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index]->inject,
+ if (dev->vqs[index]->enable_irq_wq)
+ ret = vduse_dev_queue_irq_work(dev,
+ &dev->vqs[index]->inject,
dev->vqs[index]->irq_effective_cpu);
+ else
+ ret = vduse_dev_inject_vq_irq(dev, dev->vqs[index]);
break;
}
case VDUSE_IOTLB_REG_UMEM: {
@@ -1420,6 +1445,26 @@ static const struct file_operations vduse_dev_fops = {
.llseek = noop_llseek,
};

+static ssize_t enable_irq_wq_show(struct vduse_virtqueue *vq, char *buf)
+{
+ return sprintf(buf, "%d\n", vq->enable_irq_wq);
+}
+
+static ssize_t enable_irq_wq_store(struct vduse_virtqueue *vq,
+ const char *buf, size_t count)
+{
+ bool enabled;
+ int ret;
+
+ ret = kstrtobool(buf, &enabled);
+ if (ret)
+ return ret;
+
+ vq->enable_irq_wq = enabled;
+
+ return count;
+}
+
static ssize_t irq_cb_affinity_show(struct vduse_virtqueue *vq, char *buf)
{
return sprintf(buf, "%*pb\n", cpumask_pr_args(&vq->irq_affinity));
@@ -1480,10 +1525,12 @@ struct vq_sysfs_entry {
static struct vq_sysfs_entry irq_cb_affinity_attr = __ATTR_RO(irq_cb_affinity);
static struct vq_sysfs_entry irq_cb_effective_affinity_attr =
__ATTR_RW(irq_cb_effective_affinity);
+static struct vq_sysfs_entry enable_irq_wq_attr = __ATTR_RW(enable_irq_wq);

static struct attribute *vq_attrs[] = {
&irq_cb_affinity_attr.attr,
&irq_cb_effective_affinity_attr.attr,
+ &enable_irq_wq_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(vq);
@@ -1565,6 +1612,7 @@ static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num)

dev->vqs[i]->index = i;
dev->vqs[i]->irq_effective_cpu = -1;
+ dev->vqs[i]->enable_irq_wq = true;
INIT_WORK(&dev->vqs[i]->inject, vduse_vq_irq_inject);
INIT_WORK(&dev->vqs[i]->kick, vduse_vq_kick_work);
spin_lock_init(&dev->vqs[i]->kick_lock);
--
2.20.1