virtio: allow drivers to request IRQ affinity when creating VQs
authorChristoph Hellwig <hch@lst.de>
Sun, 5 Feb 2017 17:15:22 +0000 (18:15 +0100)
committerMichael S. Tsirkin <mst@redhat.com>
Mon, 27 Feb 2017 18:54:04 +0000 (20:54 +0200)
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>
20 files changed:
drivers/block/virtio_blk.c
drivers/char/virtio_console.c
drivers/crypto/virtio/virtio_crypto_core.c
drivers/gpu/drm/virtio/virtgpu_kms.c
drivers/misc/mic/vop/vop_main.c
drivers/net/caif/caif_virtio.c
drivers/net/virtio_net.c
drivers/remoteproc/remoteproc_virtio.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/s390/virtio/kvm_virtio.c
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/virtio_scsi.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_input.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_common.h
drivers/virtio/virtio_pci_modern.c
include/linux/virtio_config.h
net/vmw_vsock/virtio_transport.c

index 10332c24f9610d7e80b154bf36eebb0354ac4576..c54118bdc67d069cfac7c0492283a427d2ef72ce 100644 (file)
@@ -411,7 +411,8 @@ static int init_vq(struct virtio_blk *vblk)
        }
 
        /* Discover virtqueues and write information to configuration.  */
-       err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names);
+       err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names,
+                       NULL);
        if (err)
                goto out;
 
index 17857beb489294b2c1b5bbd068a18ba013ab3fae..6266c0568e1d0a3e6526723a66490c932216fb56 100644 (file)
@@ -1939,7 +1939,7 @@ static int init_vqs(struct ports_device *portdev)
        /* Find the queues. */
        err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
                                              io_callbacks,
-                                             (const char **)io_names);
+                                             (const char **)io_names, NULL);
        if (err)
                goto free;
 
index fe70ec823b27dd3f31ca309756310ef71c9e3f30..0aa2f045543b5b7726f946bf2404f38ba593dd46 100644 (file)
@@ -119,7 +119,7 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi)
        }
 
        ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
-                                        names);
+                                        names, NULL);
        if (ret)
                goto err_find;
 
index 1235519853f4df79481a0b9c0050c7e15ab1f4e0..e975fa5b0a3210477df00592559dfba0c0ab4872 100644 (file)
@@ -172,7 +172,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
                 vgdev->has_virgl_3d ? "enabled" : "not available");
 
        ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs,
-                                           callbacks, names);
+                                           callbacks, names, NULL);
        if (ret) {
                DRM_ERROR("failed to find virt queues\n");
                goto err_vqs;
index 1a2b67f3183d502f74ab8e34cbd82d12a0d75011..c2e29d7f0de88838d18cdb52c965dda55e16f774 100644 (file)
@@ -374,7 +374,7 @@ unmap:
 static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs,
                        struct virtqueue *vqs[],
                        vq_callback_t *callbacks[],
-                       const char * const names[])
+                       const char * const names[], struct irq_affinity *desc)
 {
        struct _vop_vdev *vdev = to_vopvdev(dev);
        struct vop_device *vpdev = vdev->vpdev;
index b306210b02b7b40c717ae160e4116db8926418ce..bc0eb47ecceea7891c22e309f604ece0b0de9807 100644 (file)
@@ -679,7 +679,8 @@ static int cfv_probe(struct virtio_device *vdev)
                goto err;
 
        /* Get the TX virtio ring. This is a "guest side vring". */
-       err = vdev->config->find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names);
+       err = vdev->config->find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names,
+                       NULL);
        if (err)
                goto err;
 
index 765c2d6358daf38203cdb1a50a31cc04f65c1968..9be74c2dfb22bdfe79602b1911547c3f43e2970d 100644 (file)
@@ -2003,7 +2003,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
        }
 
        ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
-                                        names);
+                                        names, NULL);
        if (ret)
                goto err_find;
 
index 364411fb77343f5c043bb9e681ecde8a5ca4cec7..0142cc3f0c91c6fe98fe4222741819692592b25b 100644 (file)
@@ -137,7 +137,8 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev)
 static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
                                 struct virtqueue *vqs[],
                                 vq_callback_t *callbacks[],
-                                const char * const names[])
+                                const char * const names[],
+                                struct irq_affinity *desc)
 {
        int i, ret;
 
index 3090b0d3072f1ed8964b1697562d704abf7a99cf..5e66e081027e56ce00ac9273752a5c2bc34ea7c6 100644 (file)
@@ -869,7 +869,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        init_waitqueue_head(&vrp->sendq);
 
        /* We expect two virtqueues, rx and tx (and in this order) */
-       err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names);
+       err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names, NULL);
        if (err)
                goto free_vrp;
 
index 5e5c11f37b2420cbb406ff5591ad15fe615f5ed8..2ce0b3eb2efebc89121b8cd938d3677e936bffa4 100644 (file)
@@ -255,7 +255,8 @@ static void kvm_del_vqs(struct virtio_device *vdev)
 static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                        struct virtqueue *vqs[],
                        vq_callback_t *callbacks[],
-                       const char * const names[])
+                       const char * const names[],
+                       struct irq_affinity *desc)
 {
        struct kvm_device *kdev = to_kvmdev(vdev);
        int i;
index 070c4da95f48c0e9b0dbb7b6bcf008f8d6e5972e..304d3b3cbfd3dd5f5944610dcde188089c922b97 100644 (file)
@@ -628,7 +628,8 @@ out:
 static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                               struct virtqueue *vqs[],
                               vq_callback_t *callbacks[],
-                              const char * const names[])
+                              const char * const names[],
+                              struct irq_affinity *desc)
 {
        struct virtio_ccw_device *vcdev = to_vc_device(vdev);
        unsigned long *indicatorp = NULL;
index c680d76413116c00b80193f5e7db9de2e13441b1..c9c5ea0611e9be5113d2030677e0dd24ccd89b0d 100644 (file)
@@ -941,7 +941,8 @@ static int virtscsi_init(struct virtio_device *vdev,
        }
 
        /* Discover virtqueues and write information to configuration.  */
-       err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names);
+       err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names,
+                       NULL);
        if (err)
                goto out;
 
index 181793f078524ae8c06751d4b03677a132b4a7c3..36c9c8fcb7f867034e44d6bbba2d2c239f4cee9d 100644 (file)
@@ -413,7 +413,8 @@ static int init_vqs(struct virtio_balloon *vb)
         * optionally stat.
         */
        nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
-       err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names);
+       err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names,
+                       NULL);
        if (err)
                return err;
 
index 350a2a5a49dbedbbfcb45e9fd3ad9be142828294..79f1293cda9327a051feef083871bdbc62038496 100644 (file)
@@ -173,7 +173,8 @@ static int virtinput_init_vqs(struct virtio_input *vi)
        static const char * const names[] = { "events", "status" };
        int err;
 
-       err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names);
+       err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names,
+                       NULL);
        if (err)
                return err;
        vi->evt = vqs[0];
index 08357d70a89174256ff73c40c5324ea519035533..78343b8f9034b35ea7d18e6f8a5b3e3df4bae9e0 100644 (file)
@@ -446,7 +446,8 @@ error_available:
 static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                       struct virtqueue *vqs[],
                       vq_callback_t *callbacks[],
-                      const char * const names[])
+                      const char * const names[],
+                      struct irq_affinity *desc)
 {
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
        unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
index 822f8e5dcee421122f5cf7e21982b60790bce69e..7902e920fc73fab609a528bd7ea3b3d24acb358c 100644 (file)
@@ -143,22 +143,28 @@ void vp_del_vqs(struct virtio_device *vdev)
 
 static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,
                struct virtqueue *vqs[], vq_callback_t *callbacks[],
-               const char * const names[])
+               const char * const names[], struct irq_affinity *desc)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        const char *name = dev_name(&vp_dev->vdev.dev);
        int i, err = -ENOMEM, allocated_vectors, nvectors;
+       unsigned flags = PCI_IRQ_MSIX;
        bool shared = false;
        u16 msix_vec;
 
+       if (desc) {
+               flags |= PCI_IRQ_AFFINITY;
+               desc->pre_vectors++; /* virtio config vector */
+       }
+
        nvectors = 1;
        for (i = 0; i < nvqs; i++)
                if (callbacks[i])
                        nvectors++;
 
        /* Try one vector per queue first. */
-       err = pci_alloc_irq_vectors(vp_dev->pci_dev, nvectors, nvectors,
-                       PCI_IRQ_MSIX);
+       err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors,
+                       nvectors, flags, desc);
        if (err < 0) {
                /* Fallback to one vector for config, one shared for queues. */
                shared = true;
@@ -308,13 +314,12 @@ out_remove_vqs:
 
 /* the config->find_vqs() implementation */
 int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-               struct virtqueue *vqs[],
-               vq_callback_t *callbacks[],
-               const char * const names[])
+               struct virtqueue *vqs[], vq_callback_t *callbacks[],
+               const char * const names[], struct irq_affinity *desc)
 {
        int err;
 
-       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names);
+       err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, desc);
        if (!err)
                return 0;
        return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names);
index 217ca876eed729c335ebaa8b3a60bf28733dd090..a6ad9ec6baefd0092e7d6f32a30fff053220a3b5 100644 (file)
@@ -97,9 +97,8 @@ bool vp_notify(struct virtqueue *vq);
 void vp_del_vqs(struct virtio_device *vdev);
 /* the config->find_vqs() implementation */
 int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                      struct virtqueue *vqs[],
-                      vq_callback_t *callbacks[],
-                      const char * const names[]);
+               struct virtqueue *vqs[], vq_callback_t *callbacks[],
+               const char * const names[], struct irq_affinity *desc);
 const char *vp_bus_name(struct virtio_device *vdev);
 
 /* Setup the affinity for a virtqueue:
index e5ce310919534e2284cc5b2cf61a3e2db0e0a588..a7a0981e441ce080a91421298155f36f95b1256e 100644 (file)
@@ -384,13 +384,12 @@ err_map_notify:
 }
 
 static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                             struct virtqueue *vqs[],
-                             vq_callback_t *callbacks[],
-                             const char * const names[])
+               struct virtqueue *vqs[], vq_callback_t *callbacks[],
+               const char * const names[], struct irq_affinity *desc)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtqueue *vq;
-       int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names);
+       int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, desc);
 
        if (rc)
                return rc;
index 26c155bb639b5798ac2b35b5da9084891b28890a..2ebe506fe41aea8287781407bc6a40a6f49b4a28 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/virtio_byteorder.h>
 #include <uapi/linux/virtio_config.h>
 
+struct irq_affinity;
+
 /**
  * virtio_config_ops - operations for configuring a virtio device
  * @get: read the value of a configuration field
@@ -68,9 +70,8 @@ struct virtio_config_ops {
        void (*set_status)(struct virtio_device *vdev, u8 status);
        void (*reset)(struct virtio_device *vdev);
        int (*find_vqs)(struct virtio_device *, unsigned nvqs,
-                       struct virtqueue *vqs[],
-                       vq_callback_t *callbacks[],
-                       const char * const names[]);
+                       struct virtqueue *vqs[], vq_callback_t *callbacks[],
+                       const char * const names[], struct irq_affinity *desc);
        void (*del_vqs)(struct virtio_device *);
        u64 (*get_features)(struct virtio_device *vdev);
        int (*finalize_features)(struct virtio_device *vdev);
@@ -169,7 +170,7 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
        vq_callback_t *callbacks[] = { c };
        const char *names[] = { n };
        struct virtqueue *vq;
-       int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names);
+       int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL);
        if (err < 0)
                return ERR_PTR(err);
        return vq;
index 6788264acc632de6a309d5b895e0b78814a55e9a..9d24c0e958b18e614e30b24c0fcfbbe2152941f3 100644 (file)
@@ -532,7 +532,8 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
        vsock->vdev = vdev;
 
        ret = vsock->vdev->config->find_vqs(vsock->vdev, VSOCK_VQ_MAX,
-                                           vsock->vqs, callbacks, names);
+                                           vsock->vqs, callbacks, names,
+                                           NULL);
        if (ret < 0)
                goto out;