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