diff options
Diffstat (limited to 'drivers/virtio/virtio_pci.c')
| -rw-r--r-- | drivers/virtio/virtio_pci.c | 46 | 
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index d902464b89c..f5dfe6bdb95 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -48,6 +48,7 @@ struct virtio_pci_device  	int msix_enabled;  	int intx_enabled;  	struct msix_entry *msix_entries; +	cpumask_var_t *msix_affinity_masks;  	/* Name strings for interrupts. This size should be enough,  	 * and I'm too lazy to allocate each name separately. */  	char (*msix_names)[256]; @@ -276,6 +277,10 @@ static void vp_free_vectors(struct virtio_device *vdev)  	for (i = 0; i < vp_dev->msix_used_vectors; ++i)  		free_irq(vp_dev->msix_entries[i].vector, vp_dev); +	for (i = 0; i < vp_dev->msix_vectors; i++) +		if (vp_dev->msix_affinity_masks[i]) +			free_cpumask_var(vp_dev->msix_affinity_masks[i]); +  	if (vp_dev->msix_enabled) {  		/* Disable the vector used for configuration */  		iowrite16(VIRTIO_MSI_NO_VECTOR, @@ -293,6 +298,8 @@ static void vp_free_vectors(struct virtio_device *vdev)  	vp_dev->msix_names = NULL;  	kfree(vp_dev->msix_entries);  	vp_dev->msix_entries = NULL; +	kfree(vp_dev->msix_affinity_masks); +	vp_dev->msix_affinity_masks = NULL;  }  static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, @@ -311,6 +318,15 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,  				     GFP_KERNEL);  	if (!vp_dev->msix_names)  		goto error; +	vp_dev->msix_affinity_masks +		= kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks, +			  GFP_KERNEL); +	if (!vp_dev->msix_affinity_masks) +		goto error; +	for (i = 0; i < nvectors; ++i) +		if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i], +					GFP_KERNEL)) +			goto error;  	for (i = 0; i < nvectors; ++i)  		vp_dev->msix_entries[i].entry = i; @@ -606,6 +622,35 @@ static const char *vp_bus_name(struct virtio_device *vdev)  	return pci_name(vp_dev->pci_dev);  } +/* Setup the affinity for a virtqueue: + * - force the affinity for per vq vector + * - OR over all affinities for shared MSI + * - ignore the affinity request if we're using INTX + */ +static int vp_set_vq_affinity(struct virtqueue *vq, int cpu) +{ +	struct virtio_device *vdev = vq->vdev; +	struct virtio_pci_device *vp_dev = to_vp_device(vdev); +	struct virtio_pci_vq_info *info = vq->priv; +	struct cpumask *mask; +	unsigned int irq; + +	if (!vq->callback) +		return -EINVAL; + +	if (vp_dev->msix_enabled) { +		mask = vp_dev->msix_affinity_masks[info->msix_vector]; +		irq = vp_dev->msix_entries[info->msix_vector].vector; +		if (cpu == -1) +			irq_set_affinity_hint(irq, NULL); +		else { +			cpumask_set_cpu(cpu, mask); +			irq_set_affinity_hint(irq, mask); +		} +	} +	return 0; +} +  static struct virtio_config_ops virtio_pci_config_ops = {  	.get		= vp_get,  	.set		= vp_set, @@ -617,6 +662,7 @@ static struct virtio_config_ops virtio_pci_config_ops = {  	.get_features	= vp_get_features,  	.finalize_features = vp_finalize_features,  	.bus_name	= vp_bus_name, +	.set_vq_affinity = vp_set_vq_affinity,  };  static void virtio_pci_release_dev(struct device *_d)  |