Skip to content

Commit 0c853c2

Browse files
mgurtovoymstsirkin
authored andcommitted
vdpa: add vdpa simulator for block device
This will allow running vDPA for virtio block protocol. It's a preliminary implementation with a simple request handling: for each request, only the status (last byte) is set. It's always set to VIRTIO_BLK_S_OK. Also input validation is missing and will be added in the next commits. Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com> [sgarzare: various cleanups/fixes] Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Link: https://lore.kernel.org/r/20210315163450.254396-12-sgarzare@redhat.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 9d6d97b commit 0c853c2

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

drivers/vdpa/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ config VDPA_SIM_NET
2626
help
2727
vDPA networking device simulator which loops TX traffic back to RX.
2828

29+
config VDPA_SIM_BLOCK
30+
tristate "vDPA simulator for block device"
31+
depends on VDPA_SIM
32+
help
33+
vDPA block device simulator which terminates IO request in a
34+
memory buffer.
35+
2936
config IFCVF
3037
tristate "Intel IFC VF vDPA driver"
3138
depends on PCI_MSI

drivers/vdpa/vdpa_sim/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_VDPA_SIM) += vdpa_sim.o
33
obj-$(CONFIG_VDPA_SIM_NET) += vdpa_sim_net.o
4+
obj-$(CONFIG_VDPA_SIM_BLOCK) += vdpa_sim_blk.o
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* VDPA simulator for block device.
4+
*
5+
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
6+
*
7+
*/
8+
9+
#include <linux/init.h>
10+
#include <linux/module.h>
11+
#include <linux/device.h>
12+
#include <linux/kernel.h>
13+
#include <linux/sched.h>
14+
#include <linux/blkdev.h>
15+
#include <linux/vringh.h>
16+
#include <linux/vdpa.h>
17+
#include <uapi/linux/virtio_blk.h>
18+
19+
#include "vdpa_sim.h"
20+
21+
#define DRV_VERSION "0.1"
22+
#define DRV_AUTHOR "Max Gurtovoy <mgurtovoy@nvidia.com>"
23+
#define DRV_DESC "vDPA Device Simulator for block device"
24+
#define DRV_LICENSE "GPL v2"
25+
26+
#define VDPASIM_BLK_FEATURES (VDPASIM_FEATURES | \
27+
(1ULL << VIRTIO_BLK_F_SIZE_MAX) | \
28+
(1ULL << VIRTIO_BLK_F_SEG_MAX) | \
29+
(1ULL << VIRTIO_BLK_F_BLK_SIZE) | \
30+
(1ULL << VIRTIO_BLK_F_TOPOLOGY) | \
31+
(1ULL << VIRTIO_BLK_F_MQ))
32+
33+
#define VDPASIM_BLK_CAPACITY 0x40000
34+
#define VDPASIM_BLK_SIZE_MAX 0x1000
35+
#define VDPASIM_BLK_SEG_MAX 32
36+
#define VDPASIM_BLK_VQ_NUM 1
37+
38+
static struct vdpasim *vdpasim_blk_dev;
39+
40+
static void vdpasim_blk_work(struct work_struct *work)
41+
{
42+
struct vdpasim *vdpasim = container_of(work, struct vdpasim, work);
43+
u8 status = VIRTIO_BLK_S_OK;
44+
int i;
45+
46+
spin_lock(&vdpasim->lock);
47+
48+
if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK))
49+
goto out;
50+
51+
for (i = 0; i < VDPASIM_BLK_VQ_NUM; i++) {
52+
struct vdpasim_virtqueue *vq = &vdpasim->vqs[i];
53+
54+
if (!vq->ready)
55+
continue;
56+
57+
while (vringh_getdesc_iotlb(&vq->vring, &vq->out_iov,
58+
&vq->in_iov, &vq->head,
59+
GFP_ATOMIC) > 0) {
60+
int write;
61+
62+
vq->in_iov.i = vq->in_iov.used - 1;
63+
write = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov,
64+
&status, 1);
65+
if (write <= 0)
66+
break;
67+
68+
/* Make sure data is wrote before advancing index */
69+
smp_wmb();
70+
71+
vringh_complete_iotlb(&vq->vring, vq->head, write);
72+
73+
/* Make sure used is visible before rasing the interrupt. */
74+
smp_wmb();
75+
76+
local_bh_disable();
77+
if (vringh_need_notify_iotlb(&vq->vring) > 0)
78+
vringh_notify(&vq->vring);
79+
local_bh_enable();
80+
}
81+
}
82+
out:
83+
spin_unlock(&vdpasim->lock);
84+
}
85+
86+
static void vdpasim_blk_get_config(struct vdpasim *vdpasim, void *config)
87+
{
88+
struct virtio_blk_config *blk_config = config;
89+
90+
memset(config, 0, sizeof(struct virtio_blk_config));
91+
92+
blk_config->capacity = cpu_to_vdpasim64(vdpasim, VDPASIM_BLK_CAPACITY);
93+
blk_config->size_max = cpu_to_vdpasim32(vdpasim, VDPASIM_BLK_SIZE_MAX);
94+
blk_config->seg_max = cpu_to_vdpasim32(vdpasim, VDPASIM_BLK_SEG_MAX);
95+
blk_config->num_queues = cpu_to_vdpasim16(vdpasim, VDPASIM_BLK_VQ_NUM);
96+
blk_config->min_io_size = cpu_to_vdpasim16(vdpasim, 1);
97+
blk_config->opt_io_size = cpu_to_vdpasim32(vdpasim, 1);
98+
blk_config->blk_size = cpu_to_vdpasim32(vdpasim, SECTOR_SIZE);
99+
}
100+
101+
static int __init vdpasim_blk_init(void)
102+
{
103+
struct vdpasim_dev_attr dev_attr = {};
104+
int ret;
105+
106+
dev_attr.id = VIRTIO_ID_BLOCK;
107+
dev_attr.supported_features = VDPASIM_BLK_FEATURES;
108+
dev_attr.nvqs = VDPASIM_BLK_VQ_NUM;
109+
dev_attr.config_size = sizeof(struct virtio_blk_config);
110+
dev_attr.get_config = vdpasim_blk_get_config;
111+
dev_attr.work_fn = vdpasim_blk_work;
112+
dev_attr.buffer_size = PAGE_SIZE;
113+
114+
vdpasim_blk_dev = vdpasim_create(&dev_attr);
115+
if (IS_ERR(vdpasim_blk_dev)) {
116+
ret = PTR_ERR(vdpasim_blk_dev);
117+
goto out;
118+
}
119+
120+
ret = vdpa_register_device(&vdpasim_blk_dev->vdpa, VDPASIM_BLK_VQ_NUM);
121+
if (ret)
122+
goto put_dev;
123+
124+
return 0;
125+
126+
put_dev:
127+
put_device(&vdpasim_blk_dev->vdpa.dev);
128+
out:
129+
return ret;
130+
}
131+
132+
static void __exit vdpasim_blk_exit(void)
133+
{
134+
struct vdpa_device *vdpa = &vdpasim_blk_dev->vdpa;
135+
136+
vdpa_unregister_device(vdpa);
137+
}
138+
139+
module_init(vdpasim_blk_init)
140+
module_exit(vdpasim_blk_exit)
141+
142+
MODULE_VERSION(DRV_VERSION);
143+
MODULE_LICENSE(DRV_LICENSE);
144+
MODULE_AUTHOR(DRV_AUTHOR);
145+
MODULE_DESCRIPTION(DRV_DESC);

0 commit comments

Comments
 (0)