162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel IFC VF NIC driver for virtio dataplane offloading 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Intel Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Zhu Lingshan <lingshan.zhu@intel.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/sysfs.h> 1562306a36Sopenharmony_ci#include "ifcvf_base.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define DRIVER_AUTHOR "Intel Corporation" 1862306a36Sopenharmony_ci#define IFCVF_DRIVER_NAME "ifcvf" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic irqreturn_t ifcvf_config_changed(int irq, void *arg) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct ifcvf_hw *vf = arg; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (vf->config_cb.callback) 2562306a36Sopenharmony_ci return vf->config_cb.callback(vf->config_cb.private); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return IRQ_HANDLED; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic irqreturn_t ifcvf_vq_intr_handler(int irq, void *arg) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct vring_info *vring = arg; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (vring->cb.callback) 3562306a36Sopenharmony_ci return vring->cb.callback(vring->cb.private); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return IRQ_HANDLED; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic irqreturn_t ifcvf_vqs_reused_intr_handler(int irq, void *arg) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct ifcvf_hw *vf = arg; 4362306a36Sopenharmony_ci struct vring_info *vring; 4462306a36Sopenharmony_ci int i; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) { 4762306a36Sopenharmony_ci vring = &vf->vring[i]; 4862306a36Sopenharmony_ci if (vring->cb.callback) 4962306a36Sopenharmony_ci vring->cb.callback(vring->cb.private); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return IRQ_HANDLED; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic irqreturn_t ifcvf_dev_intr_handler(int irq, void *arg) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct ifcvf_hw *vf = arg; 5862306a36Sopenharmony_ci u8 isr; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci isr = vp_ioread8(vf->isr); 6162306a36Sopenharmony_ci if (isr & VIRTIO_PCI_ISR_CONFIG) 6262306a36Sopenharmony_ci ifcvf_config_changed(irq, arg); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return ifcvf_vqs_reused_intr_handler(irq, arg); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void ifcvf_free_irq_vectors(void *data) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci pci_free_irq_vectors(data); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void ifcvf_free_per_vq_irq(struct ifcvf_hw *vf) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 7562306a36Sopenharmony_ci int i; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) { 7862306a36Sopenharmony_ci if (vf->vring[i].irq != -EINVAL) { 7962306a36Sopenharmony_ci devm_free_irq(&pdev->dev, vf->vring[i].irq, &vf->vring[i]); 8062306a36Sopenharmony_ci vf->vring[i].irq = -EINVAL; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void ifcvf_free_vqs_reused_irq(struct ifcvf_hw *vf) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (vf->vqs_reused_irq != -EINVAL) { 9062306a36Sopenharmony_ci devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf); 9162306a36Sopenharmony_ci vf->vqs_reused_irq = -EINVAL; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void ifcvf_free_vq_irq(struct ifcvf_hw *vf) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) 9962306a36Sopenharmony_ci ifcvf_free_per_vq_irq(vf); 10062306a36Sopenharmony_ci else 10162306a36Sopenharmony_ci ifcvf_free_vqs_reused_irq(vf); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void ifcvf_free_config_irq(struct ifcvf_hw *vf) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (vf->config_irq == -EINVAL) 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* If the irq is shared by all vqs and the config interrupt, 11262306a36Sopenharmony_ci * it is already freed in ifcvf_free_vq_irq, so here only 11362306a36Sopenharmony_ci * need to free config irq when msix_vector_status != MSIX_VECTOR_DEV_SHARED 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci if (vf->msix_vector_status != MSIX_VECTOR_DEV_SHARED) { 11662306a36Sopenharmony_ci devm_free_irq(&pdev->dev, vf->config_irq, vf); 11762306a36Sopenharmony_ci vf->config_irq = -EINVAL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void ifcvf_free_irq(struct ifcvf_hw *vf) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ifcvf_free_vq_irq(vf); 12662306a36Sopenharmony_ci ifcvf_free_config_irq(vf); 12762306a36Sopenharmony_ci ifcvf_free_irq_vectors(pdev); 12862306a36Sopenharmony_ci vf->num_msix_vectors = 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* ifcvf MSIX vectors allocator, this helper tries to allocate 13262306a36Sopenharmony_ci * vectors for all virtqueues and the config interrupt. 13362306a36Sopenharmony_ci * It returns the number of allocated vectors, negative 13462306a36Sopenharmony_ci * return value when fails. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic int ifcvf_alloc_vectors(struct ifcvf_hw *vf) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 13962306a36Sopenharmony_ci int max_intr, ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* all queues and config interrupt */ 14262306a36Sopenharmony_ci max_intr = vf->nr_vring + 1; 14362306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, 1, max_intr, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (ret < 0) { 14662306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to alloc IRQ vectors\n"); 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (ret < max_intr) 15162306a36Sopenharmony_ci IFCVF_INFO(pdev, 15262306a36Sopenharmony_ci "Requested %u vectors, however only %u allocated, lower performance\n", 15362306a36Sopenharmony_ci max_intr, ret); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return ret; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int ifcvf_request_per_vq_irq(struct ifcvf_hw *vf) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 16162306a36Sopenharmony_ci int i, vector, ret, irq; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci vf->vqs_reused_irq = -EINVAL; 16462306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) { 16562306a36Sopenharmony_ci snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n", pci_name(pdev), i); 16662306a36Sopenharmony_ci vector = i; 16762306a36Sopenharmony_ci irq = pci_irq_vector(pdev, vector); 16862306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, 16962306a36Sopenharmony_ci ifcvf_vq_intr_handler, 0, 17062306a36Sopenharmony_ci vf->vring[i].msix_name, 17162306a36Sopenharmony_ci &vf->vring[i]); 17262306a36Sopenharmony_ci if (ret) { 17362306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request irq for vq %d\n", i); 17462306a36Sopenharmony_ci goto err; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci vf->vring[i].irq = irq; 17862306a36Sopenharmony_ci ret = ifcvf_set_vq_vector(vf, i, vector); 17962306a36Sopenharmony_ci if (ret == VIRTIO_MSI_NO_VECTOR) { 18062306a36Sopenharmony_ci IFCVF_ERR(pdev, "No msix vector for vq %u\n", i); 18162306a36Sopenharmony_ci goto err; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_cierr: 18762306a36Sopenharmony_ci ifcvf_free_irq(vf); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return -EFAULT; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int ifcvf_request_vqs_reused_irq(struct ifcvf_hw *vf) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 19562306a36Sopenharmony_ci int i, vector, ret, irq; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci vector = 0; 19862306a36Sopenharmony_ci snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-vqs-reused-irq\n", pci_name(pdev)); 19962306a36Sopenharmony_ci irq = pci_irq_vector(pdev, vector); 20062306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, 20162306a36Sopenharmony_ci ifcvf_vqs_reused_intr_handler, 0, 20262306a36Sopenharmony_ci vf->vring[0].msix_name, vf); 20362306a36Sopenharmony_ci if (ret) { 20462306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request reused irq for the device\n"); 20562306a36Sopenharmony_ci goto err; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci vf->vqs_reused_irq = irq; 20962306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) { 21062306a36Sopenharmony_ci vf->vring[i].irq = -EINVAL; 21162306a36Sopenharmony_ci ret = ifcvf_set_vq_vector(vf, i, vector); 21262306a36Sopenharmony_ci if (ret == VIRTIO_MSI_NO_VECTOR) { 21362306a36Sopenharmony_ci IFCVF_ERR(pdev, "No msix vector for vq %u\n", i); 21462306a36Sopenharmony_ci goto err; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_cierr: 22062306a36Sopenharmony_ci ifcvf_free_irq(vf); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return -EFAULT; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int ifcvf_request_dev_irq(struct ifcvf_hw *vf) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 22862306a36Sopenharmony_ci int i, vector, ret, irq; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci vector = 0; 23162306a36Sopenharmony_ci snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-dev-irq\n", pci_name(pdev)); 23262306a36Sopenharmony_ci irq = pci_irq_vector(pdev, vector); 23362306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, 23462306a36Sopenharmony_ci ifcvf_dev_intr_handler, 0, 23562306a36Sopenharmony_ci vf->vring[0].msix_name, vf); 23662306a36Sopenharmony_ci if (ret) { 23762306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request irq for the device\n"); 23862306a36Sopenharmony_ci goto err; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci vf->vqs_reused_irq = irq; 24262306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) { 24362306a36Sopenharmony_ci vf->vring[i].irq = -EINVAL; 24462306a36Sopenharmony_ci ret = ifcvf_set_vq_vector(vf, i, vector); 24562306a36Sopenharmony_ci if (ret == VIRTIO_MSI_NO_VECTOR) { 24662306a36Sopenharmony_ci IFCVF_ERR(pdev, "No msix vector for vq %u\n", i); 24762306a36Sopenharmony_ci goto err; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci vf->config_irq = irq; 25262306a36Sopenharmony_ci ret = ifcvf_set_config_vector(vf, vector); 25362306a36Sopenharmony_ci if (ret == VIRTIO_MSI_NO_VECTOR) { 25462306a36Sopenharmony_ci IFCVF_ERR(pdev, "No msix vector for device config\n"); 25562306a36Sopenharmony_ci goto err; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_cierr: 26062306a36Sopenharmony_ci ifcvf_free_irq(vf); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return -EFAULT; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int ifcvf_request_vq_irq(struct ifcvf_hw *vf) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int ret; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) 27162306a36Sopenharmony_ci ret = ifcvf_request_per_vq_irq(vf); 27262306a36Sopenharmony_ci else 27362306a36Sopenharmony_ci ret = ifcvf_request_vqs_reused_irq(vf); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return ret; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int ifcvf_request_config_irq(struct ifcvf_hw *vf) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct pci_dev *pdev = vf->pdev; 28162306a36Sopenharmony_ci int config_vector, ret; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) 28462306a36Sopenharmony_ci config_vector = vf->nr_vring; 28562306a36Sopenharmony_ci else if (vf->msix_vector_status == MSIX_VECTOR_SHARED_VQ_AND_CONFIG) 28662306a36Sopenharmony_ci /* vector 0 for vqs and 1 for config interrupt */ 28762306a36Sopenharmony_ci config_vector = 1; 28862306a36Sopenharmony_ci else if (vf->msix_vector_status == MSIX_VECTOR_DEV_SHARED) 28962306a36Sopenharmony_ci /* re-use the vqs vector */ 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci else 29262306a36Sopenharmony_ci return -EINVAL; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci snprintf(vf->config_msix_name, 256, "ifcvf[%s]-config\n", 29562306a36Sopenharmony_ci pci_name(pdev)); 29662306a36Sopenharmony_ci vf->config_irq = pci_irq_vector(pdev, config_vector); 29762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, vf->config_irq, 29862306a36Sopenharmony_ci ifcvf_config_changed, 0, 29962306a36Sopenharmony_ci vf->config_msix_name, vf); 30062306a36Sopenharmony_ci if (ret) { 30162306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request config irq\n"); 30262306a36Sopenharmony_ci goto err; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = ifcvf_set_config_vector(vf, config_vector); 30662306a36Sopenharmony_ci if (ret == VIRTIO_MSI_NO_VECTOR) { 30762306a36Sopenharmony_ci IFCVF_ERR(pdev, "No msix vector for device config\n"); 30862306a36Sopenharmony_ci goto err; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_cierr: 31362306a36Sopenharmony_ci ifcvf_free_irq(vf); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return -EFAULT; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int ifcvf_request_irq(struct ifcvf_hw *vf) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci int nvectors, ret, max_intr; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci nvectors = ifcvf_alloc_vectors(vf); 32362306a36Sopenharmony_ci if (nvectors <= 0) 32462306a36Sopenharmony_ci return -EFAULT; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci vf->msix_vector_status = MSIX_VECTOR_PER_VQ_AND_CONFIG; 32762306a36Sopenharmony_ci max_intr = vf->nr_vring + 1; 32862306a36Sopenharmony_ci if (nvectors < max_intr) 32962306a36Sopenharmony_ci vf->msix_vector_status = MSIX_VECTOR_SHARED_VQ_AND_CONFIG; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (nvectors == 1) { 33262306a36Sopenharmony_ci vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED; 33362306a36Sopenharmony_ci ret = ifcvf_request_dev_irq(vf); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ret = ifcvf_request_vq_irq(vf); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci return ret; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ret = ifcvf_request_config_irq(vf); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci return ret; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci vf->num_msix_vectors = nvectors; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic struct ifcvf_adapter *vdpa_to_adapter(struct vdpa_device *vdpa_dev) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return container_of(vdpa_dev, struct ifcvf_adapter, vdpa); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return adapter->vf; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic u64 ifcvf_vdpa_get_device_features(struct vdpa_device *vdpa_dev) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); 36762306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 36862306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 36962306a36Sopenharmony_ci u32 type = vf->dev_type; 37062306a36Sopenharmony_ci u64 features; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (type == VIRTIO_ID_NET || type == VIRTIO_ID_BLOCK) 37362306a36Sopenharmony_ci features = ifcvf_get_dev_features(vf); 37462306a36Sopenharmony_ci else { 37562306a36Sopenharmony_ci features = 0; 37662306a36Sopenharmony_ci IFCVF_ERR(pdev, "VIRTIO ID %u not supported\n", vf->dev_type); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return features; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int ifcvf_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 features) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 38562306a36Sopenharmony_ci int ret; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ret = ifcvf_verify_min_features(vf, features); 38862306a36Sopenharmony_ci if (ret) 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ifcvf_set_driver_features(vf, features); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic u64 ifcvf_vdpa_get_driver_features(struct vdpa_device *vdpa_dev) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 39962306a36Sopenharmony_ci u64 features; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci features = ifcvf_get_driver_features(vf); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return features; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic u8 ifcvf_vdpa_get_status(struct vdpa_device *vdpa_dev) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return ifcvf_get_status(vf); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct ifcvf_hw *vf; 41662306a36Sopenharmony_ci u8 status_old; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci vf = vdpa_to_vf(vdpa_dev); 42062306a36Sopenharmony_ci status_old = ifcvf_get_status(vf); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (status_old == status) 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && 42662306a36Sopenharmony_ci !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { 42762306a36Sopenharmony_ci ret = ifcvf_request_irq(vf); 42862306a36Sopenharmony_ci if (ret) { 42962306a36Sopenharmony_ci IFCVF_ERR(vf->pdev, "failed to request irq with error %d\n", ret); 43062306a36Sopenharmony_ci return; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ifcvf_set_status(vf, status); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 44062306a36Sopenharmony_ci u8 status = ifcvf_get_status(vf); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ifcvf_stop(vf); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (status & VIRTIO_CONFIG_S_DRIVER_OK) 44562306a36Sopenharmony_ci ifcvf_free_irq(vf); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci ifcvf_reset(vf); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic u16 ifcvf_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return ifcvf_get_max_vq_size(vf); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 46062306a36Sopenharmony_ci struct vdpa_vq_state *state) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci state->split.avail_index = ifcvf_get_vq_state(vf, qid); 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 46962306a36Sopenharmony_ci const struct vdpa_vq_state *state) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return ifcvf_set_vq_state(vf, qid, state->split.avail_index); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid, 47762306a36Sopenharmony_ci struct vdpa_callback *cb) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci vf->vring[qid].cb = *cb; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void ifcvf_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, 48562306a36Sopenharmony_ci u16 qid, bool ready) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci ifcvf_set_vq_ready(vf, qid, ready); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic bool ifcvf_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return ifcvf_get_vq_ready(vf, qid); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void ifcvf_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid, 50062306a36Sopenharmony_ci u32 num) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ifcvf_set_vq_num(vf, qid, num); 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int ifcvf_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid, 50862306a36Sopenharmony_ci u64 desc_area, u64 driver_area, 50962306a36Sopenharmony_ci u64 device_area) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return ifcvf_set_vq_address(vf, qid, desc_area, driver_area, device_area); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic void ifcvf_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci ifcvf_notify_queue(vf, qid); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic u32 ifcvf_vdpa_get_generation(struct vdpa_device *vdpa_dev) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return vp_ioread8(&vf->common_cfg->config_generation); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic u32 ifcvf_vdpa_get_device_id(struct vdpa_device *vdpa_dev) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return vf->dev_type; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic u32 ifcvf_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); 54062306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return pdev->subsystem_vendor; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic u32 ifcvf_vdpa_get_vq_align(struct vdpa_device *vdpa_dev) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci return IFCVF_QUEUE_ALIGNMENT; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic size_t ifcvf_vdpa_get_config_size(struct vdpa_device *vdpa_dev) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return vf->config_size; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic u32 ifcvf_vdpa_get_vq_group(struct vdpa_device *vdpa, u16 idx) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void ifcvf_vdpa_get_config(struct vdpa_device *vdpa_dev, 56362306a36Sopenharmony_ci unsigned int offset, 56462306a36Sopenharmony_ci void *buf, unsigned int len) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ifcvf_read_dev_config(vf, offset, buf, len); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void ifcvf_vdpa_set_config(struct vdpa_device *vdpa_dev, 57262306a36Sopenharmony_ci unsigned int offset, const void *buf, 57362306a36Sopenharmony_ci unsigned int len) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci ifcvf_write_dev_config(vf, offset, buf, len); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void ifcvf_vdpa_set_config_cb(struct vdpa_device *vdpa_dev, 58162306a36Sopenharmony_ci struct vdpa_callback *cb) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci vf->config_cb.callback = cb->callback; 58662306a36Sopenharmony_ci vf->config_cb.private = cb->private; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev, 59062306a36Sopenharmony_ci u16 qid) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (vf->vqs_reused_irq < 0) 59562306a36Sopenharmony_ci return vf->vring[qid].irq; 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev, 60162306a36Sopenharmony_ci u16 idx) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 60462306a36Sopenharmony_ci struct vdpa_notification_area area; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci area.addr = vf->vring[idx].notify_pa; 60762306a36Sopenharmony_ci if (!vf->notify_off_multiplier) 60862306a36Sopenharmony_ci area.size = PAGE_SIZE; 60962306a36Sopenharmony_ci else 61062306a36Sopenharmony_ci area.size = vf->notify_off_multiplier; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return area; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * IFCVF currently doesn't have on-chip IOMMU, so not 61762306a36Sopenharmony_ci * implemented set_map()/dma_map()/dma_unmap() 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_cistatic const struct vdpa_config_ops ifc_vdpa_ops = { 62062306a36Sopenharmony_ci .get_device_features = ifcvf_vdpa_get_device_features, 62162306a36Sopenharmony_ci .set_driver_features = ifcvf_vdpa_set_driver_features, 62262306a36Sopenharmony_ci .get_driver_features = ifcvf_vdpa_get_driver_features, 62362306a36Sopenharmony_ci .get_status = ifcvf_vdpa_get_status, 62462306a36Sopenharmony_ci .set_status = ifcvf_vdpa_set_status, 62562306a36Sopenharmony_ci .reset = ifcvf_vdpa_reset, 62662306a36Sopenharmony_ci .get_vq_num_max = ifcvf_vdpa_get_vq_num_max, 62762306a36Sopenharmony_ci .get_vq_state = ifcvf_vdpa_get_vq_state, 62862306a36Sopenharmony_ci .set_vq_state = ifcvf_vdpa_set_vq_state, 62962306a36Sopenharmony_ci .set_vq_cb = ifcvf_vdpa_set_vq_cb, 63062306a36Sopenharmony_ci .set_vq_ready = ifcvf_vdpa_set_vq_ready, 63162306a36Sopenharmony_ci .get_vq_ready = ifcvf_vdpa_get_vq_ready, 63262306a36Sopenharmony_ci .set_vq_num = ifcvf_vdpa_set_vq_num, 63362306a36Sopenharmony_ci .set_vq_address = ifcvf_vdpa_set_vq_address, 63462306a36Sopenharmony_ci .get_vq_irq = ifcvf_vdpa_get_vq_irq, 63562306a36Sopenharmony_ci .kick_vq = ifcvf_vdpa_kick_vq, 63662306a36Sopenharmony_ci .get_generation = ifcvf_vdpa_get_generation, 63762306a36Sopenharmony_ci .get_device_id = ifcvf_vdpa_get_device_id, 63862306a36Sopenharmony_ci .get_vendor_id = ifcvf_vdpa_get_vendor_id, 63962306a36Sopenharmony_ci .get_vq_align = ifcvf_vdpa_get_vq_align, 64062306a36Sopenharmony_ci .get_vq_group = ifcvf_vdpa_get_vq_group, 64162306a36Sopenharmony_ci .get_config_size = ifcvf_vdpa_get_config_size, 64262306a36Sopenharmony_ci .get_config = ifcvf_vdpa_get_config, 64362306a36Sopenharmony_ci .set_config = ifcvf_vdpa_set_config, 64462306a36Sopenharmony_ci .set_config_cb = ifcvf_vdpa_set_config_cb, 64562306a36Sopenharmony_ci .get_vq_notification = ifcvf_get_vq_notification, 64662306a36Sopenharmony_ci}; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic struct virtio_device_id id_table_net[] = { 64962306a36Sopenharmony_ci {VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID}, 65062306a36Sopenharmony_ci {0}, 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic struct virtio_device_id id_table_blk[] = { 65462306a36Sopenharmony_ci {VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID}, 65562306a36Sopenharmony_ci {0}, 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic u32 get_dev_type(struct pci_dev *pdev) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci u32 dev_type; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* This drirver drives both modern virtio devices and transitional 66362306a36Sopenharmony_ci * devices in modern mode. 66462306a36Sopenharmony_ci * vDPA requires feature bit VIRTIO_F_ACCESS_PLATFORM, 66562306a36Sopenharmony_ci * so legacy devices and transitional devices in legacy 66662306a36Sopenharmony_ci * mode will not work for vDPA, this driver will not 66762306a36Sopenharmony_ci * drive devices with legacy interface. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (pdev->device < 0x1040) 67162306a36Sopenharmony_ci dev_type = pdev->subsystem_device; 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci dev_type = pdev->device - 0x1040; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return dev_type; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, 67962306a36Sopenharmony_ci const struct vdpa_dev_set_config *config) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; 68262306a36Sopenharmony_ci struct ifcvf_adapter *adapter; 68362306a36Sopenharmony_ci struct vdpa_device *vdpa_dev; 68462306a36Sopenharmony_ci struct pci_dev *pdev; 68562306a36Sopenharmony_ci struct ifcvf_hw *vf; 68662306a36Sopenharmony_ci u64 device_features; 68762306a36Sopenharmony_ci int ret; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev); 69062306a36Sopenharmony_ci vf = &ifcvf_mgmt_dev->vf; 69162306a36Sopenharmony_ci pdev = vf->pdev; 69262306a36Sopenharmony_ci adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, 69362306a36Sopenharmony_ci &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false); 69462306a36Sopenharmony_ci if (IS_ERR(adapter)) { 69562306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); 69662306a36Sopenharmony_ci return PTR_ERR(adapter); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci ifcvf_mgmt_dev->adapter = adapter; 70062306a36Sopenharmony_ci adapter->pdev = pdev; 70162306a36Sopenharmony_ci adapter->vdpa.dma_dev = &pdev->dev; 70262306a36Sopenharmony_ci adapter->vdpa.mdev = mdev; 70362306a36Sopenharmony_ci adapter->vf = vf; 70462306a36Sopenharmony_ci vdpa_dev = &adapter->vdpa; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci device_features = vf->hw_features; 70762306a36Sopenharmony_ci if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 70862306a36Sopenharmony_ci if (config->device_features & ~device_features) { 70962306a36Sopenharmony_ci IFCVF_ERR(pdev, "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", 71062306a36Sopenharmony_ci config->device_features, device_features); 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci device_features &= config->device_features; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci vf->dev_features = device_features; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (name) 71862306a36Sopenharmony_ci ret = dev_set_name(&vdpa_dev->dev, "%s", name); 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci ret = dev_set_name(&vdpa_dev->dev, "vdpa%u", vdpa_dev->index); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = _vdpa_register_device(&adapter->vdpa, vf->nr_vring); 72362306a36Sopenharmony_ci if (ret) { 72462306a36Sopenharmony_ci put_device(&adapter->vdpa.dev); 72562306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to register to vDPA bus"); 72662306a36Sopenharmony_ci return ret; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci return 0; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev); 73762306a36Sopenharmony_ci _vdpa_unregister_device(dev); 73862306a36Sopenharmony_ci ifcvf_mgmt_dev->adapter = NULL; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic const struct vdpa_mgmtdev_ops ifcvf_vdpa_mgmt_dev_ops = { 74262306a36Sopenharmony_ci .dev_add = ifcvf_vdpa_dev_add, 74362306a36Sopenharmony_ci .dev_del = ifcvf_vdpa_dev_del 74462306a36Sopenharmony_ci}; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; 74962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 75062306a36Sopenharmony_ci struct ifcvf_hw *vf; 75162306a36Sopenharmony_ci u32 dev_type; 75262306a36Sopenharmony_ci int ret, i; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = pcim_enable_device(pdev); 75562306a36Sopenharmony_ci if (ret) { 75662306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to enable device\n"); 75762306a36Sopenharmony_ci return ret; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0) | BIT(2) | BIT(4), 76062306a36Sopenharmony_ci IFCVF_DRIVER_NAME); 76162306a36Sopenharmony_ci if (ret) { 76262306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request MMIO region\n"); 76362306a36Sopenharmony_ci return ret; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 76762306a36Sopenharmony_ci if (ret) { 76862306a36Sopenharmony_ci IFCVF_ERR(pdev, "No usable DMA configuration\n"); 76962306a36Sopenharmony_ci return ret; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, ifcvf_free_irq_vectors, pdev); 77362306a36Sopenharmony_ci if (ret) { 77462306a36Sopenharmony_ci IFCVF_ERR(pdev, 77562306a36Sopenharmony_ci "Failed for adding devres for freeing irq vectors\n"); 77662306a36Sopenharmony_ci return ret; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci pci_set_master(pdev); 78062306a36Sopenharmony_ci ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL); 78162306a36Sopenharmony_ci if (!ifcvf_mgmt_dev) { 78262306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n"); 78362306a36Sopenharmony_ci return -ENOMEM; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci vf = &ifcvf_mgmt_dev->vf; 78762306a36Sopenharmony_ci vf->dev_type = get_dev_type(pdev); 78862306a36Sopenharmony_ci vf->base = pcim_iomap_table(pdev); 78962306a36Sopenharmony_ci vf->pdev = pdev; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ret = ifcvf_init_hw(vf, pdev); 79262306a36Sopenharmony_ci if (ret) { 79362306a36Sopenharmony_ci IFCVF_ERR(pdev, "Failed to init IFCVF hw\n"); 79462306a36Sopenharmony_ci goto err; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci for (i = 0; i < vf->nr_vring; i++) 79862306a36Sopenharmony_ci vf->vring[i].irq = -EINVAL; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci vf->hw_features = ifcvf_get_hw_features(vf); 80162306a36Sopenharmony_ci vf->config_size = ifcvf_get_config_size(vf); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci dev_type = get_dev_type(pdev); 80462306a36Sopenharmony_ci switch (dev_type) { 80562306a36Sopenharmony_ci case VIRTIO_ID_NET: 80662306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.id_table = id_table_net; 80762306a36Sopenharmony_ci break; 80862306a36Sopenharmony_ci case VIRTIO_ID_BLOCK: 80962306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.id_table = id_table_blk; 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci default: 81262306a36Sopenharmony_ci IFCVF_ERR(pdev, "VIRTIO ID %u not supported\n", dev_type); 81362306a36Sopenharmony_ci ret = -EOPNOTSUPP; 81462306a36Sopenharmony_ci goto err; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops; 81862306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.device = dev; 81962306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.max_supported_vqs = vf->nr_vring; 82062306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.supported_features = vf->hw_features; 82162306a36Sopenharmony_ci ifcvf_mgmt_dev->mdev.config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ret = vdpa_mgmtdev_register(&ifcvf_mgmt_dev->mdev); 82462306a36Sopenharmony_ci if (ret) { 82562306a36Sopenharmony_ci IFCVF_ERR(pdev, 82662306a36Sopenharmony_ci "Failed to initialize the management interfaces\n"); 82762306a36Sopenharmony_ci goto err; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci pci_set_drvdata(pdev, ifcvf_mgmt_dev); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cierr: 83562306a36Sopenharmony_ci kfree(ifcvf_mgmt_dev->vf.vring); 83662306a36Sopenharmony_ci kfree(ifcvf_mgmt_dev); 83762306a36Sopenharmony_ci return ret; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic void ifcvf_remove(struct pci_dev *pdev) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci ifcvf_mgmt_dev = pci_get_drvdata(pdev); 84562306a36Sopenharmony_ci vdpa_mgmtdev_unregister(&ifcvf_mgmt_dev->mdev); 84662306a36Sopenharmony_ci kfree(ifcvf_mgmt_dev->vf.vring); 84762306a36Sopenharmony_ci kfree(ifcvf_mgmt_dev); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic struct pci_device_id ifcvf_pci_ids[] = { 85162306a36Sopenharmony_ci /* N3000 network device */ 85262306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, 85362306a36Sopenharmony_ci N3000_DEVICE_ID, 85462306a36Sopenharmony_ci PCI_VENDOR_ID_INTEL, 85562306a36Sopenharmony_ci N3000_SUBSYS_DEVICE_ID) }, 85662306a36Sopenharmony_ci /* C5000X-PL network device 85762306a36Sopenharmony_ci * F2000X-PL network device 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, 86062306a36Sopenharmony_ci VIRTIO_TRANS_ID_NET, 86162306a36Sopenharmony_ci PCI_VENDOR_ID_INTEL, 86262306a36Sopenharmony_ci VIRTIO_ID_NET) }, 86362306a36Sopenharmony_ci /* C5000X-PL block device */ 86462306a36Sopenharmony_ci { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET, 86562306a36Sopenharmony_ci VIRTIO_TRANS_ID_BLOCK, 86662306a36Sopenharmony_ci PCI_VENDOR_ID_INTEL, 86762306a36Sopenharmony_ci VIRTIO_ID_BLOCK) }, 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci { 0 }, 87062306a36Sopenharmony_ci}; 87162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ifcvf_pci_ids); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic struct pci_driver ifcvf_driver = { 87462306a36Sopenharmony_ci .name = IFCVF_DRIVER_NAME, 87562306a36Sopenharmony_ci .id_table = ifcvf_pci_ids, 87662306a36Sopenharmony_ci .probe = ifcvf_probe, 87762306a36Sopenharmony_ci .remove = ifcvf_remove, 87862306a36Sopenharmony_ci}; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cimodule_pci_driver(ifcvf_driver); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 883