xref: /kernel/linux/linux-5.10/drivers/vdpa/vdpa.c (revision 8c2ecf20)
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 <jasowang@redhat.com>
7 *
8 */
9
10#include <linux/module.h>
11#include <linux/idr.h>
12#include <linux/slab.h>
13#include <linux/vdpa.h>
14
15static DEFINE_IDA(vdpa_index_ida);
16
17static 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
29static 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
40static struct bus_type vdpa_bus = {
41	.name  = "vdpa",
42	.probe = vdpa_dev_probe,
43	.remove = vdpa_dev_remove,
44};
45
46static 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 * @nvqs: number of virtqueues supported by this device
65 * @size: size of the parent structure that contains private data
66 *
67 * Driver should use vdpa_alloc_device() wrapper macro instead of
68 * using this directly.
69 *
70 * Returns an error when parent/config/dma_dev is not set or fail to get
71 * ida.
72 */
73struct vdpa_device *__vdpa_alloc_device(struct device *parent,
74					const struct vdpa_config_ops *config,
75					int nvqs,
76					size_t size)
77{
78	struct vdpa_device *vdev;
79	int err = -EINVAL;
80
81	if (!config)
82		goto err;
83
84	if (!!config->dma_map != !!config->dma_unmap)
85		goto err;
86
87	err = -ENOMEM;
88	vdev = kzalloc(size, GFP_KERNEL);
89	if (!vdev)
90		goto err;
91
92	err = ida_simple_get(&vdpa_index_ida, 0, 0, GFP_KERNEL);
93	if (err < 0)
94		goto err_ida;
95
96	vdev->dev.bus = &vdpa_bus;
97	vdev->dev.parent = parent;
98	vdev->dev.release = vdpa_release_dev;
99	vdev->index = err;
100	vdev->config = config;
101	vdev->features_valid = false;
102	vdev->nvqs = nvqs;
103
104	err = dev_set_name(&vdev->dev, "vdpa%u", vdev->index);
105	if (err)
106		goto err_name;
107
108	device_initialize(&vdev->dev);
109
110	return vdev;
111
112err_name:
113	ida_simple_remove(&vdpa_index_ida, vdev->index);
114err_ida:
115	kfree(vdev);
116err:
117	return ERR_PTR(err);
118}
119EXPORT_SYMBOL_GPL(__vdpa_alloc_device);
120
121/**
122 * vdpa_register_device - register a vDPA device
123 * Callers must have a succeed call of vdpa_alloc_device() before.
124 * @vdev: the vdpa device to be registered to vDPA bus
125 *
126 * Returns an error when fail to add to vDPA bus
127 */
128int vdpa_register_device(struct vdpa_device *vdev)
129{
130	return device_add(&vdev->dev);
131}
132EXPORT_SYMBOL_GPL(vdpa_register_device);
133
134/**
135 * vdpa_unregister_device - unregister a vDPA device
136 * @vdev: the vdpa device to be unregisted from vDPA bus
137 */
138void vdpa_unregister_device(struct vdpa_device *vdev)
139{
140	device_unregister(&vdev->dev);
141}
142EXPORT_SYMBOL_GPL(vdpa_unregister_device);
143
144/**
145 * __vdpa_register_driver - register a vDPA device driver
146 * @drv: the vdpa device driver to be registered
147 * @owner: module owner of the driver
148 *
149 * Returns an err when fail to do the registration
150 */
151int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner)
152{
153	drv->driver.bus = &vdpa_bus;
154	drv->driver.owner = owner;
155
156	return driver_register(&drv->driver);
157}
158EXPORT_SYMBOL_GPL(__vdpa_register_driver);
159
160/**
161 * vdpa_unregister_driver - unregister a vDPA device driver
162 * @drv: the vdpa device driver to be unregistered
163 */
164void vdpa_unregister_driver(struct vdpa_driver *drv)
165{
166	driver_unregister(&drv->driver);
167}
168EXPORT_SYMBOL_GPL(vdpa_unregister_driver);
169
170static int vdpa_init(void)
171{
172	return bus_register(&vdpa_bus);
173}
174
175static void __exit vdpa_exit(void)
176{
177	bus_unregister(&vdpa_bus);
178	ida_destroy(&vdpa_index_ida);
179}
180core_initcall(vdpa_init);
181module_exit(vdpa_exit);
182
183MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");
184MODULE_LICENSE("GPL v2");
185