This patch introduces a workqueue to support injecting virtqueue's interrupt asynchronously. This is mainly for performance considerations which makes sure the push() and pop() for used vring can be asynchronous. Signed-off-by: Xie Yongji <xieyongji@xxxxxxxxxxxxx> --- drivers/vdpa/vdpa_user/vduse_dev.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 8042d3fa57f1..f5adeb9ee027 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -42,6 +42,7 @@ struct vduse_virtqueue { spinlock_t irq_lock; struct eventfd_ctx *kickfd; struct vdpa_callback cb; + struct work_struct inject; }; struct vduse_dev; @@ -99,6 +100,7 @@ static DEFINE_IDA(vduse_ida); static dev_t vduse_major; static struct class *vduse_class; +static struct workqueue_struct *vduse_irq_wq; static inline struct vduse_dev *vdpa_to_vduse(struct vdpa_device *vdpa) { @@ -852,6 +854,17 @@ static int vduse_kickfd_setup(struct vduse_dev *dev, return 0; } +static void vduse_vq_irq_inject(struct work_struct *work) +{ + struct vduse_virtqueue *vq = container_of(work, + struct vduse_virtqueue, inject); + + spin_lock_irq(&vq->irq_lock); + if (vq->ready && vq->cb.callback) + vq->cb.callback(vq->cb.private); + spin_unlock_irq(&vq->irq_lock); +} + static long vduse_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -917,12 +930,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; vq = &dev->vqs[arg]; - spin_lock_irq(&vq->irq_lock); - if (vq->ready && vq->cb.callback) { - vq->cb.callback(vq->cb.private); - ret = 0; - } - spin_unlock_irq(&vq->irq_lock); + queue_work(vduse_irq_wq, &vq->inject); break; } case VDUSE_INJECT_CONFIG_IRQ: @@ -1109,6 +1117,7 @@ static int vduse_create_dev(struct vduse_dev_config *config) for (i = 0; i < dev->vq_num; i++) { dev->vqs[i].index = i; + INIT_WORK(&dev->vqs[i].inject, vduse_vq_irq_inject); spin_lock_init(&dev->vqs[i].kick_lock); spin_lock_init(&dev->vqs[i].irq_lock); } @@ -1333,6 +1342,11 @@ static int vduse_init(void) if (ret) goto err_chardev; + vduse_irq_wq = alloc_workqueue("vduse-irq", + WQ_HIGHPRI | WQ_SYSFS | WQ_UNBOUND, 0); + if (!vduse_irq_wq) + goto err_wq; + ret = vduse_domain_init(); if (ret) goto err_domain; @@ -1344,6 +1358,8 @@ static int vduse_init(void) return 0; err_mgmtdev: vduse_domain_exit(); +err_wq: + destroy_workqueue(vduse_irq_wq); err_domain: unregister_chrdev_region(vduse_major, VDUSE_DEV_MAX); err_chardev: @@ -1359,6 +1375,7 @@ static void vduse_exit(void) misc_deregister(&vduse_misc); class_destroy(vduse_class); unregister_chrdev_region(vduse_major, VDUSE_DEV_MAX); + destroy_workqueue(vduse_irq_wq); vduse_domain_exit(); vduse_mgmtdev_exit(); } -- 2.11.0