162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Virtio PCI driver - common functionality for all device versions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This module allows virtio devices to be used over a virtual PCI device.
662306a36Sopenharmony_ci * This can be used with QEMU based VMMs like KVM or Xen.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright IBM Corp. 2007
962306a36Sopenharmony_ci * Copyright Red Hat, Inc. 2014
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Authors:
1262306a36Sopenharmony_ci *  Anthony Liguori  <aliguori@us.ibm.com>
1362306a36Sopenharmony_ci *  Rusty Russell <rusty@rustcorp.com.au>
1462306a36Sopenharmony_ci *  Michael S. Tsirkin <mst@redhat.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "virtio_pci_common.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic bool force_legacy = false;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
2262306a36Sopenharmony_cimodule_param(force_legacy, bool, 0444);
2362306a36Sopenharmony_ciMODULE_PARM_DESC(force_legacy,
2462306a36Sopenharmony_ci		 "Force legacy mode for transitional virtio 1 devices");
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* wait for pending irq handlers */
2862306a36Sopenharmony_civoid vp_synchronize_vectors(struct virtio_device *vdev)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
3162306a36Sopenharmony_ci	int i;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (vp_dev->intx_enabled)
3462306a36Sopenharmony_ci		synchronize_irq(vp_dev->pci_dev->irq);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	for (i = 0; i < vp_dev->msix_vectors; ++i)
3762306a36Sopenharmony_ci		synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i));
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* the notify function used when creating a virt queue */
4162306a36Sopenharmony_cibool vp_notify(struct virtqueue *vq)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	/* we write the queue's selector into the notification register to
4462306a36Sopenharmony_ci	 * signal the other end */
4562306a36Sopenharmony_ci	iowrite16(vq->index, (void __iomem *)vq->priv);
4662306a36Sopenharmony_ci	return true;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* Handle a configuration change: Tell driver if it wants to know. */
5062306a36Sopenharmony_cistatic irqreturn_t vp_config_changed(int irq, void *opaque)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = opaque;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	virtio_config_changed(&vp_dev->vdev);
5562306a36Sopenharmony_ci	return IRQ_HANDLED;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* Notify all virtqueues on an interrupt. */
5962306a36Sopenharmony_cistatic irqreturn_t vp_vring_interrupt(int irq, void *opaque)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = opaque;
6262306a36Sopenharmony_ci	struct virtio_pci_vq_info *info;
6362306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
6462306a36Sopenharmony_ci	unsigned long flags;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	spin_lock_irqsave(&vp_dev->lock, flags);
6762306a36Sopenharmony_ci	list_for_each_entry(info, &vp_dev->virtqueues, node) {
6862306a36Sopenharmony_ci		if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
6962306a36Sopenharmony_ci			ret = IRQ_HANDLED;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	spin_unlock_irqrestore(&vp_dev->lock, flags);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return ret;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* A small wrapper to also acknowledge the interrupt when it's handled.
7762306a36Sopenharmony_ci * I really need an EIO hook for the vring so I can ack the interrupt once we
7862306a36Sopenharmony_ci * know that we'll be handling the IRQ but before we invoke the callback since
7962306a36Sopenharmony_ci * the callback may notify the host which results in the host attempting to
8062306a36Sopenharmony_ci * raise an interrupt that we would then mask once we acknowledged the
8162306a36Sopenharmony_ci * interrupt. */
8262306a36Sopenharmony_cistatic irqreturn_t vp_interrupt(int irq, void *opaque)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = opaque;
8562306a36Sopenharmony_ci	u8 isr;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* reading the ISR has the effect of also clearing it so it's very
8862306a36Sopenharmony_ci	 * important to save off the value. */
8962306a36Sopenharmony_ci	isr = ioread8(vp_dev->isr);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* It's definitely not us if the ISR was not high */
9262306a36Sopenharmony_ci	if (!isr)
9362306a36Sopenharmony_ci		return IRQ_NONE;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Configuration change?  Tell driver if it wants to know. */
9662306a36Sopenharmony_ci	if (isr & VIRTIO_PCI_ISR_CONFIG)
9762306a36Sopenharmony_ci		vp_config_changed(irq, opaque);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return vp_vring_interrupt(irq, opaque);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
10362306a36Sopenharmony_ci				   bool per_vq_vectors, struct irq_affinity *desc)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
10662306a36Sopenharmony_ci	const char *name = dev_name(&vp_dev->vdev.dev);
10762306a36Sopenharmony_ci	unsigned int flags = PCI_IRQ_MSIX;
10862306a36Sopenharmony_ci	unsigned int i, v;
10962306a36Sopenharmony_ci	int err = -ENOMEM;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	vp_dev->msix_vectors = nvectors;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	vp_dev->msix_names = kmalloc_array(nvectors,
11462306a36Sopenharmony_ci					   sizeof(*vp_dev->msix_names),
11562306a36Sopenharmony_ci					   GFP_KERNEL);
11662306a36Sopenharmony_ci	if (!vp_dev->msix_names)
11762306a36Sopenharmony_ci		goto error;
11862306a36Sopenharmony_ci	vp_dev->msix_affinity_masks
11962306a36Sopenharmony_ci		= kcalloc(nvectors, sizeof(*vp_dev->msix_affinity_masks),
12062306a36Sopenharmony_ci			  GFP_KERNEL);
12162306a36Sopenharmony_ci	if (!vp_dev->msix_affinity_masks)
12262306a36Sopenharmony_ci		goto error;
12362306a36Sopenharmony_ci	for (i = 0; i < nvectors; ++i)
12462306a36Sopenharmony_ci		if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i],
12562306a36Sopenharmony_ci					GFP_KERNEL))
12662306a36Sopenharmony_ci			goto error;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (desc) {
12962306a36Sopenharmony_ci		flags |= PCI_IRQ_AFFINITY;
13062306a36Sopenharmony_ci		desc->pre_vectors++; /* virtio config vector */
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors,
13462306a36Sopenharmony_ci					     nvectors, flags, desc);
13562306a36Sopenharmony_ci	if (err < 0)
13662306a36Sopenharmony_ci		goto error;
13762306a36Sopenharmony_ci	vp_dev->msix_enabled = 1;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Set the vector used for configuration */
14062306a36Sopenharmony_ci	v = vp_dev->msix_used_vectors;
14162306a36Sopenharmony_ci	snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
14262306a36Sopenharmony_ci		 "%s-config", name);
14362306a36Sopenharmony_ci	err = request_irq(pci_irq_vector(vp_dev->pci_dev, v),
14462306a36Sopenharmony_ci			  vp_config_changed, 0, vp_dev->msix_names[v],
14562306a36Sopenharmony_ci			  vp_dev);
14662306a36Sopenharmony_ci	if (err)
14762306a36Sopenharmony_ci		goto error;
14862306a36Sopenharmony_ci	++vp_dev->msix_used_vectors;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	v = vp_dev->config_vector(vp_dev, v);
15162306a36Sopenharmony_ci	/* Verify we had enough resources to assign the vector */
15262306a36Sopenharmony_ci	if (v == VIRTIO_MSI_NO_VECTOR) {
15362306a36Sopenharmony_ci		err = -EBUSY;
15462306a36Sopenharmony_ci		goto error;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (!per_vq_vectors) {
15862306a36Sopenharmony_ci		/* Shared vector for all VQs */
15962306a36Sopenharmony_ci		v = vp_dev->msix_used_vectors;
16062306a36Sopenharmony_ci		snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
16162306a36Sopenharmony_ci			 "%s-virtqueues", name);
16262306a36Sopenharmony_ci		err = request_irq(pci_irq_vector(vp_dev->pci_dev, v),
16362306a36Sopenharmony_ci				  vp_vring_interrupt, 0, vp_dev->msix_names[v],
16462306a36Sopenharmony_ci				  vp_dev);
16562306a36Sopenharmony_ci		if (err)
16662306a36Sopenharmony_ci			goto error;
16762306a36Sopenharmony_ci		++vp_dev->msix_used_vectors;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_cierror:
17162306a36Sopenharmony_ci	return err;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned int index,
17562306a36Sopenharmony_ci				     void (*callback)(struct virtqueue *vq),
17662306a36Sopenharmony_ci				     const char *name,
17762306a36Sopenharmony_ci				     bool ctx,
17862306a36Sopenharmony_ci				     u16 msix_vec)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
18162306a36Sopenharmony_ci	struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL);
18262306a36Sopenharmony_ci	struct virtqueue *vq;
18362306a36Sopenharmony_ci	unsigned long flags;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* fill out our structure that represents an active queue */
18662306a36Sopenharmony_ci	if (!info)
18762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx,
19062306a36Sopenharmony_ci			      msix_vec);
19162306a36Sopenharmony_ci	if (IS_ERR(vq))
19262306a36Sopenharmony_ci		goto out_info;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	info->vq = vq;
19562306a36Sopenharmony_ci	if (callback) {
19662306a36Sopenharmony_ci		spin_lock_irqsave(&vp_dev->lock, flags);
19762306a36Sopenharmony_ci		list_add(&info->node, &vp_dev->virtqueues);
19862306a36Sopenharmony_ci		spin_unlock_irqrestore(&vp_dev->lock, flags);
19962306a36Sopenharmony_ci	} else {
20062306a36Sopenharmony_ci		INIT_LIST_HEAD(&info->node);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	vp_dev->vqs[index] = info;
20462306a36Sopenharmony_ci	return vq;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciout_info:
20762306a36Sopenharmony_ci	kfree(info);
20862306a36Sopenharmony_ci	return vq;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic void vp_del_vq(struct virtqueue *vq)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
21462306a36Sopenharmony_ci	struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
21562306a36Sopenharmony_ci	unsigned long flags;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/*
21862306a36Sopenharmony_ci	 * If it fails during re-enable reset vq. This way we won't rejoin
21962306a36Sopenharmony_ci	 * info->node to the queue. Prevent unexpected irqs.
22062306a36Sopenharmony_ci	 */
22162306a36Sopenharmony_ci	if (!vq->reset) {
22262306a36Sopenharmony_ci		spin_lock_irqsave(&vp_dev->lock, flags);
22362306a36Sopenharmony_ci		list_del(&info->node);
22462306a36Sopenharmony_ci		spin_unlock_irqrestore(&vp_dev->lock, flags);
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	vp_dev->del_vq(info);
22862306a36Sopenharmony_ci	kfree(info);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/* the config->del_vqs() implementation */
23262306a36Sopenharmony_civoid vp_del_vqs(struct virtio_device *vdev)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
23562306a36Sopenharmony_ci	struct virtqueue *vq, *n;
23662306a36Sopenharmony_ci	int i;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
23962306a36Sopenharmony_ci		if (vp_dev->per_vq_vectors) {
24062306a36Sopenharmony_ci			int v = vp_dev->vqs[vq->index]->msix_vector;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci			if (v != VIRTIO_MSI_NO_VECTOR) {
24362306a36Sopenharmony_ci				int irq = pci_irq_vector(vp_dev->pci_dev, v);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci				irq_set_affinity_hint(irq, NULL);
24662306a36Sopenharmony_ci				free_irq(irq, vq);
24762306a36Sopenharmony_ci			}
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci		vp_del_vq(vq);
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci	vp_dev->per_vq_vectors = false;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (vp_dev->intx_enabled) {
25462306a36Sopenharmony_ci		free_irq(vp_dev->pci_dev->irq, vp_dev);
25562306a36Sopenharmony_ci		vp_dev->intx_enabled = 0;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	for (i = 0; i < vp_dev->msix_used_vectors; ++i)
25962306a36Sopenharmony_ci		free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (vp_dev->msix_affinity_masks) {
26262306a36Sopenharmony_ci		for (i = 0; i < vp_dev->msix_vectors; i++)
26362306a36Sopenharmony_ci			free_cpumask_var(vp_dev->msix_affinity_masks[i]);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (vp_dev->msix_enabled) {
26762306a36Sopenharmony_ci		/* Disable the vector used for configuration */
26862306a36Sopenharmony_ci		vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		pci_free_irq_vectors(vp_dev->pci_dev);
27162306a36Sopenharmony_ci		vp_dev->msix_enabled = 0;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	vp_dev->msix_vectors = 0;
27562306a36Sopenharmony_ci	vp_dev->msix_used_vectors = 0;
27662306a36Sopenharmony_ci	kfree(vp_dev->msix_names);
27762306a36Sopenharmony_ci	vp_dev->msix_names = NULL;
27862306a36Sopenharmony_ci	kfree(vp_dev->msix_affinity_masks);
27962306a36Sopenharmony_ci	vp_dev->msix_affinity_masks = NULL;
28062306a36Sopenharmony_ci	kfree(vp_dev->vqs);
28162306a36Sopenharmony_ci	vp_dev->vqs = NULL;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
28562306a36Sopenharmony_ci		struct virtqueue *vqs[], vq_callback_t *callbacks[],
28662306a36Sopenharmony_ci		const char * const names[], bool per_vq_vectors,
28762306a36Sopenharmony_ci		const bool *ctx,
28862306a36Sopenharmony_ci		struct irq_affinity *desc)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
29162306a36Sopenharmony_ci	u16 msix_vec;
29262306a36Sopenharmony_ci	int i, err, nvectors, allocated_vectors, queue_idx = 0;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
29562306a36Sopenharmony_ci	if (!vp_dev->vqs)
29662306a36Sopenharmony_ci		return -ENOMEM;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (per_vq_vectors) {
29962306a36Sopenharmony_ci		/* Best option: one for change interrupt, one per vq. */
30062306a36Sopenharmony_ci		nvectors = 1;
30162306a36Sopenharmony_ci		for (i = 0; i < nvqs; ++i)
30262306a36Sopenharmony_ci			if (names[i] && callbacks[i])
30362306a36Sopenharmony_ci				++nvectors;
30462306a36Sopenharmony_ci	} else {
30562306a36Sopenharmony_ci		/* Second best: one for change, shared for all vqs. */
30662306a36Sopenharmony_ci		nvectors = 2;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors,
31062306a36Sopenharmony_ci				      per_vq_vectors ? desc : NULL);
31162306a36Sopenharmony_ci	if (err)
31262306a36Sopenharmony_ci		goto error_find;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	vp_dev->per_vq_vectors = per_vq_vectors;
31562306a36Sopenharmony_ci	allocated_vectors = vp_dev->msix_used_vectors;
31662306a36Sopenharmony_ci	for (i = 0; i < nvqs; ++i) {
31762306a36Sopenharmony_ci		if (!names[i]) {
31862306a36Sopenharmony_ci			vqs[i] = NULL;
31962306a36Sopenharmony_ci			continue;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		if (!callbacks[i])
32362306a36Sopenharmony_ci			msix_vec = VIRTIO_MSI_NO_VECTOR;
32462306a36Sopenharmony_ci		else if (vp_dev->per_vq_vectors)
32562306a36Sopenharmony_ci			msix_vec = allocated_vectors++;
32662306a36Sopenharmony_ci		else
32762306a36Sopenharmony_ci			msix_vec = VP_MSIX_VQ_VECTOR;
32862306a36Sopenharmony_ci		vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
32962306a36Sopenharmony_ci				     ctx ? ctx[i] : false,
33062306a36Sopenharmony_ci				     msix_vec);
33162306a36Sopenharmony_ci		if (IS_ERR(vqs[i])) {
33262306a36Sopenharmony_ci			err = PTR_ERR(vqs[i]);
33362306a36Sopenharmony_ci			goto error_find;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
33762306a36Sopenharmony_ci			continue;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		/* allocate per-vq irq if available and necessary */
34062306a36Sopenharmony_ci		snprintf(vp_dev->msix_names[msix_vec],
34162306a36Sopenharmony_ci			 sizeof *vp_dev->msix_names,
34262306a36Sopenharmony_ci			 "%s-%s",
34362306a36Sopenharmony_ci			 dev_name(&vp_dev->vdev.dev), names[i]);
34462306a36Sopenharmony_ci		err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec),
34562306a36Sopenharmony_ci				  vring_interrupt, 0,
34662306a36Sopenharmony_ci				  vp_dev->msix_names[msix_vec],
34762306a36Sopenharmony_ci				  vqs[i]);
34862306a36Sopenharmony_ci		if (err)
34962306a36Sopenharmony_ci			goto error_find;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cierror_find:
35462306a36Sopenharmony_ci	vp_del_vqs(vdev);
35562306a36Sopenharmony_ci	return err;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
35962306a36Sopenharmony_ci		struct virtqueue *vqs[], vq_callback_t *callbacks[],
36062306a36Sopenharmony_ci		const char * const names[], const bool *ctx)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
36362306a36Sopenharmony_ci	int i, err, queue_idx = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
36662306a36Sopenharmony_ci	if (!vp_dev->vqs)
36762306a36Sopenharmony_ci		return -ENOMEM;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
37062306a36Sopenharmony_ci			dev_name(&vdev->dev), vp_dev);
37162306a36Sopenharmony_ci	if (err)
37262306a36Sopenharmony_ci		goto out_del_vqs;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	vp_dev->intx_enabled = 1;
37562306a36Sopenharmony_ci	vp_dev->per_vq_vectors = false;
37662306a36Sopenharmony_ci	for (i = 0; i < nvqs; ++i) {
37762306a36Sopenharmony_ci		if (!names[i]) {
37862306a36Sopenharmony_ci			vqs[i] = NULL;
37962306a36Sopenharmony_ci			continue;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci		vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
38262306a36Sopenharmony_ci				     ctx ? ctx[i] : false,
38362306a36Sopenharmony_ci				     VIRTIO_MSI_NO_VECTOR);
38462306a36Sopenharmony_ci		if (IS_ERR(vqs[i])) {
38562306a36Sopenharmony_ci			err = PTR_ERR(vqs[i]);
38662306a36Sopenharmony_ci			goto out_del_vqs;
38762306a36Sopenharmony_ci		}
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ciout_del_vqs:
39262306a36Sopenharmony_ci	vp_del_vqs(vdev);
39362306a36Sopenharmony_ci	return err;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* the config->find_vqs() implementation */
39762306a36Sopenharmony_ciint vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
39862306a36Sopenharmony_ci		struct virtqueue *vqs[], vq_callback_t *callbacks[],
39962306a36Sopenharmony_ci		const char * const names[], const bool *ctx,
40062306a36Sopenharmony_ci		struct irq_affinity *desc)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	int err;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* Try MSI-X with one vector per queue. */
40562306a36Sopenharmony_ci	err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc);
40662306a36Sopenharmony_ci	if (!err)
40762306a36Sopenharmony_ci		return 0;
40862306a36Sopenharmony_ci	/* Fallback: MSI-X with one vector for config, one shared for queues. */
40962306a36Sopenharmony_ci	err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc);
41062306a36Sopenharmony_ci	if (!err)
41162306a36Sopenharmony_ci		return 0;
41262306a36Sopenharmony_ci	/* Is there an interrupt? If not give up. */
41362306a36Sopenharmony_ci	if (!(to_vp_device(vdev)->pci_dev->irq))
41462306a36Sopenharmony_ci		return err;
41562306a36Sopenharmony_ci	/* Finally fall back to regular interrupts. */
41662306a36Sopenharmony_ci	return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciconst char *vp_bus_name(struct virtio_device *vdev)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return pci_name(vp_dev->pci_dev);
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci/* Setup the affinity for a virtqueue:
42762306a36Sopenharmony_ci * - force the affinity for per vq vector
42862306a36Sopenharmony_ci * - OR over all affinities for shared MSI
42962306a36Sopenharmony_ci * - ignore the affinity request if we're using INTX
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_ciint vp_set_vq_affinity(struct virtqueue *vq, const struct cpumask *cpu_mask)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct virtio_device *vdev = vq->vdev;
43462306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
43562306a36Sopenharmony_ci	struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
43662306a36Sopenharmony_ci	struct cpumask *mask;
43762306a36Sopenharmony_ci	unsigned int irq;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (!vq->callback)
44062306a36Sopenharmony_ci		return -EINVAL;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (vp_dev->msix_enabled) {
44362306a36Sopenharmony_ci		mask = vp_dev->msix_affinity_masks[info->msix_vector];
44462306a36Sopenharmony_ci		irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector);
44562306a36Sopenharmony_ci		if (!cpu_mask)
44662306a36Sopenharmony_ci			irq_set_affinity_hint(irq, NULL);
44762306a36Sopenharmony_ci		else {
44862306a36Sopenharmony_ci			cpumask_copy(mask, cpu_mask);
44962306a36Sopenharmony_ci			irq_set_affinity_hint(irq, mask);
45062306a36Sopenharmony_ci		}
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ciconst struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (!vp_dev->per_vq_vectors ||
46062306a36Sopenharmony_ci	    vp_dev->vqs[index]->msix_vector == VIRTIO_MSI_NO_VECTOR)
46162306a36Sopenharmony_ci		return NULL;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return pci_irq_get_affinity(vp_dev->pci_dev,
46462306a36Sopenharmony_ci				    vp_dev->vqs[index]->msix_vector);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
46862306a36Sopenharmony_cistatic int virtio_pci_freeze(struct device *dev)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
47162306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
47262306a36Sopenharmony_ci	int ret;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	ret = virtio_device_freeze(&vp_dev->vdev);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (!ret)
47762306a36Sopenharmony_ci		pci_disable_device(pci_dev);
47862306a36Sopenharmony_ci	return ret;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int virtio_pci_restore(struct device *dev)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
48462306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
48562306a36Sopenharmony_ci	int ret;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	ret = pci_enable_device(pci_dev);
48862306a36Sopenharmony_ci	if (ret)
48962306a36Sopenharmony_ci		return ret;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	pci_set_master(pci_dev);
49262306a36Sopenharmony_ci	return virtio_device_restore(&vp_dev->vdev);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic const struct dev_pm_ops virtio_pci_pm_ops = {
49662306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
49762306a36Sopenharmony_ci};
49862306a36Sopenharmony_ci#endif
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
50262306a36Sopenharmony_cistatic const struct pci_device_id virtio_pci_id_table[] = {
50362306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) },
50462306a36Sopenharmony_ci	{ 0 }
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic void virtio_pci_release_dev(struct device *_d)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct virtio_device *vdev = dev_to_virtio(_d);
51262306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* As struct device is a kobject, it's not safe to
51562306a36Sopenharmony_ci	 * free the memory (including the reference counter itself)
51662306a36Sopenharmony_ci	 * until it's release callback. */
51762306a36Sopenharmony_ci	kfree(vp_dev);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int virtio_pci_probe(struct pci_dev *pci_dev,
52162306a36Sopenharmony_ci			    const struct pci_device_id *id)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev, *reg_dev = NULL;
52462306a36Sopenharmony_ci	int rc;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	/* allocate our structure and fill it out */
52762306a36Sopenharmony_ci	vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
52862306a36Sopenharmony_ci	if (!vp_dev)
52962306a36Sopenharmony_ci		return -ENOMEM;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	pci_set_drvdata(pci_dev, vp_dev);
53262306a36Sopenharmony_ci	vp_dev->vdev.dev.parent = &pci_dev->dev;
53362306a36Sopenharmony_ci	vp_dev->vdev.dev.release = virtio_pci_release_dev;
53462306a36Sopenharmony_ci	vp_dev->pci_dev = pci_dev;
53562306a36Sopenharmony_ci	INIT_LIST_HEAD(&vp_dev->virtqueues);
53662306a36Sopenharmony_ci	spin_lock_init(&vp_dev->lock);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* enable the device */
53962306a36Sopenharmony_ci	rc = pci_enable_device(pci_dev);
54062306a36Sopenharmony_ci	if (rc)
54162306a36Sopenharmony_ci		goto err_enable_device;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (force_legacy) {
54462306a36Sopenharmony_ci		rc = virtio_pci_legacy_probe(vp_dev);
54562306a36Sopenharmony_ci		/* Also try modern mode if we can't map BAR0 (no IO space). */
54662306a36Sopenharmony_ci		if (rc == -ENODEV || rc == -ENOMEM)
54762306a36Sopenharmony_ci			rc = virtio_pci_modern_probe(vp_dev);
54862306a36Sopenharmony_ci		if (rc)
54962306a36Sopenharmony_ci			goto err_probe;
55062306a36Sopenharmony_ci	} else {
55162306a36Sopenharmony_ci		rc = virtio_pci_modern_probe(vp_dev);
55262306a36Sopenharmony_ci		if (rc == -ENODEV)
55362306a36Sopenharmony_ci			rc = virtio_pci_legacy_probe(vp_dev);
55462306a36Sopenharmony_ci		if (rc)
55562306a36Sopenharmony_ci			goto err_probe;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	pci_set_master(pci_dev);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	rc = register_virtio_device(&vp_dev->vdev);
56162306a36Sopenharmony_ci	reg_dev = vp_dev;
56262306a36Sopenharmony_ci	if (rc)
56362306a36Sopenharmony_ci		goto err_register;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return 0;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cierr_register:
56862306a36Sopenharmony_ci	if (vp_dev->is_legacy)
56962306a36Sopenharmony_ci		virtio_pci_legacy_remove(vp_dev);
57062306a36Sopenharmony_ci	else
57162306a36Sopenharmony_ci		virtio_pci_modern_remove(vp_dev);
57262306a36Sopenharmony_cierr_probe:
57362306a36Sopenharmony_ci	pci_disable_device(pci_dev);
57462306a36Sopenharmony_cierr_enable_device:
57562306a36Sopenharmony_ci	if (reg_dev)
57662306a36Sopenharmony_ci		put_device(&vp_dev->vdev.dev);
57762306a36Sopenharmony_ci	else
57862306a36Sopenharmony_ci		kfree(vp_dev);
57962306a36Sopenharmony_ci	return rc;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void virtio_pci_remove(struct pci_dev *pci_dev)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
58562306a36Sopenharmony_ci	struct device *dev = get_device(&vp_dev->vdev.dev);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/*
58862306a36Sopenharmony_ci	 * Device is marked broken on surprise removal so that virtio upper
58962306a36Sopenharmony_ci	 * layers can abort any ongoing operation.
59062306a36Sopenharmony_ci	 */
59162306a36Sopenharmony_ci	if (!pci_device_is_present(pci_dev))
59262306a36Sopenharmony_ci		virtio_break_device(&vp_dev->vdev);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	pci_disable_sriov(pci_dev);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	unregister_virtio_device(&vp_dev->vdev);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (vp_dev->is_legacy)
59962306a36Sopenharmony_ci		virtio_pci_legacy_remove(vp_dev);
60062306a36Sopenharmony_ci	else
60162306a36Sopenharmony_ci		virtio_pci_modern_remove(vp_dev);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	pci_disable_device(pci_dev);
60462306a36Sopenharmony_ci	put_device(dev);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
61062306a36Sopenharmony_ci	struct virtio_device *vdev = &vp_dev->vdev;
61162306a36Sopenharmony_ci	int ret;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK))
61462306a36Sopenharmony_ci		return -EBUSY;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV))
61762306a36Sopenharmony_ci		return -EINVAL;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (pci_vfs_assigned(pci_dev))
62062306a36Sopenharmony_ci		return -EPERM;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (num_vfs == 0) {
62362306a36Sopenharmony_ci		pci_disable_sriov(pci_dev);
62462306a36Sopenharmony_ci		return 0;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	ret = pci_enable_sriov(pci_dev, num_vfs);
62862306a36Sopenharmony_ci	if (ret < 0)
62962306a36Sopenharmony_ci		return ret;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return num_vfs;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic struct pci_driver virtio_pci_driver = {
63562306a36Sopenharmony_ci	.name		= "virtio-pci",
63662306a36Sopenharmony_ci	.id_table	= virtio_pci_id_table,
63762306a36Sopenharmony_ci	.probe		= virtio_pci_probe,
63862306a36Sopenharmony_ci	.remove		= virtio_pci_remove,
63962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
64062306a36Sopenharmony_ci	.driver.pm	= &virtio_pci_pm_ops,
64162306a36Sopenharmony_ci#endif
64262306a36Sopenharmony_ci	.sriov_configure = virtio_pci_sriov_configure,
64362306a36Sopenharmony_ci};
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cimodule_pci_driver(virtio_pci_driver);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ciMODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>");
64862306a36Sopenharmony_ciMODULE_DESCRIPTION("virtio-pci");
64962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
65062306a36Sopenharmony_ciMODULE_VERSION("1");
651