Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vhost_vdpa: implement IRQ offloading in vhost_vdpa

This patch introduce a set of functions for setup/unsetup
and update irq offloading respectively by register/unregister
and re-register the irq_bypass_producer.

With these functions, this commit can setup/unsetup
irq offloading through setting DRIVER_OK/!DRIVER_OK, and
update irq offloading through SET_VRING_CALL.

Signed-off-by: Zhu Lingshan <lingshan.zhu@intel.com>
Suggested-by: Jason Wang <jasowang@redhat.com>
Link: https://lore.kernel.org/r/20200731065533.4144-5-lingshan.zhu@intel.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Zhu Lingshan and committed by
Michael S. Tsirkin
2cf1ba9a 7164675a

+63 -1
+1
drivers/vhost/Kconfig
··· 65 65 tristate "Vhost driver for vDPA-based backend" 66 66 depends on EVENTFD 67 67 select VHOST 68 + select IRQ_BYPASS_MANAGER 68 69 depends on VDPA 69 70 help 70 71 This kernel module can be loaded in host kernel to accelerate
+62 -1
drivers/vhost/vdpa.c
··· 82 82 return IRQ_HANDLED; 83 83 } 84 84 85 + static void vhost_vdpa_setup_vq_irq(struct vhost_vdpa *v, u16 qid) 86 + { 87 + struct vhost_virtqueue *vq = &v->vqs[qid]; 88 + const struct vdpa_config_ops *ops = v->vdpa->config; 89 + struct vdpa_device *vdpa = v->vdpa; 90 + int ret, irq; 91 + 92 + if (!ops->get_vq_irq) 93 + return; 94 + 95 + irq = ops->get_vq_irq(vdpa, qid); 96 + spin_lock(&vq->call_ctx.ctx_lock); 97 + irq_bypass_unregister_producer(&vq->call_ctx.producer); 98 + if (!vq->call_ctx.ctx || irq < 0) { 99 + spin_unlock(&vq->call_ctx.ctx_lock); 100 + return; 101 + } 102 + 103 + vq->call_ctx.producer.token = vq->call_ctx.ctx; 104 + vq->call_ctx.producer.irq = irq; 105 + ret = irq_bypass_register_producer(&vq->call_ctx.producer); 106 + spin_unlock(&vq->call_ctx.ctx_lock); 107 + } 108 + 109 + static void vhost_vdpa_unsetup_vq_irq(struct vhost_vdpa *v, u16 qid) 110 + { 111 + struct vhost_virtqueue *vq = &v->vqs[qid]; 112 + 113 + spin_lock(&vq->call_ctx.ctx_lock); 114 + irq_bypass_unregister_producer(&vq->call_ctx.producer); 115 + spin_unlock(&vq->call_ctx.ctx_lock); 116 + } 117 + 85 118 static void vhost_vdpa_reset(struct vhost_vdpa *v) 86 119 { 87 120 struct vdpa_device *vdpa = v->vdpa; ··· 154 121 { 155 122 struct vdpa_device *vdpa = v->vdpa; 156 123 const struct vdpa_config_ops *ops = vdpa->config; 157 - u8 status; 124 + u8 status, status_old; 125 + int nvqs = v->nvqs; 126 + u16 i; 158 127 159 128 if (copy_from_user(&status, statusp, sizeof(status))) 160 129 return -EFAULT; 130 + 131 + status_old = ops->get_status(vdpa); 161 132 162 133 /* 163 134 * Userspace shouldn't remove status bits unless reset the ··· 171 134 return -EINVAL; 172 135 173 136 ops->set_status(vdpa, status); 137 + 138 + /* vq irq is not expected to be changed once DRIVER_OK is set */ 139 + if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) 140 + for (i = 0; i < nvqs; i++) 141 + vhost_vdpa_setup_vq_irq(v, i); 142 + 143 + if ((status_old & VIRTIO_CONFIG_S_DRIVER_OK) && !(status & VIRTIO_CONFIG_S_DRIVER_OK)) 144 + for (i = 0; i < nvqs; i++) 145 + vhost_vdpa_unsetup_vq_irq(v, i); 174 146 175 147 return 0; 176 148 } ··· 339 293 340 294 return 0; 341 295 } 296 + 342 297 static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, 343 298 void __user *argp) 344 299 { ··· 398 351 cb.private = NULL; 399 352 } 400 353 ops->set_vq_cb(vdpa, idx, &cb); 354 + vhost_vdpa_setup_vq_irq(v, idx); 401 355 break; 402 356 403 357 case VHOST_SET_VRING_NUM: ··· 774 726 return r; 775 727 } 776 728 729 + static void vhost_vdpa_clean_irq(struct vhost_vdpa *v) 730 + { 731 + struct vhost_virtqueue *vq; 732 + int i; 733 + 734 + for (i = 0; i < v->nvqs; i++) { 735 + vq = &v->vqs[i]; 736 + if (vq->call_ctx.producer.irq) 737 + irq_bypass_unregister_producer(&vq->call_ctx.producer); 738 + } 739 + } 740 + 777 741 static int vhost_vdpa_release(struct inode *inode, struct file *filep) 778 742 { 779 743 struct vhost_vdpa *v = filep->private_data; ··· 798 738 vhost_vdpa_iotlb_free(v); 799 739 vhost_vdpa_free_domain(v); 800 740 vhost_vdpa_config_put(v); 741 + vhost_vdpa_clean_irq(v); 801 742 vhost_dev_cleanup(&v->vdev); 802 743 kfree(v->vdev.vqs); 803 744 mutex_unlock(&d->mutex);