162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * VDPA device simulator core. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020, Red Hat Inc. All rights reserved. 662306a36Sopenharmony_ci * Author: Jason Wang <jasowang@redhat.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/kthread.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 1762306a36Sopenharmony_ci#include <linux/vringh.h> 1862306a36Sopenharmony_ci#include <linux/vdpa.h> 1962306a36Sopenharmony_ci#include <linux/vhost_iotlb.h> 2062306a36Sopenharmony_ci#include <uapi/linux/vdpa.h> 2162306a36Sopenharmony_ci#include <uapi/linux/vhost_types.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "vdpa_sim.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DRV_VERSION "0.1" 2662306a36Sopenharmony_ci#define DRV_AUTHOR "Jason Wang <jasowang@redhat.com>" 2762306a36Sopenharmony_ci#define DRV_DESC "vDPA Device Simulator core" 2862306a36Sopenharmony_ci#define DRV_LICENSE "GPL v2" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int batch_mapping = 1; 3162306a36Sopenharmony_cimodule_param(batch_mapping, int, 0444); 3262306a36Sopenharmony_ciMODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int max_iotlb_entries = 2048; 3562306a36Sopenharmony_cimodule_param(max_iotlb_entries, int, 0444); 3662306a36Sopenharmony_ciMODULE_PARM_DESC(max_iotlb_entries, 3762306a36Sopenharmony_ci "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)"); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic bool use_va = true; 4062306a36Sopenharmony_cimodule_param(use_va, bool, 0444); 4162306a36Sopenharmony_ciMODULE_PARM_DESC(use_va, "Enable/disable the device's ability to use VA"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define VDPASIM_QUEUE_ALIGN PAGE_SIZE 4462306a36Sopenharmony_ci#define VDPASIM_QUEUE_MAX 256 4562306a36Sopenharmony_ci#define VDPASIM_VENDOR_ID 0 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct vdpasim_mm_work { 4862306a36Sopenharmony_ci struct kthread_work work; 4962306a36Sopenharmony_ci struct vdpasim *vdpasim; 5062306a36Sopenharmony_ci struct mm_struct *mm_to_bind; 5162306a36Sopenharmony_ci int ret; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void vdpasim_mm_work_fn(struct kthread_work *work) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct vdpasim_mm_work *mm_work = 5762306a36Sopenharmony_ci container_of(work, struct vdpasim_mm_work, work); 5862306a36Sopenharmony_ci struct vdpasim *vdpasim = mm_work->vdpasim; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci mm_work->ret = 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci //TODO: should we attach the cgroup of the mm owner? 6362306a36Sopenharmony_ci vdpasim->mm_bound = mm_work->mm_to_bind; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void vdpasim_worker_change_mm_sync(struct vdpasim *vdpasim, 6762306a36Sopenharmony_ci struct vdpasim_mm_work *mm_work) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct kthread_work *work = &mm_work->work; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci kthread_init_work(work, vdpasim_mm_work_fn); 7262306a36Sopenharmony_ci kthread_queue_work(vdpasim->worker, work); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci kthread_flush_work(work); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return container_of(vdpa, struct vdpasim, vdpa); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void vdpasim_vq_notify(struct vringh *vring) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = 8562306a36Sopenharmony_ci container_of(vring, struct vdpasim_virtqueue, vring); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!vq->cb) 8862306a36Sopenharmony_ci return; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci vq->cb(vq->private); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 9662306a36Sopenharmony_ci uint16_t last_avail_idx = vq->vring.last_avail_idx; 9762306a36Sopenharmony_ci struct vring_desc *desc = (struct vring_desc *) 9862306a36Sopenharmony_ci (uintptr_t)vq->desc_addr; 9962306a36Sopenharmony_ci struct vring_avail *avail = (struct vring_avail *) 10062306a36Sopenharmony_ci (uintptr_t)vq->driver_addr; 10162306a36Sopenharmony_ci struct vring_used *used = (struct vring_used *) 10262306a36Sopenharmony_ci (uintptr_t)vq->device_addr; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (use_va && vdpasim->mm_bound) { 10562306a36Sopenharmony_ci vringh_init_iotlb_va(&vq->vring, vdpasim->features, vq->num, 10662306a36Sopenharmony_ci true, desc, avail, used); 10762306a36Sopenharmony_ci } else { 10862306a36Sopenharmony_ci vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, 10962306a36Sopenharmony_ci true, desc, avail, used); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci vq->vring.last_avail_idx = last_avail_idx; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * Since vdpa_sim does not support receive inflight descriptors as a 11662306a36Sopenharmony_ci * destination of a migration, let's set both avail_idx and used_idx 11762306a36Sopenharmony_ci * the same at vq start. This is how vhost-user works in a 11862306a36Sopenharmony_ci * VHOST_SET_VRING_BASE call. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Although the simple fix is to set last_used_idx at 12162306a36Sopenharmony_ci * vdpasim_set_vq_state, it would be reset at vdpasim_queue_ready. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci vq->vring.last_used_idx = last_avail_idx; 12462306a36Sopenharmony_ci vq->vring.notify = vdpasim_vq_notify; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void vdpasim_vq_reset(struct vdpasim *vdpasim, 12862306a36Sopenharmony_ci struct vdpasim_virtqueue *vq) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci vq->ready = false; 13162306a36Sopenharmony_ci vq->desc_addr = 0; 13262306a36Sopenharmony_ci vq->driver_addr = 0; 13362306a36Sopenharmony_ci vq->device_addr = 0; 13462306a36Sopenharmony_ci vq->cb = NULL; 13562306a36Sopenharmony_ci vq->private = NULL; 13662306a36Sopenharmony_ci vringh_init_iotlb(&vq->vring, vdpasim->dev_attr.supported_features, 13762306a36Sopenharmony_ci VDPASIM_QUEUE_MAX, false, NULL, NULL, NULL); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci vq->vring.notify = NULL; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void vdpasim_do_reset(struct vdpasim *vdpasim) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int i; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { 14962306a36Sopenharmony_ci vdpasim_vq_reset(vdpasim, &vdpasim->vqs[i]); 15062306a36Sopenharmony_ci vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0], 15162306a36Sopenharmony_ci &vdpasim->iommu_lock); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nas; i++) { 15562306a36Sopenharmony_ci vhost_iotlb_reset(&vdpasim->iommu[i]); 15662306a36Sopenharmony_ci vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX, 15762306a36Sopenharmony_ci 0, VHOST_MAP_RW); 15862306a36Sopenharmony_ci vdpasim->iommu_pt[i] = true; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci vdpasim->running = false; 16262306a36Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci vdpasim->features = 0; 16562306a36Sopenharmony_ci vdpasim->status = 0; 16662306a36Sopenharmony_ci ++vdpasim->generation; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_config_ops; 17062306a36Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_batch_config_ops; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void vdpasim_work_fn(struct kthread_work *work) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); 17562306a36Sopenharmony_ci struct mm_struct *mm = vdpasim->mm_bound; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (use_va && mm) { 17862306a36Sopenharmony_ci if (!mmget_not_zero(mm)) 17962306a36Sopenharmony_ci return; 18062306a36Sopenharmony_ci kthread_use_mm(mm); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci vdpasim->dev_attr.work_fn(vdpasim); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (use_va && mm) { 18662306a36Sopenharmony_ci kthread_unuse_mm(mm); 18762306a36Sopenharmony_ci mmput(mm); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistruct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, 19262306a36Sopenharmony_ci const struct vdpa_dev_set_config *config) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci const struct vdpa_config_ops *ops; 19562306a36Sopenharmony_ci struct vdpa_device *vdpa; 19662306a36Sopenharmony_ci struct vdpasim *vdpasim; 19762306a36Sopenharmony_ci struct device *dev; 19862306a36Sopenharmony_ci int i, ret = -ENOMEM; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!dev_attr->alloc_size) 20162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { 20462306a36Sopenharmony_ci if (config->device_features & 20562306a36Sopenharmony_ci ~dev_attr->supported_features) 20662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 20762306a36Sopenharmony_ci dev_attr->supported_features = 20862306a36Sopenharmony_ci config->device_features; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (batch_mapping) 21262306a36Sopenharmony_ci ops = &vdpasim_batch_config_ops; 21362306a36Sopenharmony_ci else 21462306a36Sopenharmony_ci ops = &vdpasim_config_ops; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci vdpa = __vdpa_alloc_device(NULL, ops, 21762306a36Sopenharmony_ci dev_attr->ngroups, dev_attr->nas, 21862306a36Sopenharmony_ci dev_attr->alloc_size, 21962306a36Sopenharmony_ci dev_attr->name, use_va); 22062306a36Sopenharmony_ci if (IS_ERR(vdpa)) { 22162306a36Sopenharmony_ci ret = PTR_ERR(vdpa); 22262306a36Sopenharmony_ci goto err_alloc; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci vdpasim = vdpa_to_sim(vdpa); 22662306a36Sopenharmony_ci vdpasim->dev_attr = *dev_attr; 22762306a36Sopenharmony_ci dev = &vdpasim->vdpa.dev; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci kthread_init_work(&vdpasim->work, vdpasim_work_fn); 23062306a36Sopenharmony_ci vdpasim->worker = kthread_create_worker(0, "vDPA sim worker: %s", 23162306a36Sopenharmony_ci dev_attr->name); 23262306a36Sopenharmony_ci if (IS_ERR(vdpasim->worker)) 23362306a36Sopenharmony_ci goto err_iommu; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci mutex_init(&vdpasim->mutex); 23662306a36Sopenharmony_ci spin_lock_init(&vdpasim->iommu_lock); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 23962306a36Sopenharmony_ci if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) 24062306a36Sopenharmony_ci goto err_iommu; 24162306a36Sopenharmony_ci vdpasim->vdpa.mdev = dev_attr->mgmt_dev; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci vdpasim->config = kzalloc(dev_attr->config_size, GFP_KERNEL); 24462306a36Sopenharmony_ci if (!vdpasim->config) 24562306a36Sopenharmony_ci goto err_iommu; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci vdpasim->vqs = kcalloc(dev_attr->nvqs, sizeof(struct vdpasim_virtqueue), 24862306a36Sopenharmony_ci GFP_KERNEL); 24962306a36Sopenharmony_ci if (!vdpasim->vqs) 25062306a36Sopenharmony_ci goto err_iommu; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci vdpasim->iommu = kmalloc_array(vdpasim->dev_attr.nas, 25362306a36Sopenharmony_ci sizeof(*vdpasim->iommu), GFP_KERNEL); 25462306a36Sopenharmony_ci if (!vdpasim->iommu) 25562306a36Sopenharmony_ci goto err_iommu; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci vdpasim->iommu_pt = kmalloc_array(vdpasim->dev_attr.nas, 25862306a36Sopenharmony_ci sizeof(*vdpasim->iommu_pt), GFP_KERNEL); 25962306a36Sopenharmony_ci if (!vdpasim->iommu_pt) 26062306a36Sopenharmony_ci goto err_iommu; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nas; i++) 26362306a36Sopenharmony_ci vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci for (i = 0; i < dev_attr->nvqs; i++) 26662306a36Sopenharmony_ci vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0], 26762306a36Sopenharmony_ci &vdpasim->iommu_lock); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci vdpasim->vdpa.dma_dev = dev; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return vdpasim; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cierr_iommu: 27462306a36Sopenharmony_ci put_device(dev); 27562306a36Sopenharmony_cierr_alloc: 27662306a36Sopenharmony_ci return ERR_PTR(ret); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vdpasim_create); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid vdpasim_schedule_work(struct vdpasim *vdpasim) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci kthread_queue_work(vdpasim->worker, &vdpasim->work); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vdpasim_schedule_work); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx, 28762306a36Sopenharmony_ci u64 desc_area, u64 driver_area, 28862306a36Sopenharmony_ci u64 device_area) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 29162306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci vq->desc_addr = desc_area; 29462306a36Sopenharmony_ci vq->driver_addr = driver_area; 29562306a36Sopenharmony_ci vq->device_addr = device_area; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void vdpasim_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 30362306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci vq->num = num; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 31162306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!vdpasim->running && 31462306a36Sopenharmony_ci (vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) { 31562306a36Sopenharmony_ci vdpasim->pending_kick = true; 31662306a36Sopenharmony_ci return; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (vq->ready) 32062306a36Sopenharmony_ci vdpasim_schedule_work(vdpasim); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void vdpasim_set_vq_cb(struct vdpa_device *vdpa, u16 idx, 32462306a36Sopenharmony_ci struct vdpa_callback *cb) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 32762306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci vq->cb = cb->callback; 33062306a36Sopenharmony_ci vq->private = cb->private; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void vdpasim_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 33662306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 33762306a36Sopenharmony_ci bool old_ready; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 34062306a36Sopenharmony_ci old_ready = vq->ready; 34162306a36Sopenharmony_ci vq->ready = ready; 34262306a36Sopenharmony_ci if (vq->ready && !old_ready) { 34362306a36Sopenharmony_ci vdpasim_queue_ready(vdpasim, idx); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic bool vdpasim_get_vq_ready(struct vdpa_device *vdpa, u16 idx) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 35162306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return vq->ready; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, 35762306a36Sopenharmony_ci const struct vdpa_vq_state *state) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 36062306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 36162306a36Sopenharmony_ci struct vringh *vrh = &vq->vring; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 36462306a36Sopenharmony_ci vrh->last_avail_idx = state->split.avail_index; 36562306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx, 37162306a36Sopenharmony_ci struct vdpa_vq_state *state) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 37462306a36Sopenharmony_ci struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; 37562306a36Sopenharmony_ci struct vringh *vrh = &vq->vring; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci state->split.avail_index = vrh->last_avail_idx; 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int vdpasim_get_vq_stats(struct vdpa_device *vdpa, u16 idx, 38262306a36Sopenharmony_ci struct sk_buff *msg, 38362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (vdpasim->dev_attr.get_stats) 38862306a36Sopenharmony_ci return vdpasim->dev_attr.get_stats(vdpasim, idx, 38962306a36Sopenharmony_ci msg, extack); 39062306a36Sopenharmony_ci return -EOPNOTSUPP; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic u32 vdpasim_get_vq_align(struct vdpa_device *vdpa) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci return VDPASIM_QUEUE_ALIGN; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic u32 vdpasim_get_vq_group(struct vdpa_device *vdpa, u16 idx) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci /* RX and TX belongs to group 0, CVQ belongs to group 1 */ 40162306a36Sopenharmony_ci if (idx == 2) 40262306a36Sopenharmony_ci return 1; 40362306a36Sopenharmony_ci else 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic u64 vdpasim_get_device_features(struct vdpa_device *vdpa) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return vdpasim->dev_attr.supported_features; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic u64 vdpasim_get_backend_features(const struct vdpa_device *vdpa) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci return BIT_ULL(VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int vdpasim_set_driver_features(struct vdpa_device *vdpa, u64 features) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* DMA mapping must be done by driver */ 42462306a36Sopenharmony_ci if (!(features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) 42562306a36Sopenharmony_ci return -EINVAL; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci vdpasim->features = features & vdpasim->dev_attr.supported_features; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic u64 vdpasim_get_driver_features(struct vdpa_device *vdpa) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return vdpasim->features; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void vdpasim_set_config_cb(struct vdpa_device *vdpa, 44062306a36Sopenharmony_ci struct vdpa_callback *cb) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci /* We don't support config interrupt */ 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic u16 vdpasim_get_vq_num_max(struct vdpa_device *vdpa) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci return VDPASIM_QUEUE_MAX; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic u32 vdpasim_get_device_id(struct vdpa_device *vdpa) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return vdpasim->dev_attr.id; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic u32 vdpasim_get_vendor_id(struct vdpa_device *vdpa) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci return VDPASIM_VENDOR_ID; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic u8 vdpasim_get_status(struct vdpa_device *vdpa) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 46562306a36Sopenharmony_ci u8 status; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 46862306a36Sopenharmony_ci status = vdpasim->status; 46962306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return status; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 47962306a36Sopenharmony_ci vdpasim->status = status; 48062306a36Sopenharmony_ci vdpasim->running = (status & VIRTIO_CONFIG_S_DRIVER_OK) != 0; 48162306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int vdpasim_reset(struct vdpa_device *vdpa) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 48962306a36Sopenharmony_ci vdpasim->status = 0; 49062306a36Sopenharmony_ci vdpasim_do_reset(vdpasim); 49162306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int vdpasim_suspend(struct vdpa_device *vdpa) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 50162306a36Sopenharmony_ci vdpasim->running = false; 50262306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int vdpasim_resume(struct vdpa_device *vdpa) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 51062306a36Sopenharmony_ci int i; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 51362306a36Sopenharmony_ci vdpasim->running = true; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (vdpasim->pending_kick) { 51662306a36Sopenharmony_ci /* Process pending descriptors */ 51762306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nvqs; ++i) 51862306a36Sopenharmony_ci vdpasim_kick_vq(vdpa, i); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci vdpasim->pending_kick = false; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic size_t vdpasim_get_config_size(struct vdpa_device *vdpa) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return vdpasim->dev_attr.config_size; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void vdpasim_get_config(struct vdpa_device *vdpa, unsigned int offset, 53662306a36Sopenharmony_ci void *buf, unsigned int len) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (offset + len > vdpasim->dev_attr.config_size) 54162306a36Sopenharmony_ci return; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (vdpasim->dev_attr.get_config) 54462306a36Sopenharmony_ci vdpasim->dev_attr.get_config(vdpasim, vdpasim->config); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci memcpy(buf, vdpasim->config + offset, len); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void vdpasim_set_config(struct vdpa_device *vdpa, unsigned int offset, 55062306a36Sopenharmony_ci const void *buf, unsigned int len) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (offset + len > vdpasim->dev_attr.config_size) 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci memcpy(vdpasim->config + offset, buf, len); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (vdpasim->dev_attr.set_config) 56062306a36Sopenharmony_ci vdpasim->dev_attr.set_config(vdpasim, vdpasim->config); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic u32 vdpasim_get_generation(struct vdpa_device *vdpa) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return vdpasim->generation; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic struct vdpa_iova_range vdpasim_get_iova_range(struct vdpa_device *vdpa) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct vdpa_iova_range range = { 57362306a36Sopenharmony_ci .first = 0ULL, 57462306a36Sopenharmony_ci .last = ULLONG_MAX, 57562306a36Sopenharmony_ci }; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return range; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int vdpasim_set_group_asid(struct vdpa_device *vdpa, unsigned int group, 58162306a36Sopenharmony_ci unsigned int asid) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 58462306a36Sopenharmony_ci struct vhost_iotlb *iommu; 58562306a36Sopenharmony_ci int i; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (group > vdpasim->dev_attr.ngroups) 58862306a36Sopenharmony_ci return -EINVAL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (asid >= vdpasim->dev_attr.nas) 59162306a36Sopenharmony_ci return -EINVAL; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci iommu = &vdpasim->iommu[asid]; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mutex_lock(&vdpasim->mutex); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nvqs; i++) 59862306a36Sopenharmony_ci if (vdpasim_get_vq_group(vdpa, i) == group) 59962306a36Sopenharmony_ci vringh_set_iotlb(&vdpasim->vqs[i].vring, iommu, 60062306a36Sopenharmony_ci &vdpasim->iommu_lock); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci mutex_unlock(&vdpasim->mutex); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int vdpasim_set_map(struct vdpa_device *vdpa, unsigned int asid, 60862306a36Sopenharmony_ci struct vhost_iotlb *iotlb) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 61162306a36Sopenharmony_ci struct vhost_iotlb_map *map; 61262306a36Sopenharmony_ci struct vhost_iotlb *iommu; 61362306a36Sopenharmony_ci u64 start = 0ULL, last = 0ULL - 1; 61462306a36Sopenharmony_ci int ret; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (asid >= vdpasim->dev_attr.nas) 61762306a36Sopenharmony_ci return -EINVAL; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci iommu = &vdpasim->iommu[asid]; 62262306a36Sopenharmony_ci vhost_iotlb_reset(iommu); 62362306a36Sopenharmony_ci vdpasim->iommu_pt[asid] = false; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci for (map = vhost_iotlb_itree_first(iotlb, start, last); map; 62662306a36Sopenharmony_ci map = vhost_iotlb_itree_next(map, start, last)) { 62762306a36Sopenharmony_ci ret = vhost_iotlb_add_range(iommu, map->start, 62862306a36Sopenharmony_ci map->last, map->addr, map->perm); 62962306a36Sopenharmony_ci if (ret) 63062306a36Sopenharmony_ci goto err; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cierr: 63662306a36Sopenharmony_ci vhost_iotlb_reset(iommu); 63762306a36Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int vdpasim_bind_mm(struct vdpa_device *vdpa, struct mm_struct *mm) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 64462306a36Sopenharmony_ci struct vdpasim_mm_work mm_work; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci mm_work.vdpasim = vdpasim; 64762306a36Sopenharmony_ci mm_work.mm_to_bind = mm; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci vdpasim_worker_change_mm_sync(vdpasim, &mm_work); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return mm_work.ret; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic void vdpasim_unbind_mm(struct vdpa_device *vdpa) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 65762306a36Sopenharmony_ci struct vdpasim_mm_work mm_work; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci mm_work.vdpasim = vdpasim; 66062306a36Sopenharmony_ci mm_work.mm_to_bind = NULL; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci vdpasim_worker_change_mm_sync(vdpasim, &mm_work); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int vdpasim_dma_map(struct vdpa_device *vdpa, unsigned int asid, 66662306a36Sopenharmony_ci u64 iova, u64 size, 66762306a36Sopenharmony_ci u64 pa, u32 perm, void *opaque) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 67062306a36Sopenharmony_ci int ret; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (asid >= vdpasim->dev_attr.nas) 67362306a36Sopenharmony_ci return -EINVAL; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 67662306a36Sopenharmony_ci if (vdpasim->iommu_pt[asid]) { 67762306a36Sopenharmony_ci vhost_iotlb_reset(&vdpasim->iommu[asid]); 67862306a36Sopenharmony_ci vdpasim->iommu_pt[asid] = false; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci ret = vhost_iotlb_add_range_ctx(&vdpasim->iommu[asid], iova, 68162306a36Sopenharmony_ci iova + size - 1, pa, perm, opaque); 68262306a36Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int vdpasim_dma_unmap(struct vdpa_device *vdpa, unsigned int asid, 68862306a36Sopenharmony_ci u64 iova, u64 size) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (asid >= vdpasim->dev_attr.nas) 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (vdpasim->iommu_pt[asid]) { 69662306a36Sopenharmony_ci vhost_iotlb_reset(&vdpasim->iommu[asid]); 69762306a36Sopenharmony_ci vdpasim->iommu_pt[asid] = false; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci spin_lock(&vdpasim->iommu_lock); 70162306a36Sopenharmony_ci vhost_iotlb_del_range(&vdpasim->iommu[asid], iova, iova + size - 1); 70262306a36Sopenharmony_ci spin_unlock(&vdpasim->iommu_lock); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic void vdpasim_free(struct vdpa_device *vdpa) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct vdpasim *vdpasim = vdpa_to_sim(vdpa); 71062306a36Sopenharmony_ci int i; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci kthread_cancel_work_sync(&vdpasim->work); 71362306a36Sopenharmony_ci kthread_destroy_worker(vdpasim->worker); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { 71662306a36Sopenharmony_ci vringh_kiov_cleanup(&vdpasim->vqs[i].out_iov); 71762306a36Sopenharmony_ci vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci vdpasim->dev_attr.free(vdpasim); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci for (i = 0; i < vdpasim->dev_attr.nas; i++) 72362306a36Sopenharmony_ci vhost_iotlb_reset(&vdpasim->iommu[i]); 72462306a36Sopenharmony_ci kfree(vdpasim->iommu); 72562306a36Sopenharmony_ci kfree(vdpasim->iommu_pt); 72662306a36Sopenharmony_ci kfree(vdpasim->vqs); 72762306a36Sopenharmony_ci kfree(vdpasim->config); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_config_ops = { 73162306a36Sopenharmony_ci .set_vq_address = vdpasim_set_vq_address, 73262306a36Sopenharmony_ci .set_vq_num = vdpasim_set_vq_num, 73362306a36Sopenharmony_ci .kick_vq = vdpasim_kick_vq, 73462306a36Sopenharmony_ci .set_vq_cb = vdpasim_set_vq_cb, 73562306a36Sopenharmony_ci .set_vq_ready = vdpasim_set_vq_ready, 73662306a36Sopenharmony_ci .get_vq_ready = vdpasim_get_vq_ready, 73762306a36Sopenharmony_ci .set_vq_state = vdpasim_set_vq_state, 73862306a36Sopenharmony_ci .get_vendor_vq_stats = vdpasim_get_vq_stats, 73962306a36Sopenharmony_ci .get_vq_state = vdpasim_get_vq_state, 74062306a36Sopenharmony_ci .get_vq_align = vdpasim_get_vq_align, 74162306a36Sopenharmony_ci .get_vq_group = vdpasim_get_vq_group, 74262306a36Sopenharmony_ci .get_device_features = vdpasim_get_device_features, 74362306a36Sopenharmony_ci .get_backend_features = vdpasim_get_backend_features, 74462306a36Sopenharmony_ci .set_driver_features = vdpasim_set_driver_features, 74562306a36Sopenharmony_ci .get_driver_features = vdpasim_get_driver_features, 74662306a36Sopenharmony_ci .set_config_cb = vdpasim_set_config_cb, 74762306a36Sopenharmony_ci .get_vq_num_max = vdpasim_get_vq_num_max, 74862306a36Sopenharmony_ci .get_device_id = vdpasim_get_device_id, 74962306a36Sopenharmony_ci .get_vendor_id = vdpasim_get_vendor_id, 75062306a36Sopenharmony_ci .get_status = vdpasim_get_status, 75162306a36Sopenharmony_ci .set_status = vdpasim_set_status, 75262306a36Sopenharmony_ci .reset = vdpasim_reset, 75362306a36Sopenharmony_ci .suspend = vdpasim_suspend, 75462306a36Sopenharmony_ci .resume = vdpasim_resume, 75562306a36Sopenharmony_ci .get_config_size = vdpasim_get_config_size, 75662306a36Sopenharmony_ci .get_config = vdpasim_get_config, 75762306a36Sopenharmony_ci .set_config = vdpasim_set_config, 75862306a36Sopenharmony_ci .get_generation = vdpasim_get_generation, 75962306a36Sopenharmony_ci .get_iova_range = vdpasim_get_iova_range, 76062306a36Sopenharmony_ci .set_group_asid = vdpasim_set_group_asid, 76162306a36Sopenharmony_ci .dma_map = vdpasim_dma_map, 76262306a36Sopenharmony_ci .dma_unmap = vdpasim_dma_unmap, 76362306a36Sopenharmony_ci .bind_mm = vdpasim_bind_mm, 76462306a36Sopenharmony_ci .unbind_mm = vdpasim_unbind_mm, 76562306a36Sopenharmony_ci .free = vdpasim_free, 76662306a36Sopenharmony_ci}; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic const struct vdpa_config_ops vdpasim_batch_config_ops = { 76962306a36Sopenharmony_ci .set_vq_address = vdpasim_set_vq_address, 77062306a36Sopenharmony_ci .set_vq_num = vdpasim_set_vq_num, 77162306a36Sopenharmony_ci .kick_vq = vdpasim_kick_vq, 77262306a36Sopenharmony_ci .set_vq_cb = vdpasim_set_vq_cb, 77362306a36Sopenharmony_ci .set_vq_ready = vdpasim_set_vq_ready, 77462306a36Sopenharmony_ci .get_vq_ready = vdpasim_get_vq_ready, 77562306a36Sopenharmony_ci .set_vq_state = vdpasim_set_vq_state, 77662306a36Sopenharmony_ci .get_vendor_vq_stats = vdpasim_get_vq_stats, 77762306a36Sopenharmony_ci .get_vq_state = vdpasim_get_vq_state, 77862306a36Sopenharmony_ci .get_vq_align = vdpasim_get_vq_align, 77962306a36Sopenharmony_ci .get_vq_group = vdpasim_get_vq_group, 78062306a36Sopenharmony_ci .get_device_features = vdpasim_get_device_features, 78162306a36Sopenharmony_ci .get_backend_features = vdpasim_get_backend_features, 78262306a36Sopenharmony_ci .set_driver_features = vdpasim_set_driver_features, 78362306a36Sopenharmony_ci .get_driver_features = vdpasim_get_driver_features, 78462306a36Sopenharmony_ci .set_config_cb = vdpasim_set_config_cb, 78562306a36Sopenharmony_ci .get_vq_num_max = vdpasim_get_vq_num_max, 78662306a36Sopenharmony_ci .get_device_id = vdpasim_get_device_id, 78762306a36Sopenharmony_ci .get_vendor_id = vdpasim_get_vendor_id, 78862306a36Sopenharmony_ci .get_status = vdpasim_get_status, 78962306a36Sopenharmony_ci .set_status = vdpasim_set_status, 79062306a36Sopenharmony_ci .reset = vdpasim_reset, 79162306a36Sopenharmony_ci .suspend = vdpasim_suspend, 79262306a36Sopenharmony_ci .resume = vdpasim_resume, 79362306a36Sopenharmony_ci .get_config_size = vdpasim_get_config_size, 79462306a36Sopenharmony_ci .get_config = vdpasim_get_config, 79562306a36Sopenharmony_ci .set_config = vdpasim_set_config, 79662306a36Sopenharmony_ci .get_generation = vdpasim_get_generation, 79762306a36Sopenharmony_ci .get_iova_range = vdpasim_get_iova_range, 79862306a36Sopenharmony_ci .set_group_asid = vdpasim_set_group_asid, 79962306a36Sopenharmony_ci .set_map = vdpasim_set_map, 80062306a36Sopenharmony_ci .bind_mm = vdpasim_bind_mm, 80162306a36Sopenharmony_ci .unbind_mm = vdpasim_unbind_mm, 80262306a36Sopenharmony_ci .free = vdpasim_free, 80362306a36Sopenharmony_ci}; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 80662306a36Sopenharmony_ciMODULE_LICENSE(DRV_LICENSE); 80762306a36Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 80862306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 809