18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VDPA networking device simulator. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2020, Red Hat Inc. All rights reserved. 68c2ecf20Sopenharmony_ci * Author: Jason Wang <jasowang@redhat.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/fs.h> 158c2ecf20Sopenharmony_ci#include <linux/poll.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/wait.h> 198c2ecf20Sopenharmony_ci#include <linux/uuid.h> 208c2ecf20Sopenharmony_ci#include <linux/iommu.h> 218c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 228c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 238c2ecf20Sopenharmony_ci#include <linux/file.h> 248c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 258c2ecf20Sopenharmony_ci#include <linux/vringh.h> 268c2ecf20Sopenharmony_ci#include <linux/vdpa.h> 278c2ecf20Sopenharmony_ci#include <linux/virtio_byteorder.h> 288c2ecf20Sopenharmony_ci#include <linux/vhost_iotlb.h> 298c2ecf20Sopenharmony_ci#include <uapi/linux/virtio_config.h> 308c2ecf20Sopenharmony_ci#include <uapi/linux/virtio_net.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DRV_VERSION "0.1" 338c2ecf20Sopenharmony_ci#define DRV_AUTHOR "Jason Wang <jasowang@redhat.com>" 348c2ecf20Sopenharmony_ci#define DRV_DESC "vDPA Device Simulator" 358c2ecf20Sopenharmony_ci#define DRV_LICENSE "GPL v2" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int batch_mapping = 1; 388c2ecf20Sopenharmony_cimodule_param(batch_mapping, int, 0444); 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable"); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic char *macaddr; 428c2ecf20Sopenharmony_cimodule_param(macaddr, charp, 0); 438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(macaddr, "Ethernet MAC address"); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciu8 macaddr_buf[ETH_ALEN]; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct vdpasim_virtqueue { 488c2ecf20Sopenharmony_ci struct vringh vring; 498c2ecf20Sopenharmony_ci struct vringh_kiov iov; 508c2ecf20Sopenharmony_ci unsigned short head; 518c2ecf20Sopenharmony_ci bool ready; 528c2ecf20Sopenharmony_ci u64 desc_addr; 538c2ecf20Sopenharmony_ci u64 device_addr; 548c2ecf20Sopenharmony_ci u64 driver_addr; 558c2ecf20Sopenharmony_ci u32 num; 568c2ecf20Sopenharmony_ci void *private; 578c2ecf20Sopenharmony_ci irqreturn_t (*cb)(void *data); 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define VDPASIM_QUEUE_ALIGN PAGE_SIZE 618c2ecf20Sopenharmony_ci#define VDPASIM_QUEUE_MAX 256 628c2ecf20Sopenharmony_ci#define VDPASIM_DEVICE_ID 0x1 638c2ecf20Sopenharmony_ci#define VDPASIM_VENDOR_ID 0 648c2ecf20Sopenharmony_ci#define VDPASIM_VQ_NUM 0x2 658c2ecf20Sopenharmony_ci#define VDPASIM_NAME "vdpasim-netdev" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic u64 vdpasim_features = (1ULL << VIRTIO_F_ANY_LAYOUT) | 688c2ecf20Sopenharmony_ci (1ULL << VIRTIO_F_VERSION_1) | 698c2ecf20Sopenharmony_ci (1ULL << VIRTIO_F_ACCESS_PLATFORM) | 708c2ecf20Sopenharmony_ci (1ULL << VIRTIO_NET_F_MAC); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct vdpasim; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct vdpasim_dev_attr { 758c2ecf20Sopenharmony_ci size_t config_size; 768c2ecf20Sopenharmony_ci int nvqs; 778c2ecf20Sopenharmony_ci void (*get_config)(struct vdpasim *vdpasim, void *config); 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* State of each vdpasim device */ 818c2ecf20Sopenharmony_cistruct vdpasim { 828c2ecf20Sopenharmony_ci struct vdpa_device vdpa; 838c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vqs; 848c2ecf20Sopenharmony_ci struct work_struct work; 858c2ecf20Sopenharmony_ci struct vdpasim_dev_attr dev_attr; 868c2ecf20Sopenharmony_ci /* spinlock to synchronize virtqueue state */ 878c2ecf20Sopenharmony_ci spinlock_t lock; 888c2ecf20Sopenharmony_ci /* virtio config according to device type */ 898c2ecf20Sopenharmony_ci void *config; 908c2ecf20Sopenharmony_ci struct vhost_iotlb *iommu; 918c2ecf20Sopenharmony_ci void *buffer; 928c2ecf20Sopenharmony_ci u32 status; 938c2ecf20Sopenharmony_ci u32 generation; 948c2ecf20Sopenharmony_ci u64 features; 958c2ecf20Sopenharmony_ci /* spinlock to synchronize iommu table */ 968c2ecf20Sopenharmony_ci spinlock_t iommu_lock; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* TODO: cross-endian support */ 1008c2ecf20Sopenharmony_cistatic inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return virtio_legacy_is_little_endian() || 1038c2ecf20Sopenharmony_ci (vdpasim->features & (1ULL << VIRTIO_F_VERSION_1)); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline u16 vdpasim16_to_cpu(struct vdpasim *vdpasim, __virtio16 val) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return __virtio16_to_cpu(vdpasim_is_little_endian(vdpasim), val); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline __virtio16 cpu_to_vdpasim16(struct vdpasim *vdpasim, u16 val) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return __cpu_to_virtio16(vdpasim_is_little_endian(vdpasim), val); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct vdpasim *vdpasim_dev; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return container_of(vdpa, struct vdpasim, vdpa); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct vdpasim *dev_to_sim(struct device *dev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct vdpa_device *vdpa = dev_to_vdpa(dev); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return vdpa_to_sim(vdpa); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci vringh_init_iotlb(&vq->vring, vdpasim_features, 1358c2ecf20Sopenharmony_ci VDPASIM_QUEUE_MAX, false, 1368c2ecf20Sopenharmony_ci (struct vring_desc *)(uintptr_t)vq->desc_addr, 1378c2ecf20Sopenharmony_ci (struct vring_avail *) 1388c2ecf20Sopenharmony_ci (uintptr_t)vq->driver_addr, 1398c2ecf20Sopenharmony_ci (struct vring_used *) 1408c2ecf20Sopenharmony_ci (uintptr_t)vq->device_addr); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void vdpasim_vq_reset(struct vdpasim_virtqueue *vq) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci vq->ready = false; 1468c2ecf20Sopenharmony_ci vq->desc_addr = 0; 1478c2ecf20Sopenharmony_ci vq->driver_addr = 0; 1488c2ecf20Sopenharmony_ci vq->device_addr = 0; 1498c2ecf20Sopenharmony_ci vq->cb = NULL; 1508c2ecf20Sopenharmony_ci vq->private = NULL; 1518c2ecf20Sopenharmony_ci vringh_init_iotlb(&vq->vring, vdpasim_features, VDPASIM_QUEUE_MAX, 1528c2ecf20Sopenharmony_ci false, NULL, NULL, NULL); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void vdpasim_reset(struct vdpasim *vdpasim) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int i; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nvqs; i++) 1608c2ecf20Sopenharmony_ci vdpasim_vq_reset(&vdpasim->vqs[i]); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 1638c2ecf20Sopenharmony_ci vhost_iotlb_reset(vdpasim->iommu); 1648c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci vdpasim->features = 0; 1678c2ecf20Sopenharmony_ci vdpasim->status = 0; 1688c2ecf20Sopenharmony_ci ++vdpasim->generation; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void vdpasim_work(struct work_struct *work) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = container_of(work, struct 1748c2ecf20Sopenharmony_ci vdpasim, work); 1758c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; 1768c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; 1778c2ecf20Sopenharmony_ci ssize_t read, write; 1788c2ecf20Sopenharmony_ci size_t total_write; 1798c2ecf20Sopenharmony_ci int pkts = 0; 1808c2ecf20Sopenharmony_ci int err; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci spin_lock(&vdpasim->lock); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) 1858c2ecf20Sopenharmony_ci goto out; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (!txq->ready || !rxq->ready) 1888c2ecf20Sopenharmony_ci goto out; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci while (true) { 1918c2ecf20Sopenharmony_ci total_write = 0; 1928c2ecf20Sopenharmony_ci err = vringh_getdesc_iotlb(&txq->vring, &txq->iov, NULL, 1938c2ecf20Sopenharmony_ci &txq->head, GFP_ATOMIC); 1948c2ecf20Sopenharmony_ci if (err <= 0) 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->iov, 1988c2ecf20Sopenharmony_ci &rxq->head, GFP_ATOMIC); 1998c2ecf20Sopenharmony_ci if (err <= 0) { 2008c2ecf20Sopenharmony_ci vringh_complete_iotlb(&txq->vring, txq->head, 0); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci while (true) { 2058c2ecf20Sopenharmony_ci read = vringh_iov_pull_iotlb(&txq->vring, &txq->iov, 2068c2ecf20Sopenharmony_ci vdpasim->buffer, 2078c2ecf20Sopenharmony_ci PAGE_SIZE); 2088c2ecf20Sopenharmony_ci if (read <= 0) 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci write = vringh_iov_push_iotlb(&rxq->vring, &rxq->iov, 2128c2ecf20Sopenharmony_ci vdpasim->buffer, read); 2138c2ecf20Sopenharmony_ci if (write <= 0) 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci total_write += write; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Make sure data is wrote before advancing index */ 2208c2ecf20Sopenharmony_ci smp_wmb(); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci vringh_complete_iotlb(&txq->vring, txq->head, 0); 2238c2ecf20Sopenharmony_ci vringh_complete_iotlb(&rxq->vring, rxq->head, total_write); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Make sure used is visible before rasing the interrupt. */ 2268c2ecf20Sopenharmony_ci smp_wmb(); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci local_bh_disable(); 2298c2ecf20Sopenharmony_ci if (txq->cb) 2308c2ecf20Sopenharmony_ci txq->cb(txq->private); 2318c2ecf20Sopenharmony_ci if (rxq->cb) 2328c2ecf20Sopenharmony_ci rxq->cb(rxq->private); 2338c2ecf20Sopenharmony_ci local_bh_enable(); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (++pkts > 4) { 2368c2ecf20Sopenharmony_ci schedule_work(&vdpasim->work); 2378c2ecf20Sopenharmony_ci goto out; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ciout: 2428c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->lock); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int dir_to_perm(enum dma_data_direction dir) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int perm = -EFAULT; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci switch (dir) { 2508c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 2518c2ecf20Sopenharmony_ci perm = VHOST_MAP_WO; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 2548c2ecf20Sopenharmony_ci perm = VHOST_MAP_RO; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 2578c2ecf20Sopenharmony_ci perm = VHOST_MAP_RW; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci default: 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return perm; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic dma_addr_t vdpasim_map_page(struct device *dev, struct page *page, 2678c2ecf20Sopenharmony_ci unsigned long offset, size_t size, 2688c2ecf20Sopenharmony_ci enum dma_data_direction dir, 2698c2ecf20Sopenharmony_ci unsigned long attrs) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = dev_to_sim(dev); 2728c2ecf20Sopenharmony_ci struct vhost_iotlb *iommu = vdpasim->iommu; 2738c2ecf20Sopenharmony_ci u64 pa = (page_to_pfn(page) << PAGE_SHIFT) + offset; 2748c2ecf20Sopenharmony_ci int ret, perm = dir_to_perm(dir); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (perm < 0) 2778c2ecf20Sopenharmony_ci return DMA_MAPPING_ERROR; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* For simplicity, use identical mapping to avoid e.g iova 2808c2ecf20Sopenharmony_ci * allocator. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 2838c2ecf20Sopenharmony_ci ret = vhost_iotlb_add_range(iommu, pa, pa + size - 1, 2848c2ecf20Sopenharmony_ci pa, dir_to_perm(dir)); 2858c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 2868c2ecf20Sopenharmony_ci if (ret) 2878c2ecf20Sopenharmony_ci return DMA_MAPPING_ERROR; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return (dma_addr_t)(pa); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void vdpasim_unmap_page(struct device *dev, dma_addr_t dma_addr, 2938c2ecf20Sopenharmony_ci size_t size, enum dma_data_direction dir, 2948c2ecf20Sopenharmony_ci unsigned long attrs) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = dev_to_sim(dev); 2978c2ecf20Sopenharmony_ci struct vhost_iotlb *iommu = vdpasim->iommu; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 3008c2ecf20Sopenharmony_ci vhost_iotlb_del_range(iommu, (u64)dma_addr, 3018c2ecf20Sopenharmony_ci (u64)dma_addr + size - 1); 3028c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void *vdpasim_alloc_coherent(struct device *dev, size_t size, 3068c2ecf20Sopenharmony_ci dma_addr_t *dma_addr, gfp_t flag, 3078c2ecf20Sopenharmony_ci unsigned long attrs) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = dev_to_sim(dev); 3108c2ecf20Sopenharmony_ci struct vhost_iotlb *iommu = vdpasim->iommu; 3118c2ecf20Sopenharmony_ci void *addr = kmalloc(size, flag); 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 3158c2ecf20Sopenharmony_ci if (!addr) { 3168c2ecf20Sopenharmony_ci *dma_addr = DMA_MAPPING_ERROR; 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci u64 pa = virt_to_phys(addr); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ret = vhost_iotlb_add_range(iommu, (u64)pa, 3218c2ecf20Sopenharmony_ci (u64)pa + size - 1, 3228c2ecf20Sopenharmony_ci pa, VHOST_MAP_RW); 3238c2ecf20Sopenharmony_ci if (ret) { 3248c2ecf20Sopenharmony_ci *dma_addr = DMA_MAPPING_ERROR; 3258c2ecf20Sopenharmony_ci kfree(addr); 3268c2ecf20Sopenharmony_ci addr = NULL; 3278c2ecf20Sopenharmony_ci } else 3288c2ecf20Sopenharmony_ci *dma_addr = (dma_addr_t)pa; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return addr; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void vdpasim_free_coherent(struct device *dev, size_t size, 3368c2ecf20Sopenharmony_ci void *vaddr, dma_addr_t dma_addr, 3378c2ecf20Sopenharmony_ci unsigned long attrs) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = dev_to_sim(dev); 3408c2ecf20Sopenharmony_ci struct vhost_iotlb *iommu = vdpasim->iommu; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 3438c2ecf20Sopenharmony_ci vhost_iotlb_del_range(iommu, (u64)dma_addr, 3448c2ecf20Sopenharmony_ci (u64)dma_addr + size - 1); 3458c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci kfree(phys_to_virt((uintptr_t)dma_addr)); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic const struct dma_map_ops vdpasim_dma_ops = { 3518c2ecf20Sopenharmony_ci .map_page = vdpasim_map_page, 3528c2ecf20Sopenharmony_ci .unmap_page = vdpasim_unmap_page, 3538c2ecf20Sopenharmony_ci .alloc = vdpasim_alloc_coherent, 3548c2ecf20Sopenharmony_ci .free = vdpasim_free_coherent, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_net_config_ops; 3588c2ecf20Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_net_batch_config_ops; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci const struct vdpa_config_ops *ops; 3638c2ecf20Sopenharmony_ci struct vdpasim *vdpasim; 3648c2ecf20Sopenharmony_ci struct device *dev; 3658c2ecf20Sopenharmony_ci int i, ret = -ENOMEM; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (batch_mapping) 3688c2ecf20Sopenharmony_ci ops = &vdpasim_net_batch_config_ops; 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci ops = &vdpasim_net_config_ops; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL, ops, 3738c2ecf20Sopenharmony_ci dev_attr->nvqs); 3748c2ecf20Sopenharmony_ci if (!vdpasim) 3758c2ecf20Sopenharmony_ci goto err_alloc; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci vdpasim->dev_attr = *dev_attr; 3788c2ecf20Sopenharmony_ci INIT_WORK(&vdpasim->work, vdpasim_work); 3798c2ecf20Sopenharmony_ci spin_lock_init(&vdpasim->lock); 3808c2ecf20Sopenharmony_ci spin_lock_init(&vdpasim->iommu_lock); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci dev = &vdpasim->vdpa.dev; 3838c2ecf20Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 3848c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) 3858c2ecf20Sopenharmony_ci goto err_iommu; 3868c2ecf20Sopenharmony_ci set_dma_ops(dev, &vdpasim_dma_ops); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci vdpasim->config = kzalloc(dev_attr->config_size, GFP_KERNEL); 3898c2ecf20Sopenharmony_ci if (!vdpasim->config) 3908c2ecf20Sopenharmony_ci goto err_iommu; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci vdpasim->vqs = kcalloc(dev_attr->nvqs, sizeof(struct vdpasim_virtqueue), 3938c2ecf20Sopenharmony_ci GFP_KERNEL); 3948c2ecf20Sopenharmony_ci if (!vdpasim->vqs) 3958c2ecf20Sopenharmony_ci goto err_iommu; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci vdpasim->iommu = vhost_iotlb_alloc(2048, 0); 3988c2ecf20Sopenharmony_ci if (!vdpasim->iommu) 3998c2ecf20Sopenharmony_ci goto err_iommu; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci vdpasim->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 4028c2ecf20Sopenharmony_ci if (!vdpasim->buffer) 4038c2ecf20Sopenharmony_ci goto err_iommu; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (macaddr) { 4068c2ecf20Sopenharmony_ci mac_pton(macaddr, macaddr_buf); 4078c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(macaddr_buf)) { 4088c2ecf20Sopenharmony_ci ret = -EADDRNOTAVAIL; 4098c2ecf20Sopenharmony_ci goto err_iommu; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci eth_random_addr(macaddr_buf); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci for (i = 0; i < dev_attr->nvqs; i++) 4168c2ecf20Sopenharmony_ci vringh_set_iotlb(&vdpasim->vqs[i].vring, vdpasim->iommu); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci vdpasim->vdpa.dma_dev = dev; 4198c2ecf20Sopenharmony_ci ret = vdpa_register_device(&vdpasim->vdpa); 4208c2ecf20Sopenharmony_ci if (ret) 4218c2ecf20Sopenharmony_ci goto err_iommu; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return vdpasim; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cierr_iommu: 4268c2ecf20Sopenharmony_ci put_device(dev); 4278c2ecf20Sopenharmony_cierr_alloc: 4288c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx, 4328c2ecf20Sopenharmony_ci u64 desc_area, u64 driver_area, 4338c2ecf20Sopenharmony_ci u64 device_area) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4368c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci vq->desc_addr = desc_area; 4398c2ecf20Sopenharmony_ci vq->driver_addr = driver_area; 4408c2ecf20Sopenharmony_ci vq->device_addr = device_area; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void vdpasim_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4488c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci vq->num = num; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4568c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (vq->ready) 4598c2ecf20Sopenharmony_ci schedule_work(&vdpasim->work); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void vdpasim_set_vq_cb(struct vdpa_device *vdpa, u16 idx, 4638c2ecf20Sopenharmony_ci struct vdpa_callback *cb) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4668c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci vq->cb = cb->callback; 4698c2ecf20Sopenharmony_ci vq->private = cb->private; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void vdpasim_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4758c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4768c2ecf20Sopenharmony_ci bool old_ready; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci spin_lock(&vdpasim->lock); 4798c2ecf20Sopenharmony_ci old_ready = vq->ready; 4808c2ecf20Sopenharmony_ci vq->ready = ready; 4818c2ecf20Sopenharmony_ci if (vq->ready && !old_ready) { 4828c2ecf20Sopenharmony_ci vdpasim_queue_ready(vdpasim, idx); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->lock); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic bool vdpasim_get_vq_ready(struct vdpa_device *vdpa, u16 idx) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4908c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return vq->ready; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, 4968c2ecf20Sopenharmony_ci const struct vdpa_vq_state *state) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 4998c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 5008c2ecf20Sopenharmony_ci struct vringh *vrh = &vq->vring; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci spin_lock(&vdpasim->lock); 5038c2ecf20Sopenharmony_ci vrh->last_avail_idx = state->avail_index; 5048c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->lock); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx, 5108c2ecf20Sopenharmony_ci struct vdpa_vq_state *state) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 5138c2ecf20Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 5148c2ecf20Sopenharmony_ci struct vringh *vrh = &vq->vring; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci state->avail_index = vrh->last_avail_idx; 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic u32 vdpasim_get_vq_align(struct vdpa_device *vdpa) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci return VDPASIM_QUEUE_ALIGN; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic u64 vdpasim_get_features(struct vdpa_device *vdpa) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci return vdpasim_features; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int vdpasim_set_features(struct vdpa_device *vdpa, u64 features) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* DMA mapping must be done by driver */ 5358c2ecf20Sopenharmony_ci if (!(features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci vdpasim->features = features & vdpasim_features; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic void vdpasim_set_config_cb(struct vdpa_device *vdpa, 5448c2ecf20Sopenharmony_ci struct vdpa_callback *cb) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci /* We don't support config interrupt */ 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic u16 vdpasim_get_vq_num_max(struct vdpa_device *vdpa) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci return VDPASIM_QUEUE_MAX; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic u32 vdpasim_get_device_id(struct vdpa_device *vdpa) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci return VDPASIM_DEVICE_ID; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic u32 vdpasim_get_vendor_id(struct vdpa_device *vdpa) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci return VDPASIM_VENDOR_ID; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic u8 vdpasim_get_status(struct vdpa_device *vdpa) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 5678c2ecf20Sopenharmony_ci u8 status; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci spin_lock(&vdpasim->lock); 5708c2ecf20Sopenharmony_ci status = vdpasim->status; 5718c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->lock); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return status; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci spin_lock(&vdpasim->lock); 5818c2ecf20Sopenharmony_ci vdpasim->status = status; 5828c2ecf20Sopenharmony_ci if (status == 0) 5838c2ecf20Sopenharmony_ci vdpasim_reset(vdpasim); 5848c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->lock); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic void vdpasim_get_config(struct vdpa_device *vdpa, unsigned int offset, 5888c2ecf20Sopenharmony_ci void *buf, unsigned int len) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (offset + len > vdpasim->dev_attr.config_size) 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (vdpasim->dev_attr.get_config) 5968c2ecf20Sopenharmony_ci vdpasim->dev_attr.get_config(vdpasim, vdpasim->config); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci memcpy(buf, vdpasim->config + offset, len); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic void vdpasim_set_config(struct vdpa_device *vdpa, unsigned int offset, 6028c2ecf20Sopenharmony_ci const void *buf, unsigned int len) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci /* No writable config supportted by vdpasim */ 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic u32 vdpasim_get_generation(struct vdpa_device *vdpa) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return vdpasim->generation; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic struct vdpa_iova_range vdpasim_get_iova_range(struct vdpa_device *vdpa) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct vdpa_iova_range range = { 6178c2ecf20Sopenharmony_ci .first = 0ULL, 6188c2ecf20Sopenharmony_ci .last = ULLONG_MAX, 6198c2ecf20Sopenharmony_ci }; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return range; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic int vdpasim_set_map(struct vdpa_device *vdpa, 6258c2ecf20Sopenharmony_ci struct vhost_iotlb *iotlb) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 6288c2ecf20Sopenharmony_ci struct vhost_iotlb_map *map; 6298c2ecf20Sopenharmony_ci u64 start = 0ULL, last = 0ULL - 1; 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 6338c2ecf20Sopenharmony_ci vhost_iotlb_reset(vdpasim->iommu); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci for (map = vhost_iotlb_itree_first(iotlb, start, last); map; 6368c2ecf20Sopenharmony_ci map = vhost_iotlb_itree_next(map, start, last)) { 6378c2ecf20Sopenharmony_ci ret = vhost_iotlb_add_range(vdpasim->iommu, map->start, 6388c2ecf20Sopenharmony_ci map->last, map->addr, map->perm); 6398c2ecf20Sopenharmony_ci if (ret) 6408c2ecf20Sopenharmony_ci goto err; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cierr: 6468c2ecf20Sopenharmony_ci vhost_iotlb_reset(vdpasim->iommu); 6478c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 6488c2ecf20Sopenharmony_ci return ret; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic int vdpasim_dma_map(struct vdpa_device *vdpa, u64 iova, u64 size, 6528c2ecf20Sopenharmony_ci u64 pa, u32 perm) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 6558c2ecf20Sopenharmony_ci int ret; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 6588c2ecf20Sopenharmony_ci ret = vhost_iotlb_add_range(vdpasim->iommu, iova, iova + size - 1, pa, 6598c2ecf20Sopenharmony_ci perm); 6608c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return ret; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int vdpasim_dma_unmap(struct vdpa_device *vdpa, u64 iova, u64 size) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 6708c2ecf20Sopenharmony_ci vhost_iotlb_del_range(vdpasim->iommu, iova, iova + size - 1); 6718c2ecf20Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void vdpasim_free(struct vdpa_device *vdpa) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci cancel_work_sync(&vdpasim->work); 6818c2ecf20Sopenharmony_ci kfree(vdpasim->buffer); 6828c2ecf20Sopenharmony_ci if (vdpasim->iommu) 6838c2ecf20Sopenharmony_ci vhost_iotlb_free(vdpasim->iommu); 6848c2ecf20Sopenharmony_ci kfree(vdpasim->vqs); 6858c2ecf20Sopenharmony_ci kfree(vdpasim->config); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_net_config_ops = { 6898c2ecf20Sopenharmony_ci .set_vq_address = vdpasim_set_vq_address, 6908c2ecf20Sopenharmony_ci .set_vq_num = vdpasim_set_vq_num, 6918c2ecf20Sopenharmony_ci .kick_vq = vdpasim_kick_vq, 6928c2ecf20Sopenharmony_ci .set_vq_cb = vdpasim_set_vq_cb, 6938c2ecf20Sopenharmony_ci .set_vq_ready = vdpasim_set_vq_ready, 6948c2ecf20Sopenharmony_ci .get_vq_ready = vdpasim_get_vq_ready, 6958c2ecf20Sopenharmony_ci .set_vq_state = vdpasim_set_vq_state, 6968c2ecf20Sopenharmony_ci .get_vq_state = vdpasim_get_vq_state, 6978c2ecf20Sopenharmony_ci .get_vq_align = vdpasim_get_vq_align, 6988c2ecf20Sopenharmony_ci .get_features = vdpasim_get_features, 6998c2ecf20Sopenharmony_ci .set_features = vdpasim_set_features, 7008c2ecf20Sopenharmony_ci .set_config_cb = vdpasim_set_config_cb, 7018c2ecf20Sopenharmony_ci .get_vq_num_max = vdpasim_get_vq_num_max, 7028c2ecf20Sopenharmony_ci .get_device_id = vdpasim_get_device_id, 7038c2ecf20Sopenharmony_ci .get_vendor_id = vdpasim_get_vendor_id, 7048c2ecf20Sopenharmony_ci .get_status = vdpasim_get_status, 7058c2ecf20Sopenharmony_ci .set_status = vdpasim_set_status, 7068c2ecf20Sopenharmony_ci .get_config = vdpasim_get_config, 7078c2ecf20Sopenharmony_ci .set_config = vdpasim_set_config, 7088c2ecf20Sopenharmony_ci .get_generation = vdpasim_get_generation, 7098c2ecf20Sopenharmony_ci .get_iova_range = vdpasim_get_iova_range, 7108c2ecf20Sopenharmony_ci .dma_map = vdpasim_dma_map, 7118c2ecf20Sopenharmony_ci .dma_unmap = vdpasim_dma_unmap, 7128c2ecf20Sopenharmony_ci .free = vdpasim_free, 7138c2ecf20Sopenharmony_ci}; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_net_batch_config_ops = { 7168c2ecf20Sopenharmony_ci .set_vq_address = vdpasim_set_vq_address, 7178c2ecf20Sopenharmony_ci .set_vq_num = vdpasim_set_vq_num, 7188c2ecf20Sopenharmony_ci .kick_vq = vdpasim_kick_vq, 7198c2ecf20Sopenharmony_ci .set_vq_cb = vdpasim_set_vq_cb, 7208c2ecf20Sopenharmony_ci .set_vq_ready = vdpasim_set_vq_ready, 7218c2ecf20Sopenharmony_ci .get_vq_ready = vdpasim_get_vq_ready, 7228c2ecf20Sopenharmony_ci .set_vq_state = vdpasim_set_vq_state, 7238c2ecf20Sopenharmony_ci .get_vq_state = vdpasim_get_vq_state, 7248c2ecf20Sopenharmony_ci .get_vq_align = vdpasim_get_vq_align, 7258c2ecf20Sopenharmony_ci .get_features = vdpasim_get_features, 7268c2ecf20Sopenharmony_ci .set_features = vdpasim_set_features, 7278c2ecf20Sopenharmony_ci .set_config_cb = vdpasim_set_config_cb, 7288c2ecf20Sopenharmony_ci .get_vq_num_max = vdpasim_get_vq_num_max, 7298c2ecf20Sopenharmony_ci .get_device_id = vdpasim_get_device_id, 7308c2ecf20Sopenharmony_ci .get_vendor_id = vdpasim_get_vendor_id, 7318c2ecf20Sopenharmony_ci .get_status = vdpasim_get_status, 7328c2ecf20Sopenharmony_ci .set_status = vdpasim_set_status, 7338c2ecf20Sopenharmony_ci .get_config = vdpasim_get_config, 7348c2ecf20Sopenharmony_ci .set_config = vdpasim_set_config, 7358c2ecf20Sopenharmony_ci .get_generation = vdpasim_get_generation, 7368c2ecf20Sopenharmony_ci .get_iova_range = vdpasim_get_iova_range, 7378c2ecf20Sopenharmony_ci .set_map = vdpasim_set_map, 7388c2ecf20Sopenharmony_ci .free = vdpasim_free, 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct virtio_net_config *net_config = 7448c2ecf20Sopenharmony_ci (struct virtio_net_config *)config; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); 7478c2ecf20Sopenharmony_ci net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP); 7488c2ecf20Sopenharmony_ci memcpy(net_config->mac, macaddr_buf, ETH_ALEN); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int __init vdpasim_dev_init(void) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct vdpasim_dev_attr dev_attr = {}; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci dev_attr.nvqs = VDPASIM_VQ_NUM; 7568c2ecf20Sopenharmony_ci dev_attr.config_size = sizeof(struct virtio_net_config); 7578c2ecf20Sopenharmony_ci dev_attr.get_config = vdpasim_net_get_config; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci vdpasim_dev = vdpasim_create(&dev_attr); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!IS_ERR(vdpasim_dev)) 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci return PTR_ERR(vdpasim_dev); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void __exit vdpasim_dev_exit(void) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct vdpa_device *vdpa = &vdpasim_dev->vdpa; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci vdpa_unregister_device(vdpa); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cimodule_init(vdpasim_dev_init) 7758c2ecf20Sopenharmony_cimodule_exit(vdpasim_dev_exit) 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 7788c2ecf20Sopenharmony_ciMODULE_LICENSE(DRV_LICENSE); 7798c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 7808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 781