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