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_errno.h> 48 49 #include "rte_bus_vdev.h" 50 #include "vdev_logs.h" 51 52 int vdev_logtype_bus; 53 54 /* Forward declare to access virtual bus name */ 55 static struct rte_bus rte_vdev_bus; 56 57 /** Double linked list of virtual device drivers. */ 58 TAILQ_HEAD(vdev_device_list, rte_vdev_device); 59 60 static struct vdev_device_list vdev_device_list = 61 TAILQ_HEAD_INITIALIZER(vdev_device_list); 62 struct vdev_driver_list vdev_driver_list = 63 TAILQ_HEAD_INITIALIZER(vdev_driver_list); 64 65 /* register a driver */ 66 void 67 rte_vdev_register(struct rte_vdev_driver *driver) 68 { 69 TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next); 70 } 71 72 /* unregister a driver */ 73 void 74 rte_vdev_unregister(struct rte_vdev_driver *driver) 75 { 76 TAILQ_REMOVE(&vdev_driver_list, driver, next); 77 } 78 79 static int 80 vdev_parse(const char *name, void *addr) 81 { 82 struct rte_vdev_driver **out = addr; 83 struct rte_vdev_driver *driver = NULL; 84 85 TAILQ_FOREACH(driver, &vdev_driver_list, next) { 86 if (strncmp(driver->driver.name, name, 87 strlen(driver->driver.name)) == 0) 88 break; 89 if (driver->driver.alias && 90 strncmp(driver->driver.alias, name, 91 strlen(driver->driver.alias)) == 0) 92 break; 93 } 94 if (driver != NULL && 95 addr != NULL) 96 *out = driver; 97 return driver == NULL; 98 } 99 100 static int 101 vdev_probe_all_drivers(struct rte_vdev_device *dev) 102 { 103 const char *name; 104 struct rte_vdev_driver *driver; 105 int ret; 106 107 name = rte_vdev_device_name(dev); 108 109 VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name, 110 rte_vdev_device_name(dev)); 111 112 if (vdev_parse(name, &driver)) 113 return -1; 114 dev->device.driver = &driver->driver; 115 ret = driver->probe(dev); 116 if (ret) 117 dev->device.driver = NULL; 118 return ret; 119 } 120 121 static struct rte_vdev_device * 122 find_vdev(const char *name) 123 { 124 struct rte_vdev_device *dev; 125 126 if (!name) 127 return NULL; 128 129 TAILQ_FOREACH(dev, &vdev_device_list, next) { 130 const char *devname = rte_vdev_device_name(dev); 131 132 if (!strncmp(devname, name, strlen(name))) 133 return dev; 134 } 135 136 return NULL; 137 } 138 139 static struct rte_devargs * 140 alloc_devargs(const char *name, const char *args) 141 { 142 struct rte_devargs *devargs; 143 int ret; 144 145 devargs = calloc(1, sizeof(*devargs)); 146 if (!devargs) 147 return NULL; 148 149 devargs->bus = &rte_vdev_bus; 150 if (args) 151 devargs->args = strdup(args); 152 else 153 devargs->args = strdup(""); 154 155 ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name); 156 if (ret < 0 || ret >= (int)sizeof(devargs->name)) { 157 free(devargs->args); 158 free(devargs); 159 return NULL; 160 } 161 162 return devargs; 163 } 164 165 int 166 rte_vdev_init(const char *name, const char *args) 167 { 168 struct rte_vdev_device *dev; 169 struct rte_devargs *devargs; 170 int ret; 171 172 if (name == NULL) 173 return -EINVAL; 174 175 dev = find_vdev(name); 176 if (dev) 177 return -EEXIST; 178 179 devargs = alloc_devargs(name, args); 180 if (!devargs) 181 return -ENOMEM; 182 183 dev = calloc(1, sizeof(*dev)); 184 if (!dev) { 185 ret = -ENOMEM; 186 goto fail; 187 } 188 189 dev->device.devargs = devargs; 190 dev->device.numa_node = SOCKET_ID_ANY; 191 dev->device.name = devargs->name; 192 193 ret = vdev_probe_all_drivers(dev); 194 if (ret) { 195 if (ret > 0) 196 VDEV_LOG(ERR, "no driver found for %s\n", name); 197 goto fail; 198 } 199 200 TAILQ_INSERT_TAIL(&devargs_list, devargs, next); 201 202 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next); 203 return 0; 204 205 fail: 206 free(devargs->args); 207 free(devargs); 208 free(dev); 209 return ret; 210 } 211 212 static int 213 vdev_remove_driver(struct rte_vdev_device *dev) 214 { 215 const char *name = rte_vdev_device_name(dev); 216 const struct rte_vdev_driver *driver; 217 218 if (!dev->device.driver) { 219 VDEV_LOG(DEBUG, "no driver attach to device %s\n", name); 220 return 1; 221 } 222 223 driver = container_of(dev->device.driver, const struct rte_vdev_driver, 224 driver); 225 return driver->remove(dev); 226 } 227 228 int 229 rte_vdev_uninit(const char *name) 230 { 231 struct rte_vdev_device *dev; 232 struct rte_devargs *devargs; 233 int ret; 234 235 if (name == NULL) 236 return -EINVAL; 237 238 dev = find_vdev(name); 239 if (!dev) 240 return -ENOENT; 241 242 devargs = dev->device.devargs; 243 244 ret = vdev_remove_driver(dev); 245 if (ret) 246 return ret; 247 248 TAILQ_REMOVE(&vdev_device_list, dev, next); 249 250 TAILQ_REMOVE(&devargs_list, devargs, next); 251 252 free(devargs->args); 253 free(devargs); 254 free(dev); 255 return 0; 256 } 257 258 static int 259 vdev_scan(void) 260 { 261 struct rte_vdev_device *dev; 262 struct rte_devargs *devargs; 263 264 /* for virtual devices we scan the devargs_list populated via cmdline */ 265 TAILQ_FOREACH(devargs, &devargs_list, next) { 266 267 if (devargs->bus != &rte_vdev_bus) 268 continue; 269 270 dev = find_vdev(devargs->name); 271 if (dev) 272 continue; 273 274 dev = calloc(1, sizeof(*dev)); 275 if (!dev) 276 return -1; 277 278 dev->device.devargs = devargs; 279 dev->device.numa_node = SOCKET_ID_ANY; 280 dev->device.name = devargs->name; 281 282 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next); 283 } 284 285 return 0; 286 } 287 288 static int 289 vdev_probe(void) 290 { 291 struct rte_vdev_device *dev; 292 293 /* call the init function for each virtual device */ 294 TAILQ_FOREACH(dev, &vdev_device_list, next) { 295 296 if (dev->device.driver) 297 continue; 298 299 if (vdev_probe_all_drivers(dev)) { 300 VDEV_LOG(ERR, "failed to initialize %s device\n", 301 rte_vdev_device_name(dev)); 302 return -1; 303 } 304 } 305 306 return 0; 307 } 308 309 static struct rte_device * 310 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, 311 const void *data) 312 { 313 struct rte_vdev_device *dev; 314 315 TAILQ_FOREACH(dev, &vdev_device_list, next) { 316 if (start && &dev->device == start) { 317 start = NULL; 318 continue; 319 } 320 if (cmp(&dev->device, data) == 0) 321 return &dev->device; 322 } 323 return NULL; 324 } 325 326 static int 327 vdev_plug(struct rte_device *dev) 328 { 329 return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev)); 330 } 331 332 static int 333 vdev_unplug(struct rte_device *dev) 334 { 335 return rte_vdev_uninit(dev->name); 336 } 337 338 static struct rte_bus rte_vdev_bus = { 339 .scan = vdev_scan, 340 .probe = vdev_probe, 341 .find_device = vdev_find_device, 342 .plug = vdev_plug, 343 .unplug = vdev_unplug, 344 .parse = vdev_parse, 345 }; 346 347 RTE_REGISTER_BUS(vdev, rte_vdev_bus); 348 349 RTE_INIT(vdev_init_log) 350 { 351 vdev_logtype_bus = rte_log_register("bus.vdev"); 352 if (vdev_logtype_bus >= 0) 353 rte_log_set_level(vdev_logtype_bus, RTE_LOG_NOTICE); 354 } 355