1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 RehiveTech. All rights reserved. 3 */ 4 5 #include <string.h> 6 #include <inttypes.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <stdint.h> 10 #include <stdbool.h> 11 #include <sys/queue.h> 12 13 #include <rte_eal.h> 14 #include <rte_dev.h> 15 #include <rte_bus.h> 16 #include <rte_common.h> 17 #include <rte_devargs.h> 18 #include <rte_memory.h> 19 #include <rte_tailq.h> 20 #include <rte_spinlock.h> 21 #include <rte_errno.h> 22 23 #include "rte_bus_vdev.h" 24 #include "vdev_logs.h" 25 26 int vdev_logtype_bus; 27 28 /* Forward declare to access virtual bus name */ 29 static struct rte_bus rte_vdev_bus; 30 31 /** Double linked list of virtual device drivers. */ 32 TAILQ_HEAD(vdev_device_list, rte_vdev_device); 33 34 static struct vdev_device_list vdev_device_list = 35 TAILQ_HEAD_INITIALIZER(vdev_device_list); 36 struct vdev_driver_list vdev_driver_list = 37 TAILQ_HEAD_INITIALIZER(vdev_driver_list); 38 39 struct vdev_custom_scan { 40 TAILQ_ENTRY(vdev_custom_scan) next; 41 rte_vdev_scan_callback callback; 42 void *user_arg; 43 }; 44 TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan); 45 static struct vdev_custom_scans vdev_custom_scans = 46 TAILQ_HEAD_INITIALIZER(vdev_custom_scans); 47 static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER; 48 49 /* register a driver */ 50 void 51 rte_vdev_register(struct rte_vdev_driver *driver) 52 { 53 TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next); 54 } 55 56 /* unregister a driver */ 57 void 58 rte_vdev_unregister(struct rte_vdev_driver *driver) 59 { 60 TAILQ_REMOVE(&vdev_driver_list, driver, next); 61 } 62 63 int 64 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg) 65 { 66 struct vdev_custom_scan *custom_scan; 67 68 rte_spinlock_lock(&vdev_custom_scan_lock); 69 70 /* check if already registered */ 71 TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) { 72 if (custom_scan->callback == callback && 73 custom_scan->user_arg == user_arg) 74 break; 75 } 76 77 if (custom_scan == NULL) { 78 custom_scan = malloc(sizeof(struct vdev_custom_scan)); 79 if (custom_scan != NULL) { 80 custom_scan->callback = callback; 81 custom_scan->user_arg = user_arg; 82 TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next); 83 } 84 } 85 86 rte_spinlock_unlock(&vdev_custom_scan_lock); 87 88 return (custom_scan == NULL) ? -1 : 0; 89 } 90 91 int 92 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg) 93 { 94 struct vdev_custom_scan *custom_scan, *tmp_scan; 95 96 rte_spinlock_lock(&vdev_custom_scan_lock); 97 TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next, tmp_scan) { 98 if (custom_scan->callback != callback || 99 (custom_scan->user_arg != (void *)-1 && 100 custom_scan->user_arg != user_arg)) 101 continue; 102 TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next); 103 free(custom_scan); 104 } 105 rte_spinlock_unlock(&vdev_custom_scan_lock); 106 107 return 0; 108 } 109 110 static int 111 vdev_parse(const char *name, void *addr) 112 { 113 struct rte_vdev_driver **out = addr; 114 struct rte_vdev_driver *driver = NULL; 115 116 TAILQ_FOREACH(driver, &vdev_driver_list, next) { 117 if (strncmp(driver->driver.name, name, 118 strlen(driver->driver.name)) == 0) 119 break; 120 if (driver->driver.alias && 121 strncmp(driver->driver.alias, name, 122 strlen(driver->driver.alias)) == 0) 123 break; 124 } 125 if (driver != NULL && 126 addr != NULL) 127 *out = driver; 128 return driver == NULL; 129 } 130 131 static int 132 vdev_probe_all_drivers(struct rte_vdev_device *dev) 133 { 134 const char *name; 135 struct rte_vdev_driver *driver; 136 int ret; 137 138 name = rte_vdev_device_name(dev); 139 140 VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name, 141 rte_vdev_device_name(dev)); 142 143 if (vdev_parse(name, &driver)) 144 return -1; 145 dev->device.driver = &driver->driver; 146 ret = driver->probe(dev); 147 if (ret) 148 dev->device.driver = NULL; 149 return ret; 150 } 151 152 static struct rte_vdev_device * 153 find_vdev(const char *name) 154 { 155 struct rte_vdev_device *dev; 156 157 if (!name) 158 return NULL; 159 160 TAILQ_FOREACH(dev, &vdev_device_list, next) { 161 const char *devname = rte_vdev_device_name(dev); 162 163 if (!strcmp(devname, name)) 164 return dev; 165 } 166 167 return NULL; 168 } 169 170 static struct rte_devargs * 171 alloc_devargs(const char *name, const char *args) 172 { 173 struct rte_devargs *devargs; 174 int ret; 175 176 devargs = calloc(1, sizeof(*devargs)); 177 if (!devargs) 178 return NULL; 179 180 devargs->bus = &rte_vdev_bus; 181 if (args) 182 devargs->args = strdup(args); 183 else 184 devargs->args = strdup(""); 185 186 ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name); 187 if (ret < 0 || ret >= (int)sizeof(devargs->name)) { 188 free(devargs->args); 189 free(devargs); 190 return NULL; 191 } 192 193 return devargs; 194 } 195 196 int 197 rte_vdev_init(const char *name, const char *args) 198 { 199 struct rte_vdev_device *dev; 200 struct rte_devargs *devargs; 201 int ret; 202 203 if (name == NULL) 204 return -EINVAL; 205 206 dev = find_vdev(name); 207 if (dev) 208 return -EEXIST; 209 210 devargs = alloc_devargs(name, args); 211 if (!devargs) 212 return -ENOMEM; 213 214 dev = calloc(1, sizeof(*dev)); 215 if (!dev) { 216 ret = -ENOMEM; 217 goto fail; 218 } 219 220 dev->device.devargs = devargs; 221 dev->device.numa_node = SOCKET_ID_ANY; 222 dev->device.name = devargs->name; 223 224 ret = vdev_probe_all_drivers(dev); 225 if (ret) { 226 if (ret > 0) 227 VDEV_LOG(ERR, "no driver found for %s\n", name); 228 goto fail; 229 } 230 231 TAILQ_INSERT_TAIL(&devargs_list, devargs, next); 232 233 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next); 234 return 0; 235 236 fail: 237 free(devargs->args); 238 free(devargs); 239 free(dev); 240 return ret; 241 } 242 243 static int 244 vdev_remove_driver(struct rte_vdev_device *dev) 245 { 246 const char *name = rte_vdev_device_name(dev); 247 const struct rte_vdev_driver *driver; 248 249 if (!dev->device.driver) { 250 VDEV_LOG(DEBUG, "no driver attach to device %s\n", name); 251 return 1; 252 } 253 254 driver = container_of(dev->device.driver, const struct rte_vdev_driver, 255 driver); 256 return driver->remove(dev); 257 } 258 259 int 260 rte_vdev_uninit(const char *name) 261 { 262 struct rte_vdev_device *dev; 263 struct rte_devargs *devargs; 264 int ret; 265 266 if (name == NULL) 267 return -EINVAL; 268 269 dev = find_vdev(name); 270 if (!dev) 271 return -ENOENT; 272 273 devargs = dev->device.devargs; 274 275 ret = vdev_remove_driver(dev); 276 if (ret) 277 return ret; 278 279 TAILQ_REMOVE(&vdev_device_list, dev, next); 280 281 TAILQ_REMOVE(&devargs_list, devargs, next); 282 283 free(devargs->args); 284 free(devargs); 285 free(dev); 286 return 0; 287 } 288 289 static int 290 vdev_scan(void) 291 { 292 struct rte_vdev_device *dev; 293 struct rte_devargs *devargs; 294 struct vdev_custom_scan *custom_scan; 295 296 /* call custom scan callbacks if any */ 297 rte_spinlock_lock(&vdev_custom_scan_lock); 298 TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) { 299 if (custom_scan->callback != NULL) 300 /* 301 * the callback should update devargs list 302 * by calling rte_eal_devargs_insert() with 303 * devargs.bus = rte_bus_find_by_name("vdev"); 304 * devargs.type = RTE_DEVTYPE_VIRTUAL; 305 * devargs.policy = RTE_DEV_WHITELISTED; 306 */ 307 custom_scan->callback(custom_scan->user_arg); 308 } 309 rte_spinlock_unlock(&vdev_custom_scan_lock); 310 311 /* for virtual devices we scan the devargs_list populated via cmdline */ 312 TAILQ_FOREACH(devargs, &devargs_list, next) { 313 314 if (devargs->bus != &rte_vdev_bus) 315 continue; 316 317 dev = find_vdev(devargs->name); 318 if (dev) 319 continue; 320 321 dev = calloc(1, sizeof(*dev)); 322 if (!dev) 323 return -1; 324 325 dev->device.devargs = devargs; 326 dev->device.numa_node = SOCKET_ID_ANY; 327 dev->device.name = devargs->name; 328 329 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next); 330 } 331 332 return 0; 333 } 334 335 static int 336 vdev_probe(void) 337 { 338 struct rte_vdev_device *dev; 339 int ret = 0; 340 341 /* call the init function for each virtual device */ 342 TAILQ_FOREACH(dev, &vdev_device_list, next) { 343 344 if (dev->device.driver) 345 continue; 346 347 if (vdev_probe_all_drivers(dev)) { 348 VDEV_LOG(ERR, "failed to initialize %s device\n", 349 rte_vdev_device_name(dev)); 350 ret = -1; 351 } 352 } 353 354 return ret; 355 } 356 357 static struct rte_device * 358 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, 359 const void *data) 360 { 361 struct rte_vdev_device *dev; 362 363 TAILQ_FOREACH(dev, &vdev_device_list, next) { 364 if (start && &dev->device == start) { 365 start = NULL; 366 continue; 367 } 368 if (cmp(&dev->device, data) == 0) 369 return &dev->device; 370 } 371 return NULL; 372 } 373 374 static int 375 vdev_plug(struct rte_device *dev) 376 { 377 return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev)); 378 } 379 380 static int 381 vdev_unplug(struct rte_device *dev) 382 { 383 return rte_vdev_uninit(dev->name); 384 } 385 386 static struct rte_bus rte_vdev_bus = { 387 .scan = vdev_scan, 388 .probe = vdev_probe, 389 .find_device = vdev_find_device, 390 .plug = vdev_plug, 391 .unplug = vdev_unplug, 392 .parse = vdev_parse, 393 }; 394 395 RTE_REGISTER_BUS(vdev, rte_vdev_bus); 396 397 RTE_INIT(vdev_init_log) 398 { 399 vdev_logtype_bus = rte_log_register("bus.vdev"); 400 if (vdev_logtype_bus >= 0) 401 rte_log_set_level(vdev_logtype_bus, RTE_LOG_NOTICE); 402 } 403