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

virtio: allow drivers to request IRQ affinity when creating VQs

Add a struct irq_affinity pointer to the find_vqs methods, which if set
is used to tell the PCI layer to create the MSI-X vectors for our I/O
virtqueues with the proper affinity from the start. Compared to after
the fact affinity hints this gives us an instantly working setup and
allows to allocate the irq descritors node-local and avoid interconnect
traffic. Last but not least this will allow blk-mq queues are created
based on the interrupt affinity for storage drivers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Christoph Hellwig and committed by
Michael S. Tsirkin
fb5e31d9 52a61516

+48 -34
+2 -1
drivers/block/virtio_blk.c
··· 411 411 } 412 412 413 413 /* Discover virtqueues and write information to configuration. */ 414 - err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names); 414 + err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names, 415 + NULL); 415 416 if (err) 416 417 goto out; 417 418
+1 -1
drivers/char/virtio_console.c
··· 1939 1939 /* Find the queues. */ 1940 1940 err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, 1941 1941 io_callbacks, 1942 - (const char **)io_names); 1942 + (const char **)io_names, NULL); 1943 1943 if (err) 1944 1944 goto free; 1945 1945
+1 -1
drivers/crypto/virtio/virtio_crypto_core.c
··· 119 119 } 120 120 121 121 ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks, 122 - names); 122 + names, NULL); 123 123 if (ret) 124 124 goto err_find; 125 125
+1 -1
drivers/gpu/drm/virtio/virtgpu_kms.c
··· 172 172 vgdev->has_virgl_3d ? "enabled" : "not available"); 173 173 174 174 ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs, 175 - callbacks, names); 175 + callbacks, names, NULL); 176 176 if (ret) { 177 177 DRM_ERROR("failed to find virt queues\n"); 178 178 goto err_vqs;
+1 -1
drivers/misc/mic/vop/vop_main.c
··· 374 374 static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs, 375 375 struct virtqueue *vqs[], 376 376 vq_callback_t *callbacks[], 377 - const char * const names[]) 377 + const char * const names[], struct irq_affinity *desc) 378 378 { 379 379 struct _vop_vdev *vdev = to_vopvdev(dev); 380 380 struct vop_device *vpdev = vdev->vpdev;
+2 -1
drivers/net/caif/caif_virtio.c
··· 679 679 goto err; 680 680 681 681 /* Get the TX virtio ring. This is a "guest side vring". */ 682 - err = vdev->config->find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names); 682 + err = vdev->config->find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names, 683 + NULL); 683 684 if (err) 684 685 goto err; 685 686
+1 -1
drivers/net/virtio_net.c
··· 2003 2003 } 2004 2004 2005 2005 ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks, 2006 - names); 2006 + names, NULL); 2007 2007 if (ret) 2008 2008 goto err_find; 2009 2009
+2 -1
drivers/remoteproc/remoteproc_virtio.c
··· 137 137 static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, 138 138 struct virtqueue *vqs[], 139 139 vq_callback_t *callbacks[], 140 - const char * const names[]) 140 + const char * const names[], 141 + struct irq_affinity *desc) 141 142 { 142 143 int i, ret; 143 144
+1 -1
drivers/rpmsg/virtio_rpmsg_bus.c
··· 869 869 init_waitqueue_head(&vrp->sendq); 870 870 871 871 /* We expect two virtqueues, rx and tx (and in this order) */ 872 - err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names); 872 + err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names, NULL); 873 873 if (err) 874 874 goto free_vrp; 875 875
+2 -1
drivers/s390/virtio/kvm_virtio.c
··· 255 255 static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, 256 256 struct virtqueue *vqs[], 257 257 vq_callback_t *callbacks[], 258 - const char * const names[]) 258 + const char * const names[], 259 + struct irq_affinity *desc) 259 260 { 260 261 struct kvm_device *kdev = to_kvmdev(vdev); 261 262 int i;
+2 -1
drivers/s390/virtio/virtio_ccw.c
··· 628 628 static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, 629 629 struct virtqueue *vqs[], 630 630 vq_callback_t *callbacks[], 631 - const char * const names[]) 631 + const char * const names[], 632 + struct irq_affinity *desc) 632 633 { 633 634 struct virtio_ccw_device *vcdev = to_vc_device(vdev); 634 635 unsigned long *indicatorp = NULL;
+2 -1
drivers/scsi/virtio_scsi.c
··· 941 941 } 942 942 943 943 /* Discover virtqueues and write information to configuration. */ 944 - err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names); 944 + err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names, 945 + NULL); 945 946 if (err) 946 947 goto out; 947 948
+2 -1
drivers/virtio/virtio_balloon.c
··· 413 413 * optionally stat. 414 414 */ 415 415 nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2; 416 - err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names); 416 + err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names, 417 + NULL); 417 418 if (err) 418 419 return err; 419 420
+2 -1
drivers/virtio/virtio_input.c
··· 173 173 static const char * const names[] = { "events", "status" }; 174 174 int err; 175 175 176 - err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names); 176 + err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names, 177 + NULL); 177 178 if (err) 178 179 return err; 179 180 vi->evt = vqs[0];
+2 -1
drivers/virtio/virtio_mmio.c
··· 446 446 static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, 447 447 struct virtqueue *vqs[], 448 448 vq_callback_t *callbacks[], 449 - const char * const names[]) 449 + const char * const names[], 450 + struct irq_affinity *desc) 450 451 { 451 452 struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); 452 453 unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
+12 -7
drivers/virtio/virtio_pci_common.c
··· 143 143 144 144 static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, 145 145 struct virtqueue *vqs[], vq_callback_t *callbacks[], 146 - const char * const names[]) 146 + const char * const names[], struct irq_affinity *desc) 147 147 { 148 148 struct virtio_pci_device *vp_dev = to_vp_device(vdev); 149 149 const char *name = dev_name(&vp_dev->vdev.dev); 150 150 int i, err = -ENOMEM, allocated_vectors, nvectors; 151 + unsigned flags = PCI_IRQ_MSIX; 151 152 bool shared = false; 152 153 u16 msix_vec; 154 + 155 + if (desc) { 156 + flags |= PCI_IRQ_AFFINITY; 157 + desc->pre_vectors++; /* virtio config vector */ 158 + } 153 159 154 160 nvectors = 1; 155 161 for (i = 0; i < nvqs; i++) ··· 163 157 nvectors++; 164 158 165 159 /* Try one vector per queue first. */ 166 - err = pci_alloc_irq_vectors(vp_dev->pci_dev, nvectors, nvectors, 167 - PCI_IRQ_MSIX); 160 + err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors, 161 + nvectors, flags, desc); 168 162 if (err < 0) { 169 163 /* Fallback to one vector for config, one shared for queues. */ 170 164 shared = true; ··· 314 308 315 309 /* the config->find_vqs() implementation */ 316 310 int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, 317 - struct virtqueue *vqs[], 318 - vq_callback_t *callbacks[], 319 - const char * const names[]) 311 + struct virtqueue *vqs[], vq_callback_t *callbacks[], 312 + const char * const names[], struct irq_affinity *desc) 320 313 { 321 314 int err; 322 315 323 - err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names); 316 + err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, desc); 324 317 if (!err) 325 318 return 0; 326 319 return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names);
+2 -3
drivers/virtio/virtio_pci_common.h
··· 97 97 void vp_del_vqs(struct virtio_device *vdev); 98 98 /* the config->find_vqs() implementation */ 99 99 int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, 100 - struct virtqueue *vqs[], 101 - vq_callback_t *callbacks[], 102 - const char * const names[]); 100 + struct virtqueue *vqs[], vq_callback_t *callbacks[], 101 + const char * const names[], struct irq_affinity *desc); 103 102 const char *vp_bus_name(struct virtio_device *vdev); 104 103 105 104 /* Setup the affinity for a virtqueue:
+3 -4
drivers/virtio/virtio_pci_modern.c
··· 384 384 } 385 385 386 386 static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs, 387 - struct virtqueue *vqs[], 388 - vq_callback_t *callbacks[], 389 - const char * const names[]) 387 + struct virtqueue *vqs[], vq_callback_t *callbacks[], 388 + const char * const names[], struct irq_affinity *desc) 390 389 { 391 390 struct virtio_pci_device *vp_dev = to_vp_device(vdev); 392 391 struct virtqueue *vq; 393 - int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names); 392 + int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, desc); 394 393 395 394 if (rc) 396 395 return rc;
+5 -4
include/linux/virtio_config.h
··· 7 7 #include <linux/virtio_byteorder.h> 8 8 #include <uapi/linux/virtio_config.h> 9 9 10 + struct irq_affinity; 11 + 10 12 /** 11 13 * virtio_config_ops - operations for configuring a virtio device 12 14 * @get: read the value of a configuration field ··· 70 68 void (*set_status)(struct virtio_device *vdev, u8 status); 71 69 void (*reset)(struct virtio_device *vdev); 72 70 int (*find_vqs)(struct virtio_device *, unsigned nvqs, 73 - struct virtqueue *vqs[], 74 - vq_callback_t *callbacks[], 75 - const char * const names[]); 71 + struct virtqueue *vqs[], vq_callback_t *callbacks[], 72 + const char * const names[], struct irq_affinity *desc); 76 73 void (*del_vqs)(struct virtio_device *); 77 74 u64 (*get_features)(struct virtio_device *vdev); 78 75 int (*finalize_features)(struct virtio_device *vdev); ··· 170 169 vq_callback_t *callbacks[] = { c }; 171 170 const char *names[] = { n }; 172 171 struct virtqueue *vq; 173 - int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names); 172 + int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL); 174 173 if (err < 0) 175 174 return ERR_PTR(err); 176 175 return vq;
+2 -1
net/vmw_vsock/virtio_transport.c
··· 532 532 vsock->vdev = vdev; 533 533 534 534 ret = vsock->vdev->config->find_vqs(vsock->vdev, VSOCK_VQ_MAX, 535 - vsock->vqs, callbacks, names); 535 + vsock->vqs, callbacks, names, 536 + NULL); 536 537 if (ret < 0) 537 538 goto out; 538 539