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