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