forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									52a6151612
								
							
						
					
					
						commit
						fb5e31d970
					
				
					 20 changed files with 48 additions and 34 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -374,7 +374,7 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
 | 
			
		|||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -628,7 +628,8 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
 | 
			
		|||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -446,7 +446,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
 | 
			
		|||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,
 | 
			
		|||
 | 
			
		||||
/* 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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -384,13 +384,12 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue