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
					
				| @ -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 @@ 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; | ||||
|  | ||||
| @ -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 @@ 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; | ||||
|  | ||||
| @ -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 @@ 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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 @@ 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; | ||||
|  | ||||
| @ -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 New Issue
	
	Block a user