xref: /openbmc/linux/drivers/vdpa/vdpa.c (revision 15e3ae36)
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 
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 <jasowang@redhat.com>");
180 MODULE_LICENSE("GPL v2");
181