xref: /dpdk/drivers/bus/vdev/vdev.c (revision fd8c20aab4c2fe2c568455be4efab76db126791f)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 RehiveTech. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of RehiveTech nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <string.h>
34 #include <inttypes.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <sys/queue.h>
40 
41 #include <rte_eal.h>
42 #include <rte_dev.h>
43 #include <rte_bus.h>
44 #include <rte_common.h>
45 #include <rte_devargs.h>
46 #include <rte_memory.h>
47 #include <rte_tailq.h>
48 #include <rte_spinlock.h>
49 #include <rte_errno.h>
50 
51 #include "rte_bus_vdev.h"
52 #include "vdev_logs.h"
53 
54 int vdev_logtype_bus;
55 
56 /* Forward declare to access virtual bus name */
57 static struct rte_bus rte_vdev_bus;
58 
59 /** Double linked list of virtual device drivers. */
60 TAILQ_HEAD(vdev_device_list, rte_vdev_device);
61 
62 static struct vdev_device_list vdev_device_list =
63 	TAILQ_HEAD_INITIALIZER(vdev_device_list);
64 struct vdev_driver_list vdev_driver_list =
65 	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
66 
67 struct vdev_custom_scan {
68 	TAILQ_ENTRY(vdev_custom_scan) next;
69 	rte_vdev_scan_callback callback;
70 	void *user_arg;
71 };
72 TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
73 static struct vdev_custom_scans vdev_custom_scans =
74 	TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
75 static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
76 
77 /* register a driver */
78 void
79 rte_vdev_register(struct rte_vdev_driver *driver)
80 {
81 	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
82 }
83 
84 /* unregister a driver */
85 void
86 rte_vdev_unregister(struct rte_vdev_driver *driver)
87 {
88 	TAILQ_REMOVE(&vdev_driver_list, driver, next);
89 }
90 
91 int
92 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
93 {
94 	struct vdev_custom_scan *custom_scan;
95 
96 	rte_spinlock_lock(&vdev_custom_scan_lock);
97 
98 	/* check if already registered */
99 	TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
100 		if (custom_scan->callback == callback &&
101 				custom_scan->user_arg == user_arg)
102 			break;
103 	}
104 
105 	if (custom_scan == NULL) {
106 		custom_scan = malloc(sizeof(struct vdev_custom_scan));
107 		if (custom_scan != NULL) {
108 			custom_scan->callback = callback;
109 			custom_scan->user_arg = user_arg;
110 			TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
111 		}
112 	}
113 
114 	rte_spinlock_unlock(&vdev_custom_scan_lock);
115 
116 	return (custom_scan == NULL) ? -1 : 0;
117 }
118 
119 int
120 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
121 {
122 	struct vdev_custom_scan *custom_scan, *tmp_scan;
123 
124 	rte_spinlock_lock(&vdev_custom_scan_lock);
125 	TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next, tmp_scan) {
126 		if (custom_scan->callback != callback ||
127 				(custom_scan->user_arg != (void *)-1 &&
128 				custom_scan->user_arg != user_arg))
129 			continue;
130 		TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
131 		free(custom_scan);
132 	}
133 	rte_spinlock_unlock(&vdev_custom_scan_lock);
134 
135 	return 0;
136 }
137 
138 static int
139 vdev_parse(const char *name, void *addr)
140 {
141 	struct rte_vdev_driver **out = addr;
142 	struct rte_vdev_driver *driver = NULL;
143 
144 	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
145 		if (strncmp(driver->driver.name, name,
146 			    strlen(driver->driver.name)) == 0)
147 			break;
148 		if (driver->driver.alias &&
149 		    strncmp(driver->driver.alias, name,
150 			    strlen(driver->driver.alias)) == 0)
151 			break;
152 	}
153 	if (driver != NULL &&
154 	    addr != NULL)
155 		*out = driver;
156 	return driver == NULL;
157 }
158 
159 static int
160 vdev_probe_all_drivers(struct rte_vdev_device *dev)
161 {
162 	const char *name;
163 	struct rte_vdev_driver *driver;
164 	int ret;
165 
166 	name = rte_vdev_device_name(dev);
167 
168 	VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name,
169 		rte_vdev_device_name(dev));
170 
171 	if (vdev_parse(name, &driver))
172 		return -1;
173 	dev->device.driver = &driver->driver;
174 	ret = driver->probe(dev);
175 	if (ret)
176 		dev->device.driver = NULL;
177 	return ret;
178 }
179 
180 static struct rte_vdev_device *
181 find_vdev(const char *name)
182 {
183 	struct rte_vdev_device *dev;
184 
185 	if (!name)
186 		return NULL;
187 
188 	TAILQ_FOREACH(dev, &vdev_device_list, next) {
189 		const char *devname = rte_vdev_device_name(dev);
190 
191 		if (!strncmp(devname, name, strlen(name)))
192 			return dev;
193 	}
194 
195 	return NULL;
196 }
197 
198 static struct rte_devargs *
199 alloc_devargs(const char *name, const char *args)
200 {
201 	struct rte_devargs *devargs;
202 	int ret;
203 
204 	devargs = calloc(1, sizeof(*devargs));
205 	if (!devargs)
206 		return NULL;
207 
208 	devargs->bus = &rte_vdev_bus;
209 	if (args)
210 		devargs->args = strdup(args);
211 	else
212 		devargs->args = strdup("");
213 
214 	ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
215 	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
216 		free(devargs->args);
217 		free(devargs);
218 		return NULL;
219 	}
220 
221 	return devargs;
222 }
223 
224 int
225 rte_vdev_init(const char *name, const char *args)
226 {
227 	struct rte_vdev_device *dev;
228 	struct rte_devargs *devargs;
229 	int ret;
230 
231 	if (name == NULL)
232 		return -EINVAL;
233 
234 	dev = find_vdev(name);
235 	if (dev)
236 		return -EEXIST;
237 
238 	devargs = alloc_devargs(name, args);
239 	if (!devargs)
240 		return -ENOMEM;
241 
242 	dev = calloc(1, sizeof(*dev));
243 	if (!dev) {
244 		ret = -ENOMEM;
245 		goto fail;
246 	}
247 
248 	dev->device.devargs = devargs;
249 	dev->device.numa_node = SOCKET_ID_ANY;
250 	dev->device.name = devargs->name;
251 
252 	ret = vdev_probe_all_drivers(dev);
253 	if (ret) {
254 		if (ret > 0)
255 			VDEV_LOG(ERR, "no driver found for %s\n", name);
256 		goto fail;
257 	}
258 
259 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
260 
261 	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
262 	return 0;
263 
264 fail:
265 	free(devargs->args);
266 	free(devargs);
267 	free(dev);
268 	return ret;
269 }
270 
271 static int
272 vdev_remove_driver(struct rte_vdev_device *dev)
273 {
274 	const char *name = rte_vdev_device_name(dev);
275 	const struct rte_vdev_driver *driver;
276 
277 	if (!dev->device.driver) {
278 		VDEV_LOG(DEBUG, "no driver attach to device %s\n", name);
279 		return 1;
280 	}
281 
282 	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
283 		driver);
284 	return driver->remove(dev);
285 }
286 
287 int
288 rte_vdev_uninit(const char *name)
289 {
290 	struct rte_vdev_device *dev;
291 	struct rte_devargs *devargs;
292 	int ret;
293 
294 	if (name == NULL)
295 		return -EINVAL;
296 
297 	dev = find_vdev(name);
298 	if (!dev)
299 		return -ENOENT;
300 
301 	devargs = dev->device.devargs;
302 
303 	ret = vdev_remove_driver(dev);
304 	if (ret)
305 		return ret;
306 
307 	TAILQ_REMOVE(&vdev_device_list, dev, next);
308 
309 	TAILQ_REMOVE(&devargs_list, devargs, next);
310 
311 	free(devargs->args);
312 	free(devargs);
313 	free(dev);
314 	return 0;
315 }
316 
317 static int
318 vdev_scan(void)
319 {
320 	struct rte_vdev_device *dev;
321 	struct rte_devargs *devargs;
322 	struct vdev_custom_scan *custom_scan;
323 
324 	/* call custom scan callbacks if any */
325 	rte_spinlock_lock(&vdev_custom_scan_lock);
326 	TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
327 		if (custom_scan->callback != NULL)
328 			/*
329 			 * the callback should update devargs list
330 			 * by calling rte_eal_devargs_insert() with
331 			 *     devargs.bus = rte_bus_find_by_name("vdev");
332 			 *     devargs.type = RTE_DEVTYPE_VIRTUAL;
333 			 *     devargs.policy = RTE_DEV_WHITELISTED;
334 			 */
335 			custom_scan->callback(custom_scan->user_arg);
336 	}
337 	rte_spinlock_unlock(&vdev_custom_scan_lock);
338 
339 	/* for virtual devices we scan the devargs_list populated via cmdline */
340 	TAILQ_FOREACH(devargs, &devargs_list, next) {
341 
342 		if (devargs->bus != &rte_vdev_bus)
343 			continue;
344 
345 		dev = find_vdev(devargs->name);
346 		if (dev)
347 			continue;
348 
349 		dev = calloc(1, sizeof(*dev));
350 		if (!dev)
351 			return -1;
352 
353 		dev->device.devargs = devargs;
354 		dev->device.numa_node = SOCKET_ID_ANY;
355 		dev->device.name = devargs->name;
356 
357 		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
358 	}
359 
360 	return 0;
361 }
362 
363 static int
364 vdev_probe(void)
365 {
366 	struct rte_vdev_device *dev;
367 
368 	/* call the init function for each virtual device */
369 	TAILQ_FOREACH(dev, &vdev_device_list, next) {
370 
371 		if (dev->device.driver)
372 			continue;
373 
374 		if (vdev_probe_all_drivers(dev)) {
375 			VDEV_LOG(ERR, "failed to initialize %s device\n",
376 				rte_vdev_device_name(dev));
377 			return -1;
378 		}
379 	}
380 
381 	return 0;
382 }
383 
384 static struct rte_device *
385 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
386 		 const void *data)
387 {
388 	struct rte_vdev_device *dev;
389 
390 	TAILQ_FOREACH(dev, &vdev_device_list, next) {
391 		if (start && &dev->device == start) {
392 			start = NULL;
393 			continue;
394 		}
395 		if (cmp(&dev->device, data) == 0)
396 			return &dev->device;
397 	}
398 	return NULL;
399 }
400 
401 static int
402 vdev_plug(struct rte_device *dev)
403 {
404 	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
405 }
406 
407 static int
408 vdev_unplug(struct rte_device *dev)
409 {
410 	return rte_vdev_uninit(dev->name);
411 }
412 
413 static struct rte_bus rte_vdev_bus = {
414 	.scan = vdev_scan,
415 	.probe = vdev_probe,
416 	.find_device = vdev_find_device,
417 	.plug = vdev_plug,
418 	.unplug = vdev_unplug,
419 	.parse = vdev_parse,
420 };
421 
422 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
423 
424 RTE_INIT(vdev_init_log)
425 {
426 	vdev_logtype_bus = rte_log_register("bus.vdev");
427 	if (vdev_logtype_bus >= 0)
428 		rte_log_set_level(vdev_logtype_bus, RTE_LOG_NOTICE);
429 }
430