18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel IFC VF NIC driver for virtio dataplane offloading 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Intel Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Zhu Lingshan <lingshan.zhu@intel.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 158c2ecf20Sopenharmony_ci#include "ifcvf_base.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define VERSION_STRING "0.1" 188c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Intel Corporation" 198c2ecf20Sopenharmony_ci#define IFCVF_DRIVER_NAME "ifcvf" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic irqreturn_t ifcvf_config_changed(int irq, void *arg) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = arg; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (vf->config_cb.callback) 268c2ecf20Sopenharmony_ci return vf->config_cb.callback(vf->config_cb.private); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return IRQ_HANDLED; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic irqreturn_t ifcvf_intr_handler(int irq, void *arg) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct vring_info *vring = arg; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (vring->cb.callback) 368c2ecf20Sopenharmony_ci return vring->cb.callback(vring->cb.private); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return IRQ_HANDLED; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void ifcvf_free_irq_vectors(void *data) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci pci_free_irq_vectors(data); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void ifcvf_free_irq(struct ifcvf_adapter *adapter, int queues) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 498c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = &adapter->vf; 508c2ecf20Sopenharmony_ci int i; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < queues; i++) { 548c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, vf->vring[i].irq, &vf->vring[i]); 558c2ecf20Sopenharmony_ci vf->vring[i].irq = -EINVAL; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, vf->config_irq, vf); 598c2ecf20Sopenharmony_ci ifcvf_free_irq_vectors(pdev); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int ifcvf_request_irq(struct ifcvf_adapter *adapter) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 658c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = &adapter->vf; 668c2ecf20Sopenharmony_ci int vector, i, ret, irq; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, IFCVF_MAX_INTR, 698c2ecf20Sopenharmony_ci IFCVF_MAX_INTR, PCI_IRQ_MSIX); 708c2ecf20Sopenharmony_ci if (ret < 0) { 718c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to alloc IRQ vectors\n"); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci snprintf(vf->config_msix_name, 256, "ifcvf[%s]-config\n", 768c2ecf20Sopenharmony_ci pci_name(pdev)); 778c2ecf20Sopenharmony_ci vector = 0; 788c2ecf20Sopenharmony_ci vf->config_irq = pci_irq_vector(pdev, vector); 798c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, vf->config_irq, 808c2ecf20Sopenharmony_ci ifcvf_config_changed, 0, 818c2ecf20Sopenharmony_ci vf->config_msix_name, vf); 828c2ecf20Sopenharmony_ci if (ret) { 838c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request config irq\n"); 848c2ecf20Sopenharmony_ci return ret; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) { 888c2ecf20Sopenharmony_ci snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n", 898c2ecf20Sopenharmony_ci pci_name(pdev), i); 908c2ecf20Sopenharmony_ci vector = i + IFCVF_MSI_QUEUE_OFF; 918c2ecf20Sopenharmony_ci irq = pci_irq_vector(pdev, vector); 928c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, 938c2ecf20Sopenharmony_ci ifcvf_intr_handler, 0, 948c2ecf20Sopenharmony_ci vf->vring[i].msix_name, 958c2ecf20Sopenharmony_ci &vf->vring[i]); 968c2ecf20Sopenharmony_ci if (ret) { 978c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, 988c2ecf20Sopenharmony_ci "Failed to request irq for vq %d\n", i); 998c2ecf20Sopenharmony_ci ifcvf_free_irq(adapter, i); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci vf->vring[i].irq = irq; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int ifcvf_start_datapath(void *private) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = ifcvf_private_to_vf(private); 1138c2ecf20Sopenharmony_ci u8 status; 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci vf->nr_vring = IFCVF_MAX_QUEUE_PAIRS * 2; 1178c2ecf20Sopenharmony_ci ret = ifcvf_start_hw(vf); 1188c2ecf20Sopenharmony_ci if (ret < 0) { 1198c2ecf20Sopenharmony_ci status = ifcvf_get_status(vf); 1208c2ecf20Sopenharmony_ci status |= VIRTIO_CONFIG_S_FAILED; 1218c2ecf20Sopenharmony_ci ifcvf_set_status(vf, status); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return ret; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int ifcvf_stop_datapath(void *private) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = ifcvf_private_to_vf(private); 1308c2ecf20Sopenharmony_ci int i; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) 1338c2ecf20Sopenharmony_ci vf->vring[i].cb.callback = NULL; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ifcvf_stop_hw(vf); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void ifcvf_reset_vring(struct ifcvf_adapter *adapter) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = ifcvf_private_to_vf(adapter); 1438c2ecf20Sopenharmony_ci int i; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) { 1468c2ecf20Sopenharmony_ci vf->vring[i].last_avail_idx = 0; 1478c2ecf20Sopenharmony_ci vf->vring[i].desc = 0; 1488c2ecf20Sopenharmony_ci vf->vring[i].avail = 0; 1498c2ecf20Sopenharmony_ci vf->vring[i].used = 0; 1508c2ecf20Sopenharmony_ci vf->vring[i].ready = 0; 1518c2ecf20Sopenharmony_ci vf->vring[i].cb.callback = NULL; 1528c2ecf20Sopenharmony_ci vf->vring[i].cb.private = NULL; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ifcvf_reset(vf); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic struct ifcvf_adapter *vdpa_to_adapter(struct vdpa_device *vdpa_dev) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return container_of(vdpa_dev, struct ifcvf_adapter, vdpa); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return &adapter->vf; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic u64 ifcvf_vdpa_get_features(struct vdpa_device *vdpa_dev) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 1738c2ecf20Sopenharmony_ci u64 features; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci features = ifcvf_get_features(vf) & IFCVF_SUPPORTED_FEATURES; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return features; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int ifcvf_vdpa_set_features(struct vdpa_device *vdpa_dev, u64 features) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci vf->req_features = features; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic u8 ifcvf_vdpa_get_status(struct vdpa_device *vdpa_dev) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return ifcvf_get_status(vf); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct ifcvf_adapter *adapter; 1998c2ecf20Sopenharmony_ci struct ifcvf_hw *vf; 2008c2ecf20Sopenharmony_ci u8 status_old; 2018c2ecf20Sopenharmony_ci int ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci vf = vdpa_to_vf(vdpa_dev); 2048c2ecf20Sopenharmony_ci adapter = dev_get_drvdata(vdpa_dev->dev.parent); 2058c2ecf20Sopenharmony_ci status_old = ifcvf_get_status(vf); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (status_old == status) 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if ((status_old & VIRTIO_CONFIG_S_DRIVER_OK) && 2118c2ecf20Sopenharmony_ci !(status & VIRTIO_CONFIG_S_DRIVER_OK)) { 2128c2ecf20Sopenharmony_ci ifcvf_stop_datapath(adapter); 2138c2ecf20Sopenharmony_ci ifcvf_free_irq(adapter, IFCVF_MAX_QUEUE_PAIRS * 2); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (status == 0) { 2178c2ecf20Sopenharmony_ci ifcvf_reset_vring(adapter); 2188c2ecf20Sopenharmony_ci return; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && 2228c2ecf20Sopenharmony_ci !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { 2238c2ecf20Sopenharmony_ci ret = ifcvf_request_irq(adapter); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci status = ifcvf_get_status(vf); 2268c2ecf20Sopenharmony_ci status |= VIRTIO_CONFIG_S_FAILED; 2278c2ecf20Sopenharmony_ci ifcvf_set_status(vf, status); 2288c2ecf20Sopenharmony_ci return; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (ifcvf_start_datapath(adapter) < 0) 2328c2ecf20Sopenharmony_ci IFCVF_ERR(adapter->pdev, 2338c2ecf20Sopenharmony_ci "Failed to set ifcvf vdpa status %u\n", 2348c2ecf20Sopenharmony_ci status); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ifcvf_set_status(vf, status); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic u16 ifcvf_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci return IFCVF_QUEUE_MAX; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 2468c2ecf20Sopenharmony_ci struct vdpa_vq_state *state) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci state->avail_index = ifcvf_get_vq_state(vf, qid); 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid, 2558c2ecf20Sopenharmony_ci const struct vdpa_vq_state *state) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return ifcvf_set_vq_state(vf, qid, state->avail_index); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid, 2638c2ecf20Sopenharmony_ci struct vdpa_callback *cb) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci vf->vring[qid].cb = *cb; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, 2718c2ecf20Sopenharmony_ci u16 qid, bool ready) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci vf->vring[qid].ready = ready; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic bool ifcvf_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return vf->vring[qid].ready; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid, 2868c2ecf20Sopenharmony_ci u32 num) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci vf->vring[qid].size = num; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int ifcvf_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid, 2948c2ecf20Sopenharmony_ci u64 desc_area, u64 driver_area, 2958c2ecf20Sopenharmony_ci u64 device_area) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci vf->vring[qid].desc = desc_area; 3008c2ecf20Sopenharmony_ci vf->vring[qid].avail = driver_area; 3018c2ecf20Sopenharmony_ci vf->vring[qid].used = device_area; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ifcvf_notify_queue(vf, qid); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic u32 ifcvf_vdpa_get_generation(struct vdpa_device *vdpa_dev) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return ioread8(&vf->common_cfg->config_generation); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic u32 ifcvf_vdpa_get_device_id(struct vdpa_device *vdpa_dev) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci return VIRTIO_ID_NET; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic u32 ifcvf_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci return IFCVF_SUBSYS_VENDOR_ID; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic u32 ifcvf_vdpa_get_vq_align(struct vdpa_device *vdpa_dev) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci return IFCVF_QUEUE_ALIGNMENT; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_get_config(struct vdpa_device *vdpa_dev, 3368c2ecf20Sopenharmony_ci unsigned int offset, 3378c2ecf20Sopenharmony_ci void *buf, unsigned int len) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci WARN_ON(offset + len > sizeof(struct virtio_net_config)); 3428c2ecf20Sopenharmony_ci ifcvf_read_net_config(vf, offset, buf, len); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_config(struct vdpa_device *vdpa_dev, 3468c2ecf20Sopenharmony_ci unsigned int offset, const void *buf, 3478c2ecf20Sopenharmony_ci unsigned int len) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci WARN_ON(offset + len > sizeof(struct virtio_net_config)); 3528c2ecf20Sopenharmony_ci ifcvf_write_net_config(vf, offset, buf, len); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void ifcvf_vdpa_set_config_cb(struct vdpa_device *vdpa_dev, 3568c2ecf20Sopenharmony_ci struct vdpa_callback *cb) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci vf->config_cb.callback = cb->callback; 3618c2ecf20Sopenharmony_ci vf->config_cb.private = cb->private; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev, 3658c2ecf20Sopenharmony_ci u16 qid) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return vf->vring[qid].irq; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 3738c2ecf20Sopenharmony_ci * IFCVF currently does't have on-chip IOMMU, so not 3748c2ecf20Sopenharmony_ci * implemented set_map()/dma_map()/dma_unmap() 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_cistatic const struct vdpa_config_ops ifc_vdpa_ops = { 3778c2ecf20Sopenharmony_ci .get_features = ifcvf_vdpa_get_features, 3788c2ecf20Sopenharmony_ci .set_features = ifcvf_vdpa_set_features, 3798c2ecf20Sopenharmony_ci .get_status = ifcvf_vdpa_get_status, 3808c2ecf20Sopenharmony_ci .set_status = ifcvf_vdpa_set_status, 3818c2ecf20Sopenharmony_ci .get_vq_num_max = ifcvf_vdpa_get_vq_num_max, 3828c2ecf20Sopenharmony_ci .get_vq_state = ifcvf_vdpa_get_vq_state, 3838c2ecf20Sopenharmony_ci .set_vq_state = ifcvf_vdpa_set_vq_state, 3848c2ecf20Sopenharmony_ci .set_vq_cb = ifcvf_vdpa_set_vq_cb, 3858c2ecf20Sopenharmony_ci .set_vq_ready = ifcvf_vdpa_set_vq_ready, 3868c2ecf20Sopenharmony_ci .get_vq_ready = ifcvf_vdpa_get_vq_ready, 3878c2ecf20Sopenharmony_ci .set_vq_num = ifcvf_vdpa_set_vq_num, 3888c2ecf20Sopenharmony_ci .set_vq_address = ifcvf_vdpa_set_vq_address, 3898c2ecf20Sopenharmony_ci .get_vq_irq = ifcvf_vdpa_get_vq_irq, 3908c2ecf20Sopenharmony_ci .kick_vq = ifcvf_vdpa_kick_vq, 3918c2ecf20Sopenharmony_ci .get_generation = ifcvf_vdpa_get_generation, 3928c2ecf20Sopenharmony_ci .get_device_id = ifcvf_vdpa_get_device_id, 3938c2ecf20Sopenharmony_ci .get_vendor_id = ifcvf_vdpa_get_vendor_id, 3948c2ecf20Sopenharmony_ci .get_vq_align = ifcvf_vdpa_get_vq_align, 3958c2ecf20Sopenharmony_ci .get_config = ifcvf_vdpa_get_config, 3968c2ecf20Sopenharmony_ci .set_config = ifcvf_vdpa_set_config, 3978c2ecf20Sopenharmony_ci .set_config_cb = ifcvf_vdpa_set_config_cb, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4038c2ecf20Sopenharmony_ci struct ifcvf_adapter *adapter; 4048c2ecf20Sopenharmony_ci struct ifcvf_hw *vf; 4058c2ecf20Sopenharmony_ci int ret, i; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 4088c2ecf20Sopenharmony_ci if (ret) { 4098c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to enable device\n"); 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0) | BIT(2) | BIT(4), 4148c2ecf20Sopenharmony_ci IFCVF_DRIVER_NAME); 4158c2ecf20Sopenharmony_ci if (ret) { 4168c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to request MMIO region\n"); 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 4218c2ecf20Sopenharmony_ci if (ret) { 4228c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "No usable DMA confiugration\n"); 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 4278c2ecf20Sopenharmony_ci if (ret) { 4288c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, 4298c2ecf20Sopenharmony_ci "No usable coherent DMA confiugration\n"); 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, ifcvf_free_irq_vectors, pdev); 4348c2ecf20Sopenharmony_ci if (ret) { 4358c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, 4368c2ecf20Sopenharmony_ci "Failed for adding devres for freeing irq vectors\n"); 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, 4418c2ecf20Sopenharmony_ci dev, &ifc_vdpa_ops, 4428c2ecf20Sopenharmony_ci IFCVF_MAX_QUEUE_PAIRS * 2); 4438c2ecf20Sopenharmony_ci if (adapter == NULL) { 4448c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); 4458c2ecf20Sopenharmony_ci return -ENOMEM; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci pci_set_master(pdev); 4498c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci vf = &adapter->vf; 4528c2ecf20Sopenharmony_ci vf->base = pcim_iomap_table(pdev); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci adapter->pdev = pdev; 4558c2ecf20Sopenharmony_ci adapter->vdpa.dma_dev = &pdev->dev; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci ret = ifcvf_init_hw(vf, pdev); 4588c2ecf20Sopenharmony_ci if (ret) { 4598c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to init IFCVF hw\n"); 4608c2ecf20Sopenharmony_ci goto err; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) 4648c2ecf20Sopenharmony_ci vf->vring[i].irq = -EINVAL; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci ret = vdpa_register_device(&adapter->vdpa); 4678c2ecf20Sopenharmony_ci if (ret) { 4688c2ecf20Sopenharmony_ci IFCVF_ERR(pdev, "Failed to register ifcvf to vdpa bus"); 4698c2ecf20Sopenharmony_ci goto err; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cierr: 4758c2ecf20Sopenharmony_ci put_device(&adapter->vdpa.dev); 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void ifcvf_remove(struct pci_dev *pdev) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct ifcvf_adapter *adapter = pci_get_drvdata(pdev); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci vdpa_unregister_device(&adapter->vdpa); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic struct pci_device_id ifcvf_pci_ids[] = { 4878c2ecf20Sopenharmony_ci { PCI_DEVICE_SUB(IFCVF_VENDOR_ID, 4888c2ecf20Sopenharmony_ci IFCVF_DEVICE_ID, 4898c2ecf20Sopenharmony_ci IFCVF_SUBSYS_VENDOR_ID, 4908c2ecf20Sopenharmony_ci IFCVF_SUBSYS_DEVICE_ID) }, 4918c2ecf20Sopenharmony_ci { 0 }, 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ifcvf_pci_ids); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic struct pci_driver ifcvf_driver = { 4968c2ecf20Sopenharmony_ci .name = IFCVF_DRIVER_NAME, 4978c2ecf20Sopenharmony_ci .id_table = ifcvf_pci_ids, 4988c2ecf20Sopenharmony_ci .probe = ifcvf_probe, 4998c2ecf20Sopenharmony_ci .remove = ifcvf_remove, 5008c2ecf20Sopenharmony_ci}; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cimodule_pci_driver(ifcvf_driver); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5058c2ecf20Sopenharmony_ciMODULE_VERSION(VERSION_STRING); 506