Skip to content

Commit 961e9c8

Browse files
jasowangmstsirkin
authored andcommitted
vDPA: introduce vDPA bus
vDPA device is a device that uses a datapath which complies with the virtio specifications with vendor specific control path. vDPA devices can be both physically located on the hardware or emulated by software. vDPA hardware devices are usually implemented through PCIE with the following types: - PF (Physical Function) - A single Physical Function - VF (Virtual Function) - Device that supports single root I/O virtualization (SR-IOV). Its Virtual Function (VF) represents a virtualized instance of the device that can be assigned to different partitions - ADI (Assignable Device Interface) and its equivalents - With technologies such as Intel Scalable IOV, a virtual device (VDEV) composed by host OS utilizing one or more ADIs. Or its equivalent like SF (Sub function) from Mellanox. >From a driver's perspective, depends on how and where the DMA translation is done, vDPA devices are split into two types: - Platform specific DMA translation - From the driver's perspective, the device can be used on a platform where device access to data in memory is limited and/or translated. An example is a PCIE vDPA whose DMA request was tagged via a bus (e.g PCIE) specific way. DMA translation and protection are done at PCIE bus IOMMU level. - Device specific DMA translation - The device implements DMA isolation and protection through its own logic. An example is a vDPA device which uses on-chip IOMMU. To hide the differences and complexity of the above types for a vDPA device/IOMMU options and in order to present a generic virtio device to the upper layer, a device agnostic framework is required. This patch introduces a software vDPA bus which abstracts the common attributes of vDPA device, vDPA bus driver and the communication method (vdpa_config_ops) between the vDPA device abstraction and the vDPA bus driver. This allows multiple types of drivers to be used for vDPA device like the virtio_vdpa and vhost_vdpa driver to operate on the bus and allow vDPA device could be used by either kernel virtio driver or userspace vhost drivers as: virtio drivers vhost drivers | | [virtio bus] [vhost uAPI] | | virtio device vhost device virtio_vdpa drv vhost_vdpa drv \ / [vDPA bus] | vDPA device hardware drv | [hardware bus] | vDPA hardware With the abstraction of vDPA bus and vDPA bus operations, the difference and complexity of the under layer hardware is hidden from upper layer. The vDPA bus drivers on top can use a unified vdpa_config_ops to control different types of vDPA device. Signed-off-by: Jason Wang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 9ad9c49 commit 961e9c8

File tree

7 files changed

+446
-0
lines changed

7 files changed

+446
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17699,6 +17699,7 @@ F: tools/virtio/
1769917699
F: drivers/net/virtio_net.c
1770017700
F: drivers/block/virtio_blk.c
1770117701
F: include/linux/virtio*.h
17702+
F: include/linux/vdpa.h
1770217703
F: include/uapi/linux/virtio_*.h
1770317704
F: drivers/crypto/virtio/
1770417705
F: mm/balloon_compaction.c

drivers/virtio/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,5 @@ config VIRTIO_MMIO_CMDLINE_DEVICES
9696
If unsure, say 'N'.
9797

9898
endif # VIRTIO_MENU
99+
100+
source "drivers/virtio/vdpa/Kconfig"

drivers/virtio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
66
virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
77
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
88
obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
9+
obj-$(CONFIG_VDPA) += vdpa/

drivers/virtio/vdpa/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
config VDPA
3+
tristate
4+
help
5+
Enable this module to support vDPA device that uses a
6+
datapath which complies with virtio specifications with
7+
vendor specific control path.

drivers/virtio/vdpa/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
obj-$(CONFIG_VDPA) += vdpa.o

drivers/virtio/vdpa/vdpa.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* vDPA bus.
4+
*
5+
* Copyright (c) 2020, Red Hat. All rights reserved.
6+
* Author: Jason Wang <[email protected]>
7+
*
8+
*/
9+
10+
#include <linux/module.h>
11+
#include <linux/idr.h>
12+
#include <linux/slab.h>
13+
#include <linux/vdpa.h>
14+
15+
static DEFINE_IDA(vdpa_index_ida);
16+
17+
static int vdpa_dev_probe(struct device *d)
18+
{
19+
struct vdpa_device *vdev = dev_to_vdpa(d);
20+
struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
21+
int ret = 0;
22+
23+
if (drv && drv->probe)
24+
ret = drv->probe(vdev);
25+
26+
return ret;
27+
}
28+
29+
static int vdpa_dev_remove(struct device *d)
30+
{
31+
struct vdpa_device *vdev = dev_to_vdpa(d);
32+
struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
33+
34+
if (drv && drv->remove)
35+
drv->remove(vdev);
36+
37+
return 0;
38+
}
39+
40+
static struct bus_type vdpa_bus = {
41+
.name = "vdpa",
42+
.probe = vdpa_dev_probe,
43+
.remove = vdpa_dev_remove,
44+
};
45+
46+
static void vdpa_release_dev(struct device *d)
47+
{
48+
struct vdpa_device *vdev = dev_to_vdpa(d);
49+
const struct vdpa_config_ops *ops = vdev->config;
50+
51+
if (ops->free)
52+
ops->free(vdev);
53+
54+
ida_simple_remove(&vdpa_index_ida, vdev->index);
55+
kfree(vdev);
56+
}
57+
58+
/**
59+
* __vdpa_alloc_device - allocate and initilaize a vDPA device
60+
* This allows driver to some prepartion after device is
61+
* initialized but before registered.
62+
* @parent: the parent device
63+
* @config: the bus operations that is supported by this device
64+
* @size: size of the parent structure that contains private data
65+
*
66+
* Drvier should use vdap_alloc_device() wrapper macro instead of
67+
* using this directly.
68+
*
69+
* Returns an error when parent/config/dma_dev is not set or fail to get
70+
* ida.
71+
*/
72+
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
73+
const struct vdpa_config_ops *config,
74+
size_t size)
75+
{
76+
struct vdpa_device *vdev;
77+
int err = -EINVAL;
78+
79+
if (!config)
80+
goto err;
81+
82+
if (!!config->dma_map != !!config->dma_unmap)
83+
goto err;
84+
85+
err = -ENOMEM;
86+
vdev = kzalloc(size, GFP_KERNEL);
87+
if (!vdev)
88+
goto err;
89+
90+
err = ida_simple_get(&vdpa_index_ida, 0, 0, GFP_KERNEL);
91+
if (err < 0)
92+
goto err_ida;
93+
94+
vdev->dev.bus = &vdpa_bus;
95+
vdev->dev.parent = parent;
96+
vdev->dev.release = vdpa_release_dev;
97+
vdev->index = err;
98+
vdev->config = config;
99+
100+
err = dev_set_name(&vdev->dev, "vdpa%u", vdev->index);
101+
if (err)
102+
goto err_name;
103+
104+
device_initialize(&vdev->dev);
105+
106+
return vdev;
107+
108+
err_name:
109+
ida_simple_remove(&vdpa_index_ida, vdev->index);
110+
err_ida:
111+
kfree(vdev);
112+
err:
113+
return ERR_PTR(err);
114+
}
115+
EXPORT_SYMBOL_GPL(__vdpa_alloc_device);
116+
117+
/**
118+
* vdpa_register_device - register a vDPA device
119+
* Callers must have a succeed call of vdpa_init_device() before.
120+
* @vdev: the vdpa device to be registered to vDPA bus
121+
*
122+
* Returns an error when fail to add to vDPA bus
123+
*/
124+
int vdpa_register_device(struct vdpa_device *vdev)
125+
{
126+
return device_add(&vdev->dev);
127+
}
128+
EXPORT_SYMBOL_GPL(vdpa_register_device);
129+
130+
/**
131+
* vdpa_unregister_device - unregister a vDPA device
132+
* @vdev: the vdpa device to be unregisted from vDPA bus
133+
*/
134+
void vdpa_unregister_device(struct vdpa_device *vdev)
135+
{
136+
device_unregister(&vdev->dev);
137+
}
138+
EXPORT_SYMBOL_GPL(vdpa_unregister_device);
139+
140+
/**
141+
* __vdpa_register_driver - register a vDPA device driver
142+
* @drv: the vdpa device driver to be registered
143+
* @owner: module owner of the driver
144+
*
145+
* Returns an err when fail to do the registration
146+
*/
147+
int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner)
148+
{
149+
drv->driver.bus = &vdpa_bus;
150+
drv->driver.owner = owner;
151+
152+
return driver_register(&drv->driver);
153+
}
154+
EXPORT_SYMBOL_GPL(__vdpa_register_driver);
155+
156+
/**
157+
* vdpa_unregister_driver - unregister a vDPA device driver
158+
* @drv: the vdpa device driver to be unregistered
159+
*/
160+
void vdpa_unregister_driver(struct vdpa_driver *drv)
161+
{
162+
driver_unregister(&drv->driver);
163+
}
164+
EXPORT_SYMBOL_GPL(vdpa_unregister_driver);
165+
166+
static int vdpa_init(void)
167+
{
168+
return bus_register(&vdpa_bus);
169+
}
170+
171+
static void __exit vdpa_exit(void)
172+
{
173+
bus_unregister(&vdpa_bus);
174+
ida_destroy(&vdpa_index_ida);
175+
}
176+
core_initcall(vdpa_init);
177+
module_exit(vdpa_exit);
178+
179+
MODULE_AUTHOR("Jason Wang <[email protected]>");
180+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)