]>
Commit | Line | Data |
---|---|---|
961e9c84 JW |
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 | |
ac8b85f9 | 119 | * Callers must have a succeed call of vdpa_alloc_device() before. |
961e9c84 JW |
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"); |