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