xref: /openbmc/linux/drivers/vdpa/ifcvf/ifcvf_main.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c9b9f5f8SMichael S. Tsirkin // SPDX-License-Identifier: GPL-2.0-only
2c9b9f5f8SMichael S. Tsirkin /*
3c9b9f5f8SMichael S. Tsirkin  * Intel IFC VF NIC driver for virtio dataplane offloading
4c9b9f5f8SMichael S. Tsirkin  *
5c9b9f5f8SMichael S. Tsirkin  * Copyright (C) 2020 Intel Corporation.
6c9b9f5f8SMichael S. Tsirkin  *
7c9b9f5f8SMichael S. Tsirkin  * Author: Zhu Lingshan <lingshan.zhu@intel.com>
8c9b9f5f8SMichael S. Tsirkin  *
9c9b9f5f8SMichael S. Tsirkin  */
10c9b9f5f8SMichael S. Tsirkin 
11c9b9f5f8SMichael S. Tsirkin #include <linux/interrupt.h>
12c9b9f5f8SMichael S. Tsirkin #include <linux/module.h>
13c9b9f5f8SMichael S. Tsirkin #include <linux/pci.h>
14c9b9f5f8SMichael S. Tsirkin #include <linux/sysfs.h>
15c9b9f5f8SMichael S. Tsirkin #include "ifcvf_base.h"
16c9b9f5f8SMichael S. Tsirkin 
17c9b9f5f8SMichael S. Tsirkin #define DRIVER_AUTHOR   "Intel Corporation"
18c9b9f5f8SMichael S. Tsirkin #define IFCVF_DRIVER_NAME       "ifcvf"
19c9b9f5f8SMichael S. Tsirkin 
ifcvf_config_changed(int irq,void * arg)20e7991f37SZhu Lingshan static irqreturn_t ifcvf_config_changed(int irq, void *arg)
21e7991f37SZhu Lingshan {
22e7991f37SZhu Lingshan 	struct ifcvf_hw *vf = arg;
23e7991f37SZhu Lingshan 
24e7991f37SZhu Lingshan 	if (vf->config_cb.callback)
25e7991f37SZhu Lingshan 		return vf->config_cb.callback(vf->config_cb.private);
26e7991f37SZhu Lingshan 
27e7991f37SZhu Lingshan 	return IRQ_HANDLED;
28e7991f37SZhu Lingshan }
29e7991f37SZhu Lingshan 
ifcvf_vq_intr_handler(int irq,void * arg)309b3e8148SZhu Lingshan static irqreturn_t ifcvf_vq_intr_handler(int irq, void *arg)
31c9b9f5f8SMichael S. Tsirkin {
32c9b9f5f8SMichael S. Tsirkin 	struct vring_info *vring = arg;
33c9b9f5f8SMichael S. Tsirkin 
34c9b9f5f8SMichael S. Tsirkin 	if (vring->cb.callback)
35c9b9f5f8SMichael S. Tsirkin 		return vring->cb.callback(vring->cb.private);
36c9b9f5f8SMichael S. Tsirkin 
37c9b9f5f8SMichael S. Tsirkin 	return IRQ_HANDLED;
38c9b9f5f8SMichael S. Tsirkin }
39c9b9f5f8SMichael S. Tsirkin 
ifcvf_vqs_reused_intr_handler(int irq,void * arg)409b3e8148SZhu Lingshan static irqreturn_t ifcvf_vqs_reused_intr_handler(int irq, void *arg)
419b3e8148SZhu Lingshan {
429b3e8148SZhu Lingshan 	struct ifcvf_hw *vf = arg;
439b3e8148SZhu Lingshan 	struct vring_info *vring;
449b3e8148SZhu Lingshan 	int i;
459b3e8148SZhu Lingshan 
469b3e8148SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++) {
479b3e8148SZhu Lingshan 		vring = &vf->vring[i];
489b3e8148SZhu Lingshan 		if (vring->cb.callback)
499b3e8148SZhu Lingshan 			vring->cb.callback(vring->cb.private);
509b3e8148SZhu Lingshan 	}
519b3e8148SZhu Lingshan 
529b3e8148SZhu Lingshan 	return IRQ_HANDLED;
539b3e8148SZhu Lingshan }
549b3e8148SZhu Lingshan 
ifcvf_dev_intr_handler(int irq,void * arg)559b3e8148SZhu Lingshan static irqreturn_t ifcvf_dev_intr_handler(int irq, void *arg)
569b3e8148SZhu Lingshan {
579b3e8148SZhu Lingshan 	struct ifcvf_hw *vf = arg;
589b3e8148SZhu Lingshan 	u8 isr;
599b3e8148SZhu Lingshan 
609b3e8148SZhu Lingshan 	isr = vp_ioread8(vf->isr);
619b3e8148SZhu Lingshan 	if (isr & VIRTIO_PCI_ISR_CONFIG)
629b3e8148SZhu Lingshan 		ifcvf_config_changed(irq, arg);
639b3e8148SZhu Lingshan 
649b3e8148SZhu Lingshan 	return ifcvf_vqs_reused_intr_handler(irq, arg);
659b3e8148SZhu Lingshan }
669b3e8148SZhu Lingshan 
ifcvf_free_irq_vectors(void * data)677dd793f3SZhu Lingshan static void ifcvf_free_irq_vectors(void *data)
687dd793f3SZhu Lingshan {
697dd793f3SZhu Lingshan 	pci_free_irq_vectors(data);
707dd793f3SZhu Lingshan }
717dd793f3SZhu Lingshan 
ifcvf_free_per_vq_irq(struct ifcvf_hw * vf)72004cbcabSZhu Lingshan static void ifcvf_free_per_vq_irq(struct ifcvf_hw *vf)
737dd793f3SZhu Lingshan {
74004cbcabSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
757dd793f3SZhu Lingshan 	int i;
767dd793f3SZhu Lingshan 
779b3e8148SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++) {
789b3e8148SZhu Lingshan 		if (vf->vring[i].irq != -EINVAL) {
797dd793f3SZhu Lingshan 			devm_free_irq(&pdev->dev, vf->vring[i].irq, &vf->vring[i]);
803597a2fbSZhu Lingshan 			vf->vring[i].irq = -EINVAL;
813597a2fbSZhu Lingshan 		}
829b3e8148SZhu Lingshan 	}
839b3e8148SZhu Lingshan }
847dd793f3SZhu Lingshan 
ifcvf_free_vqs_reused_irq(struct ifcvf_hw * vf)85004cbcabSZhu Lingshan static void ifcvf_free_vqs_reused_irq(struct ifcvf_hw *vf)
869b3e8148SZhu Lingshan {
87004cbcabSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
889b3e8148SZhu Lingshan 
899b3e8148SZhu Lingshan 	if (vf->vqs_reused_irq != -EINVAL) {
909b3e8148SZhu Lingshan 		devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf);
919b3e8148SZhu Lingshan 		vf->vqs_reused_irq = -EINVAL;
929b3e8148SZhu Lingshan 	}
939b3e8148SZhu Lingshan 
949b3e8148SZhu Lingshan }
959b3e8148SZhu Lingshan 
ifcvf_free_vq_irq(struct ifcvf_hw * vf)96004cbcabSZhu Lingshan static void ifcvf_free_vq_irq(struct ifcvf_hw *vf)
979b3e8148SZhu Lingshan {
989b3e8148SZhu Lingshan 	if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
99004cbcabSZhu Lingshan 		ifcvf_free_per_vq_irq(vf);
1009b3e8148SZhu Lingshan 	else
101004cbcabSZhu Lingshan 		ifcvf_free_vqs_reused_irq(vf);
1029b3e8148SZhu Lingshan }
1039b3e8148SZhu Lingshan 
ifcvf_free_config_irq(struct ifcvf_hw * vf)10423dac55cSZhu Lingshan static void ifcvf_free_config_irq(struct ifcvf_hw *vf)
1059b3e8148SZhu Lingshan {
10623dac55cSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
1079b3e8148SZhu Lingshan 
1089b3e8148SZhu Lingshan 	if (vf->config_irq == -EINVAL)
1099b3e8148SZhu Lingshan 		return;
1109b3e8148SZhu Lingshan 
1119b3e8148SZhu Lingshan 	/* If the irq is shared by all vqs and the config interrupt,
1129b3e8148SZhu Lingshan 	 * it is already freed in ifcvf_free_vq_irq, so here only
1139b3e8148SZhu Lingshan 	 * need to free config irq when msix_vector_status != MSIX_VECTOR_DEV_SHARED
1149b3e8148SZhu Lingshan 	 */
1159b3e8148SZhu Lingshan 	if (vf->msix_vector_status != MSIX_VECTOR_DEV_SHARED) {
1162b9f28d5SJason Wang 		devm_free_irq(&pdev->dev, vf->config_irq, vf);
1179b3e8148SZhu Lingshan 		vf->config_irq = -EINVAL;
1189b3e8148SZhu Lingshan 	}
1199b3e8148SZhu Lingshan }
1209b3e8148SZhu Lingshan 
ifcvf_free_irq(struct ifcvf_hw * vf)12123dac55cSZhu Lingshan static void ifcvf_free_irq(struct ifcvf_hw *vf)
1229b3e8148SZhu Lingshan {
12323dac55cSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
1249b3e8148SZhu Lingshan 
125004cbcabSZhu Lingshan 	ifcvf_free_vq_irq(vf);
12623dac55cSZhu Lingshan 	ifcvf_free_config_irq(vf);
1277dd793f3SZhu Lingshan 	ifcvf_free_irq_vectors(pdev);
128386a2620SZhu Lingshan 	vf->num_msix_vectors = 0;
1297dd793f3SZhu Lingshan }
1307dd793f3SZhu Lingshan 
131ad5c5690SZhu Lingshan /* ifcvf MSIX vectors allocator, this helper tries to allocate
132ad5c5690SZhu Lingshan  * vectors for all virtqueues and the config interrupt.
133ad5c5690SZhu Lingshan  * It returns the number of allocated vectors, negative
134ad5c5690SZhu Lingshan  * return value when fails.
135ad5c5690SZhu Lingshan  */
ifcvf_alloc_vectors(struct ifcvf_hw * vf)136a70d833eSZhu Lingshan static int ifcvf_alloc_vectors(struct ifcvf_hw *vf)
1377dd793f3SZhu Lingshan {
138a70d833eSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
139ad5c5690SZhu Lingshan 	int max_intr, ret;
1407dd793f3SZhu Lingshan 
1412ddae773SZhu Lingshan 	/* all queues and config interrupt  */
1422ddae773SZhu Lingshan 	max_intr = vf->nr_vring + 1;
143ad5c5690SZhu Lingshan 	ret = pci_alloc_irq_vectors(pdev, 1, max_intr, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
1442ddae773SZhu Lingshan 
1457dd793f3SZhu Lingshan 	if (ret < 0) {
1467dd793f3SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to alloc IRQ vectors\n");
1477dd793f3SZhu Lingshan 		return ret;
1487dd793f3SZhu Lingshan 	}
1497dd793f3SZhu Lingshan 
150ad5c5690SZhu Lingshan 	if (ret < max_intr)
151ad5c5690SZhu Lingshan 		IFCVF_INFO(pdev,
152ad5c5690SZhu Lingshan 			   "Requested %u vectors, however only %u allocated, lower performance\n",
153ad5c5690SZhu Lingshan 			   max_intr, ret);
154ad5c5690SZhu Lingshan 
155ad5c5690SZhu Lingshan 	return ret;
156ad5c5690SZhu Lingshan }
157ad5c5690SZhu Lingshan 
ifcvf_request_per_vq_irq(struct ifcvf_hw * vf)158f9a9ffb2SZhu Lingshan static int ifcvf_request_per_vq_irq(struct ifcvf_hw *vf)
159ad5c5690SZhu Lingshan {
160f9a9ffb2SZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
1619b3e8148SZhu Lingshan 	int i, vector, ret, irq;
162ad5c5690SZhu Lingshan 
1639b3e8148SZhu Lingshan 	vf->vqs_reused_irq = -EINVAL;
1649b3e8148SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++) {
1659b3e8148SZhu Lingshan 		snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n", pci_name(pdev), i);
1669b3e8148SZhu Lingshan 		vector = i;
1679b3e8148SZhu Lingshan 		irq = pci_irq_vector(pdev, vector);
1689b3e8148SZhu Lingshan 		ret = devm_request_irq(&pdev->dev, irq,
1699b3e8148SZhu Lingshan 				       ifcvf_vq_intr_handler, 0,
1709b3e8148SZhu Lingshan 				       vf->vring[i].msix_name,
1719b3e8148SZhu Lingshan 				       &vf->vring[i]);
1729b3e8148SZhu Lingshan 		if (ret) {
1739b3e8148SZhu Lingshan 			IFCVF_ERR(pdev, "Failed to request irq for vq %d\n", i);
1749b3e8148SZhu Lingshan 			goto err;
1759b3e8148SZhu Lingshan 		}
1769b3e8148SZhu Lingshan 
1779b3e8148SZhu Lingshan 		vf->vring[i].irq = irq;
1789b3e8148SZhu Lingshan 		ret = ifcvf_set_vq_vector(vf, i, vector);
1799b3e8148SZhu Lingshan 		if (ret == VIRTIO_MSI_NO_VECTOR) {
1809b3e8148SZhu Lingshan 			IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
1819b3e8148SZhu Lingshan 			goto err;
1829b3e8148SZhu Lingshan 		}
1839b3e8148SZhu Lingshan 	}
1849b3e8148SZhu Lingshan 
1859b3e8148SZhu Lingshan 	return 0;
1869b3e8148SZhu Lingshan err:
18723dac55cSZhu Lingshan 	ifcvf_free_irq(vf);
1889b3e8148SZhu Lingshan 
189ad5c5690SZhu Lingshan 	return -EFAULT;
1909b3e8148SZhu Lingshan }
1919b3e8148SZhu Lingshan 
ifcvf_request_vqs_reused_irq(struct ifcvf_hw * vf)192f9a9ffb2SZhu Lingshan static int ifcvf_request_vqs_reused_irq(struct ifcvf_hw *vf)
1939b3e8148SZhu Lingshan {
194f9a9ffb2SZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
1959b3e8148SZhu Lingshan 	int i, vector, ret, irq;
1969b3e8148SZhu Lingshan 
1979b3e8148SZhu Lingshan 	vector = 0;
1989b3e8148SZhu Lingshan 	snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-vqs-reused-irq\n", pci_name(pdev));
1999b3e8148SZhu Lingshan 	irq = pci_irq_vector(pdev, vector);
2009b3e8148SZhu Lingshan 	ret = devm_request_irq(&pdev->dev, irq,
2019b3e8148SZhu Lingshan 			       ifcvf_vqs_reused_intr_handler, 0,
2029b3e8148SZhu Lingshan 			       vf->vring[0].msix_name, vf);
2039b3e8148SZhu Lingshan 	if (ret) {
2049b3e8148SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to request reused irq for the device\n");
2059b3e8148SZhu Lingshan 		goto err;
2069b3e8148SZhu Lingshan 	}
2079b3e8148SZhu Lingshan 
2089b3e8148SZhu Lingshan 	vf->vqs_reused_irq = irq;
2099b3e8148SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++) {
2109b3e8148SZhu Lingshan 		vf->vring[i].irq = -EINVAL;
2119b3e8148SZhu Lingshan 		ret = ifcvf_set_vq_vector(vf, i, vector);
2129b3e8148SZhu Lingshan 		if (ret == VIRTIO_MSI_NO_VECTOR) {
2139b3e8148SZhu Lingshan 			IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
2149b3e8148SZhu Lingshan 			goto err;
2159b3e8148SZhu Lingshan 		}
2169b3e8148SZhu Lingshan 	}
2179b3e8148SZhu Lingshan 
2189b3e8148SZhu Lingshan 	return 0;
2199b3e8148SZhu Lingshan err:
22023dac55cSZhu Lingshan 	ifcvf_free_irq(vf);
2219b3e8148SZhu Lingshan 
2229b3e8148SZhu Lingshan 	return -EFAULT;
2239b3e8148SZhu Lingshan }
2249b3e8148SZhu Lingshan 
ifcvf_request_dev_irq(struct ifcvf_hw * vf)225a70d833eSZhu Lingshan static int ifcvf_request_dev_irq(struct ifcvf_hw *vf)
2269b3e8148SZhu Lingshan {
227a70d833eSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
2289b3e8148SZhu Lingshan 	int i, vector, ret, irq;
2299b3e8148SZhu Lingshan 
2309b3e8148SZhu Lingshan 	vector = 0;
2319b3e8148SZhu Lingshan 	snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-dev-irq\n", pci_name(pdev));
2329b3e8148SZhu Lingshan 	irq = pci_irq_vector(pdev, vector);
2339b3e8148SZhu Lingshan 	ret = devm_request_irq(&pdev->dev, irq,
2349b3e8148SZhu Lingshan 			       ifcvf_dev_intr_handler, 0,
2359b3e8148SZhu Lingshan 			       vf->vring[0].msix_name, vf);
2369b3e8148SZhu Lingshan 	if (ret) {
2379b3e8148SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to request irq for the device\n");
2389b3e8148SZhu Lingshan 		goto err;
2399b3e8148SZhu Lingshan 	}
2409b3e8148SZhu Lingshan 
2419b3e8148SZhu Lingshan 	vf->vqs_reused_irq = irq;
2429b3e8148SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++) {
2439b3e8148SZhu Lingshan 		vf->vring[i].irq = -EINVAL;
2449b3e8148SZhu Lingshan 		ret = ifcvf_set_vq_vector(vf, i, vector);
2459b3e8148SZhu Lingshan 		if (ret == VIRTIO_MSI_NO_VECTOR) {
2469b3e8148SZhu Lingshan 			IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
2479b3e8148SZhu Lingshan 			goto err;
2489b3e8148SZhu Lingshan 		}
2499b3e8148SZhu Lingshan 	}
2509b3e8148SZhu Lingshan 
2519b3e8148SZhu Lingshan 	vf->config_irq = irq;
2529b3e8148SZhu Lingshan 	ret = ifcvf_set_config_vector(vf, vector);
2539b3e8148SZhu Lingshan 	if (ret == VIRTIO_MSI_NO_VECTOR) {
2549b3e8148SZhu Lingshan 		IFCVF_ERR(pdev, "No msix vector for device config\n");
2559b3e8148SZhu Lingshan 		goto err;
2569b3e8148SZhu Lingshan 	}
2579b3e8148SZhu Lingshan 
2589b3e8148SZhu Lingshan 	return 0;
2599b3e8148SZhu Lingshan err:
26023dac55cSZhu Lingshan 	ifcvf_free_irq(vf);
2619b3e8148SZhu Lingshan 
2629b3e8148SZhu Lingshan 	return -EFAULT;
2639b3e8148SZhu Lingshan 
2649b3e8148SZhu Lingshan }
2659b3e8148SZhu Lingshan 
ifcvf_request_vq_irq(struct ifcvf_hw * vf)266f9a9ffb2SZhu Lingshan static int ifcvf_request_vq_irq(struct ifcvf_hw *vf)
2679b3e8148SZhu Lingshan {
2689b3e8148SZhu Lingshan 	int ret;
2699b3e8148SZhu Lingshan 
2709b3e8148SZhu Lingshan 	if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
271f9a9ffb2SZhu Lingshan 		ret = ifcvf_request_per_vq_irq(vf);
2729b3e8148SZhu Lingshan 	else
273f9a9ffb2SZhu Lingshan 		ret = ifcvf_request_vqs_reused_irq(vf);
2749b3e8148SZhu Lingshan 
2759b3e8148SZhu Lingshan 	return ret;
2769b3e8148SZhu Lingshan }
2779b3e8148SZhu Lingshan 
ifcvf_request_config_irq(struct ifcvf_hw * vf)278a70d833eSZhu Lingshan static int ifcvf_request_config_irq(struct ifcvf_hw *vf)
2799b3e8148SZhu Lingshan {
280a70d833eSZhu Lingshan 	struct pci_dev *pdev = vf->pdev;
2819b3e8148SZhu Lingshan 	int config_vector, ret;
2829b3e8148SZhu Lingshan 
2839b3e8148SZhu Lingshan 	if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
2849b3e8148SZhu Lingshan 		config_vector = vf->nr_vring;
285ac33f84bSZhu Lingshan 	else if (vf->msix_vector_status ==  MSIX_VECTOR_SHARED_VQ_AND_CONFIG)
2869b3e8148SZhu Lingshan 		/* vector 0 for vqs and 1 for config interrupt */
2879b3e8148SZhu Lingshan 		config_vector = 1;
288ac33f84bSZhu Lingshan 	else if (vf->msix_vector_status == MSIX_VECTOR_DEV_SHARED)
289ac33f84bSZhu Lingshan 		/* re-use the vqs vector */
290ac33f84bSZhu Lingshan 		return 0;
291ac33f84bSZhu Lingshan 	else
292ac33f84bSZhu Lingshan 		return -EINVAL;
293ad5c5690SZhu Lingshan 
294e7991f37SZhu Lingshan 	snprintf(vf->config_msix_name, 256, "ifcvf[%s]-config\n",
295e7991f37SZhu Lingshan 		 pci_name(pdev));
2969b3e8148SZhu Lingshan 	vf->config_irq = pci_irq_vector(pdev, config_vector);
2972b9f28d5SJason Wang 	ret = devm_request_irq(&pdev->dev, vf->config_irq,
298e7991f37SZhu Lingshan 			       ifcvf_config_changed, 0,
299e7991f37SZhu Lingshan 			       vf->config_msix_name, vf);
3009f4ce5d7SJason Wang 	if (ret) {
3019f4ce5d7SJason Wang 		IFCVF_ERR(pdev, "Failed to request config irq\n");
3029b3e8148SZhu Lingshan 		goto err;
3039f4ce5d7SJason Wang 	}
304e7991f37SZhu Lingshan 
3059b3e8148SZhu Lingshan 	ret = ifcvf_set_config_vector(vf, config_vector);
3069b3e8148SZhu Lingshan 	if (ret == VIRTIO_MSI_NO_VECTOR) {
3079b3e8148SZhu Lingshan 		IFCVF_ERR(pdev, "No msix vector for device config\n");
3089b3e8148SZhu Lingshan 		goto err;
3099b3e8148SZhu Lingshan 	}
3109b3e8148SZhu Lingshan 
3119b3e8148SZhu Lingshan 	return 0;
3129b3e8148SZhu Lingshan err:
31323dac55cSZhu Lingshan 	ifcvf_free_irq(vf);
3149b3e8148SZhu Lingshan 
3159b3e8148SZhu Lingshan 	return -EFAULT;
3169b3e8148SZhu Lingshan }
3179b3e8148SZhu Lingshan 
ifcvf_request_irq(struct ifcvf_hw * vf)3187cfd36b7SZhu Lingshan static int ifcvf_request_irq(struct ifcvf_hw *vf)
3199b3e8148SZhu Lingshan {
3209b3e8148SZhu Lingshan 	int nvectors, ret, max_intr;
3219b3e8148SZhu Lingshan 
322a70d833eSZhu Lingshan 	nvectors = ifcvf_alloc_vectors(vf);
3239b3e8148SZhu Lingshan 	if (nvectors <= 0)
3249b3e8148SZhu Lingshan 		return -EFAULT;
3259b3e8148SZhu Lingshan 
3269b3e8148SZhu Lingshan 	vf->msix_vector_status = MSIX_VECTOR_PER_VQ_AND_CONFIG;
3279b3e8148SZhu Lingshan 	max_intr = vf->nr_vring + 1;
3289b3e8148SZhu Lingshan 	if (nvectors < max_intr)
3299b3e8148SZhu Lingshan 		vf->msix_vector_status = MSIX_VECTOR_SHARED_VQ_AND_CONFIG;
3309b3e8148SZhu Lingshan 
3319b3e8148SZhu Lingshan 	if (nvectors == 1) {
3329b3e8148SZhu Lingshan 		vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED;
333a70d833eSZhu Lingshan 		ret = ifcvf_request_dev_irq(vf);
3347dd793f3SZhu Lingshan 
3357dd793f3SZhu Lingshan 		return ret;
3367dd793f3SZhu Lingshan 	}
3377dd793f3SZhu Lingshan 
338f9a9ffb2SZhu Lingshan 	ret = ifcvf_request_vq_irq(vf);
3399b3e8148SZhu Lingshan 	if (ret)
3409b3e8148SZhu Lingshan 		return ret;
3419b3e8148SZhu Lingshan 
342a70d833eSZhu Lingshan 	ret = ifcvf_request_config_irq(vf);
3439b3e8148SZhu Lingshan 
3449b3e8148SZhu Lingshan 	if (ret)
3459b3e8148SZhu Lingshan 		return ret;
3467dd793f3SZhu Lingshan 
347386a2620SZhu Lingshan 	vf->num_msix_vectors = nvectors;
348c9b9f5f8SMichael S. Tsirkin 
349c9b9f5f8SMichael S. Tsirkin 	return 0;
350c9b9f5f8SMichael S. Tsirkin }
351c9b9f5f8SMichael S. Tsirkin 
vdpa_to_adapter(struct vdpa_device * vdpa_dev)352c9b9f5f8SMichael S. Tsirkin static struct ifcvf_adapter *vdpa_to_adapter(struct vdpa_device *vdpa_dev)
353c9b9f5f8SMichael S. Tsirkin {
354c9b9f5f8SMichael S. Tsirkin 	return container_of(vdpa_dev, struct ifcvf_adapter, vdpa);
355c9b9f5f8SMichael S. Tsirkin }
356c9b9f5f8SMichael S. Tsirkin 
vdpa_to_vf(struct vdpa_device * vdpa_dev)357c9b9f5f8SMichael S. Tsirkin static struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev)
358c9b9f5f8SMichael S. Tsirkin {
359c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev);
360c9b9f5f8SMichael S. Tsirkin 
3616a3b2f17SZhu Lingshan 	return adapter->vf;
362c9b9f5f8SMichael S. Tsirkin }
363c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_device_features(struct vdpa_device * vdpa_dev)364a64917bcSEli Cohen static u64 ifcvf_vdpa_get_device_features(struct vdpa_device *vdpa_dev)
365c9b9f5f8SMichael S. Tsirkin {
3666ad31d16SZhu Lingshan 	struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev);
367c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
3686ad31d16SZhu Lingshan 	struct pci_dev *pdev = adapter->pdev;
36990d19366SZhu Lingshan 	u32 type = vf->dev_type;
370c9b9f5f8SMichael S. Tsirkin 	u64 features;
371c9b9f5f8SMichael S. Tsirkin 
37290d19366SZhu Lingshan 	if (type == VIRTIO_ID_NET || type == VIRTIO_ID_BLOCK)
3731a252f03SZhu Lingshan 		features = ifcvf_get_dev_features(vf);
37490d19366SZhu Lingshan 	else {
3756ad31d16SZhu Lingshan 		features = 0;
3766ad31d16SZhu Lingshan 		IFCVF_ERR(pdev, "VIRTIO ID %u not supported\n", vf->dev_type);
3776ad31d16SZhu Lingshan 	}
378c9b9f5f8SMichael S. Tsirkin 
379c9b9f5f8SMichael S. Tsirkin 	return features;
380c9b9f5f8SMichael S. Tsirkin }
381c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_driver_features(struct vdpa_device * vdpa_dev,u64 features)382a64917bcSEli Cohen static int ifcvf_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 features)
383c9b9f5f8SMichael S. Tsirkin {
384c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
3851d895a68SZhu Lingshan 	int ret;
3861d895a68SZhu Lingshan 
3871d895a68SZhu Lingshan 	ret = ifcvf_verify_min_features(vf, features);
3881d895a68SZhu Lingshan 	if (ret)
3891d895a68SZhu Lingshan 		return ret;
390c9b9f5f8SMichael S. Tsirkin 
3911a252f03SZhu Lingshan 	ifcvf_set_driver_features(vf, features);
392c9b9f5f8SMichael S. Tsirkin 
393c9b9f5f8SMichael S. Tsirkin 	return 0;
394c9b9f5f8SMichael S. Tsirkin }
395c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_driver_features(struct vdpa_device * vdpa_dev)396a64917bcSEli Cohen static u64 ifcvf_vdpa_get_driver_features(struct vdpa_device *vdpa_dev)
397a64917bcSEli Cohen {
398a64917bcSEli Cohen 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
3991a252f03SZhu Lingshan 	u64 features;
400a64917bcSEli Cohen 
4011a252f03SZhu Lingshan 	features = ifcvf_get_driver_features(vf);
4021a252f03SZhu Lingshan 
4031a252f03SZhu Lingshan 	return features;
404a64917bcSEli Cohen }
405a64917bcSEli Cohen 
ifcvf_vdpa_get_status(struct vdpa_device * vdpa_dev)406c9b9f5f8SMichael S. Tsirkin static u8 ifcvf_vdpa_get_status(struct vdpa_device *vdpa_dev)
407c9b9f5f8SMichael S. Tsirkin {
408c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
409c9b9f5f8SMichael S. Tsirkin 
410c9b9f5f8SMichael S. Tsirkin 	return ifcvf_get_status(vf);
411c9b9f5f8SMichael S. Tsirkin }
412c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_status(struct vdpa_device * vdpa_dev,u8 status)413c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
414c9b9f5f8SMichael S. Tsirkin {
415c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf;
4167dd793f3SZhu Lingshan 	u8 status_old;
4177dd793f3SZhu Lingshan 	int ret;
418c9b9f5f8SMichael S. Tsirkin 
419c9b9f5f8SMichael S. Tsirkin 	vf  = vdpa_to_vf(vdpa_dev);
4207dd793f3SZhu Lingshan 	status_old = ifcvf_get_status(vf);
4217dd793f3SZhu Lingshan 
422bb02e6e6SZhu Lingshan 	if (status_old == status)
423bb02e6e6SZhu Lingshan 		return;
424bb02e6e6SZhu Lingshan 
4257dd793f3SZhu Lingshan 	if ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
4267dd793f3SZhu Lingshan 	    !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) {
4277cfd36b7SZhu Lingshan 		ret = ifcvf_request_irq(vf);
4287dd793f3SZhu Lingshan 		if (ret) {
42949a64c6dSZhu Lingshan 			IFCVF_ERR(vf->pdev, "failed to request irq with error %d\n", ret);
4307dd793f3SZhu Lingshan 			return;
4317dd793f3SZhu Lingshan 		}
432c9b9f5f8SMichael S. Tsirkin 	}
433c9b9f5f8SMichael S. Tsirkin 
434c9b9f5f8SMichael S. Tsirkin 	ifcvf_set_status(vf, status);
435c9b9f5f8SMichael S. Tsirkin }
436c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_reset(struct vdpa_device * vdpa_dev)4370686082dSXie Yongji static int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev)
4380686082dSXie Yongji {
439386a2620SZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
440386a2620SZhu Lingshan 	u8 status = ifcvf_get_status(vf);
4410686082dSXie Yongji 
442386a2620SZhu Lingshan 	ifcvf_stop(vf);
4430686082dSXie Yongji 
444386a2620SZhu Lingshan 	if (status & VIRTIO_CONFIG_S_DRIVER_OK)
44523dac55cSZhu Lingshan 		ifcvf_free_irq(vf);
4460686082dSXie Yongji 
447386a2620SZhu Lingshan 	ifcvf_reset(vf);
4480686082dSXie Yongji 
4490686082dSXie Yongji 	return 0;
4500686082dSXie Yongji }
4510686082dSXie Yongji 
ifcvf_vdpa_get_vq_num_max(struct vdpa_device * vdpa_dev)452c9b9f5f8SMichael S. Tsirkin static u16 ifcvf_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev)
453c9b9f5f8SMichael S. Tsirkin {
454ae904d9cSZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
455ae904d9cSZhu Lingshan 
456ae904d9cSZhu Lingshan 	return ifcvf_get_max_vq_size(vf);
457c9b9f5f8SMichael S. Tsirkin }
458c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_vq_state(struct vdpa_device * vdpa_dev,u16 qid,struct vdpa_vq_state * state)45923750e39SEli Cohen static int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
460aac50c0bSEli Cohen 				   struct vdpa_vq_state *state)
461c9b9f5f8SMichael S. Tsirkin {
462c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
463c9b9f5f8SMichael S. Tsirkin 
464530a5678SJason Wang 	state->split.avail_index = ifcvf_get_vq_state(vf, qid);
46523750e39SEli Cohen 	return 0;
466c9b9f5f8SMichael S. Tsirkin }
467c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_vq_state(struct vdpa_device * vdpa_dev,u16 qid,const struct vdpa_vq_state * state)468c9b9f5f8SMichael S. Tsirkin static int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
469aac50c0bSEli Cohen 				   const struct vdpa_vq_state *state)
470c9b9f5f8SMichael S. Tsirkin {
471c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
472c9b9f5f8SMichael S. Tsirkin 
473530a5678SJason Wang 	return ifcvf_set_vq_state(vf, qid, state->split.avail_index);
474c9b9f5f8SMichael S. Tsirkin }
475c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_vq_cb(struct vdpa_device * vdpa_dev,u16 qid,struct vdpa_callback * cb)476c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid,
477c9b9f5f8SMichael S. Tsirkin 				 struct vdpa_callback *cb)
478c9b9f5f8SMichael S. Tsirkin {
479c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
480c9b9f5f8SMichael S. Tsirkin 
481c9b9f5f8SMichael S. Tsirkin 	vf->vring[qid].cb = *cb;
482c9b9f5f8SMichael S. Tsirkin }
483c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_vq_ready(struct vdpa_device * vdpa_dev,u16 qid,bool ready)484c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev,
485c9b9f5f8SMichael S. Tsirkin 				    u16 qid, bool ready)
486c9b9f5f8SMichael S. Tsirkin {
487c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
488c9b9f5f8SMichael S. Tsirkin 
489a4751306SZhu Lingshan 	ifcvf_set_vq_ready(vf, qid, ready);
490c9b9f5f8SMichael S. Tsirkin }
491c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_vq_ready(struct vdpa_device * vdpa_dev,u16 qid)492c9b9f5f8SMichael S. Tsirkin static bool ifcvf_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid)
493c9b9f5f8SMichael S. Tsirkin {
494c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
495c9b9f5f8SMichael S. Tsirkin 
496a4751306SZhu Lingshan 	return ifcvf_get_vq_ready(vf, qid);
497c9b9f5f8SMichael S. Tsirkin }
498c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_vq_num(struct vdpa_device * vdpa_dev,u16 qid,u32 num)499c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid,
500c9b9f5f8SMichael S. Tsirkin 				  u32 num)
501c9b9f5f8SMichael S. Tsirkin {
502c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
503c9b9f5f8SMichael S. Tsirkin 
504a4751306SZhu Lingshan 	ifcvf_set_vq_num(vf, qid, num);
505c9b9f5f8SMichael S. Tsirkin }
506c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_vq_address(struct vdpa_device * vdpa_dev,u16 qid,u64 desc_area,u64 driver_area,u64 device_area)507c9b9f5f8SMichael S. Tsirkin static int ifcvf_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid,
508c9b9f5f8SMichael S. Tsirkin 				     u64 desc_area, u64 driver_area,
509c9b9f5f8SMichael S. Tsirkin 				     u64 device_area)
510c9b9f5f8SMichael S. Tsirkin {
511c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
512c9b9f5f8SMichael S. Tsirkin 
513a4751306SZhu Lingshan 	return ifcvf_set_vq_address(vf, qid, desc_area, driver_area, device_area);
514c9b9f5f8SMichael S. Tsirkin }
515c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_kick_vq(struct vdpa_device * vdpa_dev,u16 qid)516c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid)
517c9b9f5f8SMichael S. Tsirkin {
518c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
519c9b9f5f8SMichael S. Tsirkin 
520c9b9f5f8SMichael S. Tsirkin 	ifcvf_notify_queue(vf, qid);
521c9b9f5f8SMichael S. Tsirkin }
522c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_generation(struct vdpa_device * vdpa_dev)523c9b9f5f8SMichael S. Tsirkin static u32 ifcvf_vdpa_get_generation(struct vdpa_device *vdpa_dev)
524c9b9f5f8SMichael S. Tsirkin {
525c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
526c9b9f5f8SMichael S. Tsirkin 
5278897d6d0SZhu Lingshan 	return vp_ioread8(&vf->common_cfg->config_generation);
528c9b9f5f8SMichael S. Tsirkin }
529c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_device_id(struct vdpa_device * vdpa_dev)530c9b9f5f8SMichael S. Tsirkin static u32 ifcvf_vdpa_get_device_id(struct vdpa_device *vdpa_dev)
531c9b9f5f8SMichael S. Tsirkin {
53226bfea13SZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
533e8ef6124SZhu Lingshan 
53426bfea13SZhu Lingshan 	return vf->dev_type;
535c9b9f5f8SMichael S. Tsirkin }
536c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_vendor_id(struct vdpa_device * vdpa_dev)537c9b9f5f8SMichael S. Tsirkin static u32 ifcvf_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev)
538c9b9f5f8SMichael S. Tsirkin {
5390ecb1960SZhu Lingshan 	struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev);
5400ecb1960SZhu Lingshan 	struct pci_dev *pdev = adapter->pdev;
5410ecb1960SZhu Lingshan 
5420ecb1960SZhu Lingshan 	return pdev->subsystem_vendor;
543c9b9f5f8SMichael S. Tsirkin }
544c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_vq_align(struct vdpa_device * vdpa_dev)545425a5070SMichael S. Tsirkin static u32 ifcvf_vdpa_get_vq_align(struct vdpa_device *vdpa_dev)
546c9b9f5f8SMichael S. Tsirkin {
547c9b9f5f8SMichael S. Tsirkin 	return IFCVF_QUEUE_ALIGNMENT;
548c9b9f5f8SMichael S. Tsirkin }
549c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_config_size(struct vdpa_device * vdpa_dev)550442706f9SStefano Garzarella static size_t ifcvf_vdpa_get_config_size(struct vdpa_device *vdpa_dev)
551442706f9SStefano Garzarella {
55256190031SZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
55356190031SZhu Lingshan 
5540f420c38SZhu Lingshan 	return  vf->config_size;
555442706f9SStefano Garzarella }
556442706f9SStefano Garzarella 
ifcvf_vdpa_get_vq_group(struct vdpa_device * vdpa,u16 idx)557d4821902SGautam Dawar static u32 ifcvf_vdpa_get_vq_group(struct vdpa_device *vdpa, u16 idx)
558d4821902SGautam Dawar {
559d4821902SGautam Dawar 	return 0;
560d4821902SGautam Dawar }
561d4821902SGautam Dawar 
ifcvf_vdpa_get_config(struct vdpa_device * vdpa_dev,unsigned int offset,void * buf,unsigned int len)562c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_get_config(struct vdpa_device *vdpa_dev,
563c9b9f5f8SMichael S. Tsirkin 				  unsigned int offset,
564c9b9f5f8SMichael S. Tsirkin 				  void *buf, unsigned int len)
565c9b9f5f8SMichael S. Tsirkin {
566c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
567c9b9f5f8SMichael S. Tsirkin 
5680f420c38SZhu Lingshan 	ifcvf_read_dev_config(vf, offset, buf, len);
569c9b9f5f8SMichael S. Tsirkin }
570c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_config(struct vdpa_device * vdpa_dev,unsigned int offset,const void * buf,unsigned int len)571c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_config(struct vdpa_device *vdpa_dev,
572c9b9f5f8SMichael S. Tsirkin 				  unsigned int offset, const void *buf,
573c9b9f5f8SMichael S. Tsirkin 				  unsigned int len)
574c9b9f5f8SMichael S. Tsirkin {
575c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
576c9b9f5f8SMichael S. Tsirkin 
5770f420c38SZhu Lingshan 	ifcvf_write_dev_config(vf, offset, buf, len);
578c9b9f5f8SMichael S. Tsirkin }
579c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_set_config_cb(struct vdpa_device * vdpa_dev,struct vdpa_callback * cb)580c9b9f5f8SMichael S. Tsirkin static void ifcvf_vdpa_set_config_cb(struct vdpa_device *vdpa_dev,
581c9b9f5f8SMichael S. Tsirkin 				     struct vdpa_callback *cb)
582c9b9f5f8SMichael S. Tsirkin {
583e7991f37SZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
584e7991f37SZhu Lingshan 
585e7991f37SZhu Lingshan 	vf->config_cb.callback = cb->callback;
586e7991f37SZhu Lingshan 	vf->config_cb.private = cb->private;
587c9b9f5f8SMichael S. Tsirkin }
588c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_get_vq_irq(struct vdpa_device * vdpa_dev,u16 qid)5893597a2fbSZhu Lingshan static int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev,
5903597a2fbSZhu Lingshan 				 u16 qid)
5913597a2fbSZhu Lingshan {
5923597a2fbSZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
5933597a2fbSZhu Lingshan 
5949b3e8148SZhu Lingshan 	if (vf->vqs_reused_irq < 0)
5953597a2fbSZhu Lingshan 		return vf->vring[qid].irq;
5969b3e8148SZhu Lingshan 	else
5979b3e8148SZhu Lingshan 		return -EINVAL;
5983597a2fbSZhu Lingshan }
5993597a2fbSZhu Lingshan 
ifcvf_get_vq_notification(struct vdpa_device * vdpa_dev,u16 idx)6005f1b73a2SZhu Lingshan static struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev,
6015f1b73a2SZhu Lingshan 							       u16 idx)
6025f1b73a2SZhu Lingshan {
6035f1b73a2SZhu Lingshan 	struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
6045f1b73a2SZhu Lingshan 	struct vdpa_notification_area area;
6055f1b73a2SZhu Lingshan 
6065f1b73a2SZhu Lingshan 	area.addr = vf->vring[idx].notify_pa;
6075f1b73a2SZhu Lingshan 	if (!vf->notify_off_multiplier)
6085f1b73a2SZhu Lingshan 		area.size = PAGE_SIZE;
6095f1b73a2SZhu Lingshan 	else
6105f1b73a2SZhu Lingshan 		area.size = vf->notify_off_multiplier;
6115f1b73a2SZhu Lingshan 
6125f1b73a2SZhu Lingshan 	return area;
6135f1b73a2SZhu Lingshan }
6145f1b73a2SZhu Lingshan 
615c9b9f5f8SMichael S. Tsirkin /*
6166e33fa09SZhang Jiaming  * IFCVF currently doesn't have on-chip IOMMU, so not
617c9b9f5f8SMichael S. Tsirkin  * implemented set_map()/dma_map()/dma_unmap()
618c9b9f5f8SMichael S. Tsirkin  */
619c9b9f5f8SMichael S. Tsirkin static const struct vdpa_config_ops ifc_vdpa_ops = {
620a64917bcSEli Cohen 	.get_device_features = ifcvf_vdpa_get_device_features,
621a64917bcSEli Cohen 	.set_driver_features = ifcvf_vdpa_set_driver_features,
622a64917bcSEli Cohen 	.get_driver_features = ifcvf_vdpa_get_driver_features,
623c9b9f5f8SMichael S. Tsirkin 	.get_status	= ifcvf_vdpa_get_status,
624c9b9f5f8SMichael S. Tsirkin 	.set_status	= ifcvf_vdpa_set_status,
6250686082dSXie Yongji 	.reset		= ifcvf_vdpa_reset,
626c9b9f5f8SMichael S. Tsirkin 	.get_vq_num_max	= ifcvf_vdpa_get_vq_num_max,
627c9b9f5f8SMichael S. Tsirkin 	.get_vq_state	= ifcvf_vdpa_get_vq_state,
628c9b9f5f8SMichael S. Tsirkin 	.set_vq_state	= ifcvf_vdpa_set_vq_state,
629c9b9f5f8SMichael S. Tsirkin 	.set_vq_cb	= ifcvf_vdpa_set_vq_cb,
630c9b9f5f8SMichael S. Tsirkin 	.set_vq_ready	= ifcvf_vdpa_set_vq_ready,
631c9b9f5f8SMichael S. Tsirkin 	.get_vq_ready	= ifcvf_vdpa_get_vq_ready,
632c9b9f5f8SMichael S. Tsirkin 	.set_vq_num	= ifcvf_vdpa_set_vq_num,
633c9b9f5f8SMichael S. Tsirkin 	.set_vq_address	= ifcvf_vdpa_set_vq_address,
6343597a2fbSZhu Lingshan 	.get_vq_irq	= ifcvf_vdpa_get_vq_irq,
635c9b9f5f8SMichael S. Tsirkin 	.kick_vq	= ifcvf_vdpa_kick_vq,
636c9b9f5f8SMichael S. Tsirkin 	.get_generation	= ifcvf_vdpa_get_generation,
637c9b9f5f8SMichael S. Tsirkin 	.get_device_id	= ifcvf_vdpa_get_device_id,
638c9b9f5f8SMichael S. Tsirkin 	.get_vendor_id	= ifcvf_vdpa_get_vendor_id,
639c9b9f5f8SMichael S. Tsirkin 	.get_vq_align	= ifcvf_vdpa_get_vq_align,
640d4821902SGautam Dawar 	.get_vq_group	= ifcvf_vdpa_get_vq_group,
641442706f9SStefano Garzarella 	.get_config_size	= ifcvf_vdpa_get_config_size,
642c9b9f5f8SMichael S. Tsirkin 	.get_config	= ifcvf_vdpa_get_config,
643c9b9f5f8SMichael S. Tsirkin 	.set_config	= ifcvf_vdpa_set_config,
644c9b9f5f8SMichael S. Tsirkin 	.set_config_cb  = ifcvf_vdpa_set_config_cb,
6455f1b73a2SZhu Lingshan 	.get_vq_notification = ifcvf_get_vq_notification,
646c9b9f5f8SMichael S. Tsirkin };
647c9b9f5f8SMichael S. Tsirkin 
6486b5df347SZhu Lingshan static struct virtio_device_id id_table_net[] = {
6496b5df347SZhu Lingshan 	{VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID},
6506b5df347SZhu Lingshan 	{0},
6516b5df347SZhu Lingshan };
6526b5df347SZhu Lingshan 
6536b5df347SZhu Lingshan static struct virtio_device_id id_table_blk[] = {
6546b5df347SZhu Lingshan 	{VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID},
6556b5df347SZhu Lingshan 	{0},
6566b5df347SZhu Lingshan };
6576b5df347SZhu Lingshan 
get_dev_type(struct pci_dev * pdev)65830326f95SZhu Lingshan static u32 get_dev_type(struct pci_dev *pdev)
65930326f95SZhu Lingshan {
66030326f95SZhu Lingshan 	u32 dev_type;
66130326f95SZhu Lingshan 
66230326f95SZhu Lingshan 	/* This drirver drives both modern virtio devices and transitional
66330326f95SZhu Lingshan 	 * devices in modern mode.
66430326f95SZhu Lingshan 	 * vDPA requires feature bit VIRTIO_F_ACCESS_PLATFORM,
66530326f95SZhu Lingshan 	 * so legacy devices and transitional devices in legacy
66630326f95SZhu Lingshan 	 * mode will not work for vDPA, this driver will not
66730326f95SZhu Lingshan 	 * drive devices with legacy interface.
66830326f95SZhu Lingshan 	 */
66930326f95SZhu Lingshan 
67030326f95SZhu Lingshan 	if (pdev->device < 0x1040)
67130326f95SZhu Lingshan 		dev_type =  pdev->subsystem_device;
67230326f95SZhu Lingshan 	else
67330326f95SZhu Lingshan 		dev_type =  pdev->device - 0x1040;
67430326f95SZhu Lingshan 
67530326f95SZhu Lingshan 	return dev_type;
67630326f95SZhu Lingshan }
67730326f95SZhu Lingshan 
ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev * mdev,const char * name,const struct vdpa_dev_set_config * config)678d8ca2fa5SParav Pandit static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
679d8ca2fa5SParav Pandit 			      const struct vdpa_dev_set_config *config)
680c9b9f5f8SMichael S. Tsirkin {
6816b5df347SZhu Lingshan 	struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
682c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_adapter *adapter;
683378b2e95SZhu Lingshan 	struct vdpa_device *vdpa_dev;
6846b5df347SZhu Lingshan 	struct pci_dev *pdev;
685c9b9f5f8SMichael S. Tsirkin 	struct ifcvf_hw *vf;
68646fc0917SZhu Lingshan 	u64 device_features;
687378b2e95SZhu Lingshan 	int ret;
688c9b9f5f8SMichael S. Tsirkin 
6896b5df347SZhu Lingshan 	ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev);
69093139037SZhu Lingshan 	vf = &ifcvf_mgmt_dev->vf;
69193139037SZhu Lingshan 	pdev = vf->pdev;
69293139037SZhu Lingshan 	adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
69393139037SZhu Lingshan 				    &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false);
69493139037SZhu Lingshan 	if (IS_ERR(adapter)) {
69593139037SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
69693139037SZhu Lingshan 		return PTR_ERR(adapter);
69793139037SZhu Lingshan 	}
698c9b9f5f8SMichael S. Tsirkin 
69993139037SZhu Lingshan 	ifcvf_mgmt_dev->adapter = adapter;
70093139037SZhu Lingshan 	adapter->pdev = pdev;
70193139037SZhu Lingshan 	adapter->vdpa.dma_dev = &pdev->dev;
70293139037SZhu Lingshan 	adapter->vdpa.mdev = mdev;
70393139037SZhu Lingshan 	adapter->vf = vf;
704378b2e95SZhu Lingshan 	vdpa_dev = &adapter->vdpa;
705c9b9f5f8SMichael S. Tsirkin 
70646fc0917SZhu Lingshan 	device_features = vf->hw_features;
70746fc0917SZhu Lingshan 	if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
70846fc0917SZhu Lingshan 		if (config->device_features & ~device_features) {
70946fc0917SZhu Lingshan 			IFCVF_ERR(pdev, "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n",
71046fc0917SZhu Lingshan 				  config->device_features, device_features);
71146fc0917SZhu Lingshan 			return -EINVAL;
71246fc0917SZhu Lingshan 		}
71346fc0917SZhu Lingshan 		device_features &= config->device_features;
71446fc0917SZhu Lingshan 	}
71546fc0917SZhu Lingshan 	vf->dev_features = device_features;
71646fc0917SZhu Lingshan 
717378b2e95SZhu Lingshan 	if (name)
718378b2e95SZhu Lingshan 		ret = dev_set_name(&vdpa_dev->dev, "%s", name);
719378b2e95SZhu Lingshan 	else
720378b2e95SZhu Lingshan 		ret = dev_set_name(&vdpa_dev->dev, "vdpa%u", vdpa_dev->index);
721c9b9f5f8SMichael S. Tsirkin 
7222ddae773SZhu Lingshan 	ret = _vdpa_register_device(&adapter->vdpa, vf->nr_vring);
723c9b9f5f8SMichael S. Tsirkin 	if (ret) {
724378b2e95SZhu Lingshan 		put_device(&adapter->vdpa.dev);
7256b5df347SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to register to vDPA bus");
726378b2e95SZhu Lingshan 		return ret;
727c9b9f5f8SMichael S. Tsirkin 	}
728c9b9f5f8SMichael S. Tsirkin 
729c9b9f5f8SMichael S. Tsirkin 	return 0;
730c9b9f5f8SMichael S. Tsirkin }
731c9b9f5f8SMichael S. Tsirkin 
ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev * mdev,struct vdpa_device * dev)7326b5df347SZhu Lingshan static void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev)
7336b5df347SZhu Lingshan {
7346b5df347SZhu Lingshan 	struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
7356b5df347SZhu Lingshan 
7366b5df347SZhu Lingshan 	ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev);
7376b5df347SZhu Lingshan 	_vdpa_unregister_device(dev);
7386b5df347SZhu Lingshan 	ifcvf_mgmt_dev->adapter = NULL;
7396b5df347SZhu Lingshan }
7406b5df347SZhu Lingshan 
7416b5df347SZhu Lingshan static const struct vdpa_mgmtdev_ops ifcvf_vdpa_mgmt_dev_ops = {
7426b5df347SZhu Lingshan 	.dev_add = ifcvf_vdpa_dev_add,
7436b5df347SZhu Lingshan 	.dev_del = ifcvf_vdpa_dev_del
7446b5df347SZhu Lingshan };
7456b5df347SZhu Lingshan 
ifcvf_probe(struct pci_dev * pdev,const struct pci_device_id * id)7466b5df347SZhu Lingshan static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
7476b5df347SZhu Lingshan {
7486b5df347SZhu Lingshan 	struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
7496b5df347SZhu Lingshan 	struct device *dev = &pdev->dev;
750378b2e95SZhu Lingshan 	struct ifcvf_hw *vf;
7516b5df347SZhu Lingshan 	u32 dev_type;
752378b2e95SZhu Lingshan 	int ret, i;
753378b2e95SZhu Lingshan 
754378b2e95SZhu Lingshan 	ret = pcim_enable_device(pdev);
755378b2e95SZhu Lingshan 	if (ret) {
756378b2e95SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to enable device\n");
757378b2e95SZhu Lingshan 		return ret;
758378b2e95SZhu Lingshan 	}
759378b2e95SZhu Lingshan 	ret = pcim_iomap_regions(pdev, BIT(0) | BIT(2) | BIT(4),
760378b2e95SZhu Lingshan 				 IFCVF_DRIVER_NAME);
761378b2e95SZhu Lingshan 	if (ret) {
762378b2e95SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to request MMIO region\n");
763378b2e95SZhu Lingshan 		return ret;
764378b2e95SZhu Lingshan 	}
765378b2e95SZhu Lingshan 
766378b2e95SZhu Lingshan 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
767378b2e95SZhu Lingshan 	if (ret) {
768378b2e95SZhu Lingshan 		IFCVF_ERR(pdev, "No usable DMA configuration\n");
769378b2e95SZhu Lingshan 		return ret;
770378b2e95SZhu Lingshan 	}
771378b2e95SZhu Lingshan 
772378b2e95SZhu Lingshan 	ret = devm_add_action_or_reset(dev, ifcvf_free_irq_vectors, pdev);
773378b2e95SZhu Lingshan 	if (ret) {
774378b2e95SZhu Lingshan 		IFCVF_ERR(pdev,
775378b2e95SZhu Lingshan 			  "Failed for adding devres for freeing irq vectors\n");
776378b2e95SZhu Lingshan 		return ret;
777378b2e95SZhu Lingshan 	}
778378b2e95SZhu Lingshan 
779378b2e95SZhu Lingshan 	pci_set_master(pdev);
78066e3970bSZhu Lingshan 	ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL);
78166e3970bSZhu Lingshan 	if (!ifcvf_mgmt_dev) {
78266e3970bSZhu Lingshan 		IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n");
78366e3970bSZhu Lingshan 		return -ENOMEM;
78466e3970bSZhu Lingshan 	}
785378b2e95SZhu Lingshan 
7866a3b2f17SZhu Lingshan 	vf = &ifcvf_mgmt_dev->vf;
787378b2e95SZhu Lingshan 	vf->dev_type = get_dev_type(pdev);
788378b2e95SZhu Lingshan 	vf->base = pcim_iomap_table(pdev);
789d59f633dSZhu Lingshan 	vf->pdev = pdev;
790378b2e95SZhu Lingshan 
791378b2e95SZhu Lingshan 	ret = ifcvf_init_hw(vf, pdev);
792378b2e95SZhu Lingshan 	if (ret) {
793378b2e95SZhu Lingshan 		IFCVF_ERR(pdev, "Failed to init IFCVF hw\n");
7946b04456eSTanmay Bhushan 		goto err;
795378b2e95SZhu Lingshan 	}
796378b2e95SZhu Lingshan 
797378b2e95SZhu Lingshan 	for (i = 0; i < vf->nr_vring; i++)
798378b2e95SZhu Lingshan 		vf->vring[i].irq = -EINVAL;
799378b2e95SZhu Lingshan 
800378b2e95SZhu Lingshan 	vf->hw_features = ifcvf_get_hw_features(vf);
801378b2e95SZhu Lingshan 	vf->config_size = ifcvf_get_config_size(vf);
8026b5df347SZhu Lingshan 
8036b5df347SZhu Lingshan 	dev_type = get_dev_type(pdev);
8046b5df347SZhu Lingshan 	switch (dev_type) {
8056b5df347SZhu Lingshan 	case VIRTIO_ID_NET:
8066b5df347SZhu Lingshan 		ifcvf_mgmt_dev->mdev.id_table = id_table_net;
8076b5df347SZhu Lingshan 		break;
8086b5df347SZhu Lingshan 	case VIRTIO_ID_BLOCK:
8096b5df347SZhu Lingshan 		ifcvf_mgmt_dev->mdev.id_table = id_table_blk;
8106b5df347SZhu Lingshan 		break;
8116b5df347SZhu Lingshan 	default:
8126b5df347SZhu Lingshan 		IFCVF_ERR(pdev, "VIRTIO ID %u not supported\n", dev_type);
8136b5df347SZhu Lingshan 		ret = -EOPNOTSUPP;
8146b5df347SZhu Lingshan 		goto err;
8156b5df347SZhu Lingshan 	}
8166b5df347SZhu Lingshan 
81766e3970bSZhu Lingshan 	ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops;
81866e3970bSZhu Lingshan 	ifcvf_mgmt_dev->mdev.device = dev;
819378b2e95SZhu Lingshan 	ifcvf_mgmt_dev->mdev.max_supported_vqs = vf->nr_vring;
820378b2e95SZhu Lingshan 	ifcvf_mgmt_dev->mdev.supported_features = vf->hw_features;
82146fc0917SZhu Lingshan 	ifcvf_mgmt_dev->mdev.config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES);
8226b5df347SZhu Lingshan 
8236b5df347SZhu Lingshan 	ret = vdpa_mgmtdev_register(&ifcvf_mgmt_dev->mdev);
8246b5df347SZhu Lingshan 	if (ret) {
8256b5df347SZhu Lingshan 		IFCVF_ERR(pdev,
8266b5df347SZhu Lingshan 			  "Failed to initialize the management interfaces\n");
8276b5df347SZhu Lingshan 		goto err;
8286b5df347SZhu Lingshan 	}
8296b5df347SZhu Lingshan 
830bd8bb9aeSJason Wang 	pci_set_drvdata(pdev, ifcvf_mgmt_dev);
831bd8bb9aeSJason Wang 
8326b5df347SZhu Lingshan 	return 0;
8336b5df347SZhu Lingshan 
8346b5df347SZhu Lingshan err:
83577128322SZhu Lingshan 	kfree(ifcvf_mgmt_dev->vf.vring);
8366b5df347SZhu Lingshan 	kfree(ifcvf_mgmt_dev);
8376b5df347SZhu Lingshan 	return ret;
8386b5df347SZhu Lingshan }
8396b5df347SZhu Lingshan 
ifcvf_remove(struct pci_dev * pdev)840c9b9f5f8SMichael S. Tsirkin static void ifcvf_remove(struct pci_dev *pdev)
841c9b9f5f8SMichael S. Tsirkin {
8426b5df347SZhu Lingshan 	struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
843c9b9f5f8SMichael S. Tsirkin 
8446b5df347SZhu Lingshan 	ifcvf_mgmt_dev = pci_get_drvdata(pdev);
8456b5df347SZhu Lingshan 	vdpa_mgmtdev_unregister(&ifcvf_mgmt_dev->mdev);
84677128322SZhu Lingshan 	kfree(ifcvf_mgmt_dev->vf.vring);
8476b5df347SZhu Lingshan 	kfree(ifcvf_mgmt_dev);
848c9b9f5f8SMichael S. Tsirkin }
849c9b9f5f8SMichael S. Tsirkin 
850c9b9f5f8SMichael S. Tsirkin static struct pci_device_id ifcvf_pci_ids[] = {
85142326903SZhu Lingshan 	/* N3000 network device */
85242326903SZhu Lingshan 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
85351fc387bSZhu Lingshan 			 N3000_DEVICE_ID,
85442326903SZhu Lingshan 			 PCI_VENDOR_ID_INTEL,
85551fc387bSZhu Lingshan 			 N3000_SUBSYS_DEVICE_ID) },
856*4cf8b6d0SZhu Lingshan 	/* C5000X-PL network device
857*4cf8b6d0SZhu Lingshan 	 * F2000X-PL network device
858*4cf8b6d0SZhu Lingshan 	 */
85942326903SZhu Lingshan 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
86042326903SZhu Lingshan 			 VIRTIO_TRANS_ID_NET,
86142326903SZhu Lingshan 			 PCI_VENDOR_ID_INTEL,
86242326903SZhu Lingshan 			 VIRTIO_ID_NET) },
86342326903SZhu Lingshan 	/* C5000X-PL block device */
86442326903SZhu Lingshan 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
86542326903SZhu Lingshan 			 VIRTIO_TRANS_ID_BLOCK,
86642326903SZhu Lingshan 			 PCI_VENDOR_ID_INTEL,
86742326903SZhu Lingshan 			 VIRTIO_ID_BLOCK) },
868139c3fd9SZhu Lingshan 
869c9b9f5f8SMichael S. Tsirkin 	{ 0 },
870c9b9f5f8SMichael S. Tsirkin };
871c9b9f5f8SMichael S. Tsirkin MODULE_DEVICE_TABLE(pci, ifcvf_pci_ids);
872c9b9f5f8SMichael S. Tsirkin 
873c9b9f5f8SMichael S. Tsirkin static struct pci_driver ifcvf_driver = {
874c9b9f5f8SMichael S. Tsirkin 	.name     = IFCVF_DRIVER_NAME,
875c9b9f5f8SMichael S. Tsirkin 	.id_table = ifcvf_pci_ids,
876c9b9f5f8SMichael S. Tsirkin 	.probe    = ifcvf_probe,
877c9b9f5f8SMichael S. Tsirkin 	.remove   = ifcvf_remove,
878c9b9f5f8SMichael S. Tsirkin };
879c9b9f5f8SMichael S. Tsirkin 
880c9b9f5f8SMichael S. Tsirkin module_pci_driver(ifcvf_driver);
881c9b9f5f8SMichael S. Tsirkin 
882c9b9f5f8SMichael S. Tsirkin MODULE_LICENSE("GPL v2");
883