LCOV - code coverage report
Current view: top level - drivers/bus/vdev - vdev.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 161 248 64.9 %
Date: 2025-05-01 17:49:45 Functions: 17 24 70.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 97 180 53.9 %

           Branch data     Line data    Source code
       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 <eal_export.h>
      14                 :            : #include <rte_eal.h>
      15                 :            : #include <dev_driver.h>
      16                 :            : #include <bus_driver.h>
      17                 :            : #include <rte_common.h>
      18                 :            : #include <rte_devargs.h>
      19                 :            : #include <rte_memory.h>
      20                 :            : #include <rte_tailq.h>
      21                 :            : #include <rte_spinlock.h>
      22                 :            : #include <rte_string_fns.h>
      23                 :            : #include <rte_errno.h>
      24                 :            : 
      25                 :            : #include "bus_vdev_driver.h"
      26                 :            : #include "vdev_logs.h"
      27                 :            : #include "vdev_private.h"
      28                 :            : 
      29                 :            : #define VDEV_MP_KEY     "bus_vdev_mp"
      30                 :            : 
      31                 :            : /* Forward declare to access virtual bus name */
      32                 :            : static struct rte_bus rte_vdev_bus;
      33                 :            : 
      34                 :            : 
      35                 :            : static TAILQ_HEAD(, rte_vdev_device) vdev_device_list =
      36                 :            :         TAILQ_HEAD_INITIALIZER(vdev_device_list);
      37                 :            : /* The lock needs to be recursive because a vdev can manage another vdev. */
      38                 :            : static rte_spinlock_recursive_t vdev_device_list_lock =
      39                 :            :         RTE_SPINLOCK_RECURSIVE_INITIALIZER;
      40                 :            : 
      41                 :            : static TAILQ_HEAD(, rte_vdev_driver) vdev_driver_list =
      42                 :            :         TAILQ_HEAD_INITIALIZER(vdev_driver_list);
      43                 :            : 
      44                 :            : struct vdev_custom_scan {
      45                 :            :         TAILQ_ENTRY(vdev_custom_scan) next;
      46                 :            :         rte_vdev_scan_callback callback;
      47                 :            :         void *user_arg;
      48                 :            : };
      49                 :            : TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
      50                 :            : static struct vdev_custom_scans vdev_custom_scans =
      51                 :            :         TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
      52                 :            : static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
      53                 :            : 
      54                 :            : /* register a driver */
      55                 :            : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdev_register)
      56                 :            : void
      57                 :      10080 : rte_vdev_register(struct rte_vdev_driver *driver)
      58                 :            : {
      59                 :      10080 :         TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
      60                 :      10080 : }
      61                 :            : 
      62                 :            : /* unregister a driver */
      63                 :            : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdev_unregister)
      64                 :            : void
      65                 :          0 : rte_vdev_unregister(struct rte_vdev_driver *driver)
      66                 :            : {
      67         [ #  # ]:          0 :         TAILQ_REMOVE(&vdev_driver_list, driver, next);
      68                 :          0 : }
      69                 :            : 
      70                 :            : RTE_EXPORT_SYMBOL(rte_vdev_add_custom_scan)
      71                 :            : int
      72                 :          0 : rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
      73                 :            : {
      74                 :            :         struct vdev_custom_scan *custom_scan;
      75                 :            : 
      76                 :            :         rte_spinlock_lock(&vdev_custom_scan_lock);
      77                 :            : 
      78                 :            :         /* check if already registered */
      79         [ #  # ]:          0 :         TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
      80         [ #  # ]:          0 :                 if (custom_scan->callback == callback &&
      81         [ #  # ]:          0 :                                 custom_scan->user_arg == user_arg)
      82                 :            :                         break;
      83                 :            :         }
      84                 :            : 
      85         [ #  # ]:          0 :         if (custom_scan == NULL) {
      86                 :          0 :                 custom_scan = malloc(sizeof(struct vdev_custom_scan));
      87         [ #  # ]:          0 :                 if (custom_scan != NULL) {
      88                 :          0 :                         custom_scan->callback = callback;
      89                 :          0 :                         custom_scan->user_arg = user_arg;
      90                 :          0 :                         TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
      91                 :            :                 }
      92                 :            :         }
      93                 :            : 
      94                 :            :         rte_spinlock_unlock(&vdev_custom_scan_lock);
      95                 :            : 
      96         [ #  # ]:          0 :         return (custom_scan == NULL) ? -1 : 0;
      97                 :            : }
      98                 :            : 
      99                 :            : RTE_EXPORT_SYMBOL(rte_vdev_remove_custom_scan)
     100                 :            : int
     101                 :          0 : rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
     102                 :            : {
     103                 :            :         struct vdev_custom_scan *custom_scan, *tmp_scan;
     104                 :            : 
     105                 :            :         rte_spinlock_lock(&vdev_custom_scan_lock);
     106         [ #  # ]:          0 :         RTE_TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next,
     107                 :            :                                 tmp_scan) {
     108         [ #  # ]:          0 :                 if (custom_scan->callback != callback ||
     109   [ #  #  #  # ]:          0 :                                 (custom_scan->user_arg != (void *)-1 &&
     110                 :            :                                 custom_scan->user_arg != user_arg))
     111                 :          0 :                         continue;
     112         [ #  # ]:          0 :                 TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
     113                 :          0 :                 free(custom_scan);
     114                 :            :         }
     115                 :            :         rte_spinlock_unlock(&vdev_custom_scan_lock);
     116                 :            : 
     117                 :          0 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :            : static int
     121                 :         66 : vdev_parse(const char *name, void *addr)
     122                 :            : {
     123                 :            :         struct rte_vdev_driver **out = addr;
     124                 :            :         struct rte_vdev_driver *driver = NULL;
     125                 :            : 
     126         [ +  + ]:       1476 :         TAILQ_FOREACH(driver, &vdev_driver_list, next) {
     127         [ +  + ]:       1461 :                 if (strncmp(driver->driver.name, name,
     128                 :            :                             strlen(driver->driver.name)) == 0)
     129                 :            :                         break;
     130         [ +  + ]:       1412 :                 if (driver->driver.alias &&
     131         [ +  + ]:        512 :                     strncmp(driver->driver.alias, name,
     132                 :            :                             strlen(driver->driver.alias)) == 0)
     133                 :            :                         break;
     134                 :            :         }
     135                 :         66 :         if (driver != NULL &&
     136         [ +  + ]:         66 :             addr != NULL)
     137                 :         37 :                 *out = driver;
     138                 :         66 :         return driver == NULL;
     139                 :            : }
     140                 :            : 
     141                 :            : static int
     142                 :          0 : vdev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
     143                 :            : {
     144                 :          0 :         struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
     145                 :            :         const struct rte_vdev_driver *driver;
     146                 :            : 
     147         [ #  # ]:          0 :         if (!vdev) {
     148                 :          0 :                 rte_errno = EINVAL;
     149                 :          0 :                 return -1;
     150                 :            :         }
     151                 :            : 
     152         [ #  # ]:          0 :         if (!vdev->device.driver) {
     153                 :          0 :                 VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
     154                 :          0 :                 return 1;
     155                 :            :         }
     156                 :            : 
     157                 :          0 :         driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
     158                 :            :                         driver);
     159                 :            : 
     160         [ #  # ]:          0 :         if (driver->dma_map)
     161                 :          0 :                 return driver->dma_map(vdev, addr, iova, len);
     162                 :            : 
     163                 :            :         return 0;
     164                 :            : }
     165                 :            : 
     166                 :            : static int
     167                 :          0 : vdev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
     168                 :            : {
     169                 :          0 :         struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
     170                 :            :         const struct rte_vdev_driver *driver;
     171                 :            : 
     172         [ #  # ]:          0 :         if (!vdev) {
     173                 :          0 :                 rte_errno = EINVAL;
     174                 :          0 :                 return -1;
     175                 :            :         }
     176                 :            : 
     177         [ #  # ]:          0 :         if (!vdev->device.driver) {
     178                 :          0 :                 VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
     179                 :          0 :                 return 1;
     180                 :            :         }
     181                 :            : 
     182                 :          0 :         driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
     183                 :            :                         driver);
     184                 :            : 
     185         [ #  # ]:          0 :         if (driver->dma_unmap)
     186                 :          0 :                 return driver->dma_unmap(vdev, addr, iova, len);
     187                 :            : 
     188                 :            :         return 0;
     189                 :            : }
     190                 :            : 
     191                 :            : static int
     192                 :         29 : vdev_probe_all_drivers(struct rte_vdev_device *dev)
     193                 :            : {
     194                 :            :         const char *name;
     195                 :            :         struct rte_vdev_driver *driver;
     196                 :            :         enum rte_iova_mode iova_mode;
     197                 :            :         int ret;
     198                 :            : 
     199         [ +  - ]:         29 :         if (rte_dev_is_probed(&dev->device))
     200                 :            :                 return -EEXIST;
     201                 :            : 
     202                 :            :         name = rte_vdev_device_name(dev);
     203                 :         29 :         VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
     204                 :            : 
     205         [ +  - ]:         29 :         if (vdev_parse(name, &driver))
     206                 :            :                 return -1;
     207                 :            : 
     208                 :         29 :         iova_mode = rte_eal_iova_mode();
     209   [ +  +  -  + ]:         29 :         if ((driver->drv_flags & RTE_VDEV_DRV_NEED_IOVA_AS_VA) && (iova_mode == RTE_IOVA_PA)) {
     210                 :          0 :                 VDEV_LOG(ERR, "%s requires VA IOVA mode but current mode is PA, not initializing",
     211                 :            :                                 name);
     212                 :          0 :                 return -1;
     213                 :            :         }
     214                 :            : 
     215                 :         29 :         ret = driver->probe(dev);
     216         [ +  - ]:         29 :         if (ret == 0)
     217                 :         29 :                 dev->device.driver = &driver->driver;
     218                 :            :         return ret;
     219                 :            : }
     220                 :            : 
     221                 :            : /* The caller shall be responsible for thread-safe */
     222                 :            : static struct rte_vdev_device *
     223                 :         49 : find_vdev(const char *name)
     224                 :            : {
     225                 :            :         struct rte_vdev_device *dev;
     226                 :            : 
     227         [ +  - ]:         49 :         if (!name)
     228                 :            :                 return NULL;
     229                 :            : 
     230         [ +  + ]:         86 :         TAILQ_FOREACH(dev, &vdev_device_list, next) {
     231                 :            :                 const char *devname = rte_vdev_device_name(dev);
     232                 :            : 
     233         [ +  + ]:         55 :                 if (!strcmp(devname, name))
     234                 :         18 :                         return dev;
     235                 :            :         }
     236                 :            : 
     237                 :            :         return NULL;
     238                 :            : }
     239                 :            : 
     240                 :            : static struct rte_devargs *
     241                 :         20 : alloc_devargs(const char *name, const char *args)
     242                 :            : {
     243                 :            :         struct rte_devargs *devargs;
     244                 :            :         int ret;
     245                 :            : 
     246                 :         20 :         devargs = calloc(1, sizeof(*devargs));
     247         [ +  - ]:         20 :         if (!devargs)
     248                 :            :                 return NULL;
     249                 :            : 
     250                 :         20 :         devargs->bus = &rte_vdev_bus;
     251         [ +  + ]:         20 :         if (args)
     252                 :         14 :                 devargs->data = strdup(args);
     253                 :            :         else
     254                 :          6 :                 devargs->data = strdup("");
     255         [ -  + ]:         20 :         if (devargs->data == NULL) {
     256                 :          0 :                 free(devargs);
     257                 :          0 :                 return NULL;
     258                 :            :         }
     259                 :         20 :         devargs->args = devargs->data;
     260                 :            : 
     261         [ -  + ]:         20 :         ret = strlcpy(devargs->name, name, sizeof(devargs->name));
     262         [ -  + ]:         20 :         if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
     263                 :          0 :                 rte_devargs_reset(devargs);
     264                 :          0 :                 free(devargs);
     265                 :          0 :                 return NULL;
     266                 :            :         }
     267                 :            : 
     268                 :            :         return devargs;
     269                 :            : }
     270                 :            : 
     271                 :            : static int
     272                 :         20 : insert_vdev(const char *name, const char *args,
     273                 :            :                 struct rte_vdev_device **p_dev,
     274                 :            :                 bool init)
     275                 :            : {
     276                 :            :         struct rte_vdev_device *dev;
     277                 :            :         struct rte_devargs *devargs;
     278                 :            :         int ret;
     279                 :            : 
     280         [ +  - ]:         20 :         if (name == NULL)
     281                 :            :                 return -EINVAL;
     282                 :            : 
     283                 :         20 :         devargs = alloc_devargs(name, args);
     284                 :            : 
     285         [ +  - ]:         20 :         if (!devargs)
     286                 :            :                 return -ENOMEM;
     287                 :            : 
     288                 :         20 :         dev = calloc(1, sizeof(*dev));
     289         [ -  + ]:         20 :         if (!dev) {
     290                 :            :                 ret = -ENOMEM;
     291                 :          0 :                 goto fail;
     292                 :            :         }
     293                 :            : 
     294                 :         20 :         dev->device.bus = &rte_vdev_bus;
     295                 :         20 :         dev->device.numa_node = SOCKET_ID_ANY;
     296                 :            : 
     297         [ -  + ]:         20 :         if (find_vdev(name)) {
     298                 :            :                 /*
     299                 :            :                  * A vdev is expected to have only one port.
     300                 :            :                  * So there is no reason to try probing again,
     301                 :            :                  * even with new arguments.
     302                 :            :                  */
     303                 :            :                 ret = -EEXIST;
     304                 :          0 :                 goto fail;
     305                 :            :         }
     306                 :            : 
     307         [ +  + ]:         20 :         if (init)
     308                 :         19 :                 rte_devargs_insert(&devargs);
     309                 :         20 :         dev->device.devargs = devargs;
     310                 :         20 :         dev->device.name = devargs->name;
     311                 :         20 :         TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
     312                 :            : 
     313         [ +  + ]:         20 :         if (p_dev)
     314                 :         19 :                 *p_dev = dev;
     315                 :            : 
     316                 :            :         return 0;
     317                 :          0 : fail:
     318                 :          0 :         rte_devargs_reset(devargs);
     319                 :          0 :         free(devargs);
     320                 :          0 :         free(dev);
     321                 :          0 :         return ret;
     322                 :            : }
     323                 :            : 
     324                 :            : RTE_EXPORT_SYMBOL(rte_vdev_init)
     325                 :            : int
     326                 :         19 : rte_vdev_init(const char *name, const char *args)
     327                 :            : {
     328                 :            :         struct rte_vdev_device *dev;
     329                 :            :         int ret;
     330                 :            : 
     331                 :         19 :         rte_spinlock_recursive_lock(&vdev_device_list_lock);
     332                 :         19 :         ret = insert_vdev(name, args, &dev, true);
     333         [ +  - ]:         19 :         if (ret == 0) {
     334                 :         19 :                 ret = vdev_probe_all_drivers(dev);
     335         [ -  + ]:         19 :                 if (ret) {
     336         [ #  # ]:          0 :                         if (ret > 0)
     337                 :          0 :                                 VDEV_LOG(ERR, "no driver found for %s", name);
     338                 :            :                         /* If fails, remove it from vdev list */
     339         [ #  # ]:          0 :                         TAILQ_REMOVE(&vdev_device_list, dev, next);
     340                 :          0 :                         rte_devargs_remove(dev->device.devargs);
     341                 :          0 :                         free(dev);
     342                 :            :                 }
     343                 :            :         }
     344                 :            :         rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     345                 :         19 :         return ret;
     346                 :            : }
     347                 :            : 
     348                 :            : static int
     349         [ +  - ]:         17 : vdev_remove_driver(struct rte_vdev_device *dev)
     350                 :            : {
     351                 :            :         const char *name = rte_vdev_device_name(dev);
     352                 :            :         const struct rte_vdev_driver *driver;
     353                 :            : 
     354         [ -  + ]:         17 :         if (!dev->device.driver) {
     355                 :          0 :                 VDEV_LOG(DEBUG, "no driver attach to device %s", name);
     356                 :          0 :                 return 1;
     357                 :            :         }
     358                 :            : 
     359                 :         17 :         driver = container_of(dev->device.driver, const struct rte_vdev_driver,
     360                 :            :                 driver);
     361                 :         17 :         return driver->remove(dev);
     362                 :            : }
     363                 :            : 
     364                 :            : RTE_EXPORT_SYMBOL(rte_vdev_uninit)
     365                 :            : int
     366                 :         18 : rte_vdev_uninit(const char *name)
     367                 :            : {
     368                 :            :         struct rte_vdev_device *dev;
     369                 :            :         int ret;
     370                 :            : 
     371         [ +  - ]:         18 :         if (name == NULL)
     372                 :            :                 return -EINVAL;
     373                 :            : 
     374                 :         18 :         rte_spinlock_recursive_lock(&vdev_device_list_lock);
     375                 :            : 
     376                 :         18 :         dev = find_vdev(name);
     377         [ +  + ]:         18 :         if (!dev) {
     378                 :            :                 ret = -ENOENT;
     379                 :          1 :                 goto unlock;
     380                 :            :         }
     381                 :            : 
     382                 :         17 :         ret = vdev_remove_driver(dev);
     383         [ -  + ]:         17 :         if (ret)
     384                 :          0 :                 goto unlock;
     385                 :            : 
     386         [ +  + ]:         17 :         TAILQ_REMOVE(&vdev_device_list, dev, next);
     387                 :         17 :         rte_devargs_remove(dev->device.devargs);
     388                 :         17 :         free(dev);
     389                 :            : 
     390         [ +  - ]:         18 : unlock:
     391                 :            :         rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     392                 :            :         return ret;
     393                 :            : }
     394                 :            : 
     395                 :            : struct vdev_param {
     396                 :            : #define VDEV_SCAN_REQ   1
     397                 :            : #define VDEV_SCAN_ONE   2
     398                 :            : #define VDEV_SCAN_REP   3
     399                 :            :         int type;
     400                 :            :         int num;
     401                 :            :         char name[RTE_DEV_NAME_MAX_LEN];
     402                 :            : };
     403                 :            : 
     404                 :            : static int vdev_plug(struct rte_device *dev);
     405                 :            : 
     406                 :            : /**
     407                 :            :  * This function works as the action for both primary and secondary process
     408                 :            :  * for static vdev discovery when a secondary process is booting.
     409                 :            :  *
     410                 :            :  * step 1, secondary process sends a sync request to ask for vdev in primary;
     411                 :            :  * step 2, primary process receives the request, and send vdevs one by one;
     412                 :            :  * step 3, primary process sends back reply, which indicates how many vdevs
     413                 :            :  * are sent.
     414                 :            :  */
     415                 :            : static int
     416      [ +  +  - ]:         27 : vdev_action(const struct rte_mp_msg *mp_msg, const void *peer)
     417                 :            : {
     418                 :            :         struct rte_vdev_device *dev;
     419                 :            :         struct rte_mp_msg mp_resp;
     420                 :            :         struct vdev_param *ou = (struct vdev_param *)&mp_resp.param;
     421                 :            :         const struct vdev_param *in = (const struct vdev_param *)mp_msg->param;
     422                 :            :         const char *devname;
     423                 :            :         int num;
     424                 :            :         int ret;
     425                 :            : 
     426                 :            :         strlcpy(mp_resp.name, VDEV_MP_KEY, sizeof(mp_resp.name));
     427                 :         27 :         mp_resp.len_param = sizeof(*ou);
     428                 :         27 :         mp_resp.num_fds = 0;
     429                 :            : 
     430      [ +  +  - ]:         27 :         switch (in->type) {
     431                 :         26 :         case VDEV_SCAN_REQ:
     432                 :         26 :                 ou->type = VDEV_SCAN_ONE;
     433                 :         26 :                 ou->num = 1;
     434                 :            :                 num = 0;
     435                 :            : 
     436                 :         26 :                 rte_spinlock_recursive_lock(&vdev_device_list_lock);
     437         [ +  + ]:         27 :                 TAILQ_FOREACH(dev, &vdev_device_list, next) {
     438                 :            :                         devname = rte_vdev_device_name(dev);
     439         [ -  + ]:          1 :                         if (strlen(devname) == 0) {
     440                 :          0 :                                 VDEV_LOG(INFO, "vdev with no name is not sent");
     441                 :          0 :                                 continue;
     442                 :            :                         }
     443                 :          1 :                         VDEV_LOG(INFO, "send vdev, %s", devname);
     444                 :            :                         strlcpy(ou->name, devname, RTE_DEV_NAME_MAX_LEN);
     445         [ -  + ]:          1 :                         if (rte_mp_sendmsg(&mp_resp) < 0)
     446                 :          0 :                                 VDEV_LOG(ERR, "send vdev, %s, failed, %s",
     447                 :            :                                          devname, strerror(rte_errno));
     448                 :          1 :                         num++;
     449                 :            :                 }
     450                 :            :                 rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     451                 :            : 
     452                 :         26 :                 ou->type = VDEV_SCAN_REP;
     453                 :         26 :                 ou->num = num;
     454         [ -  + ]:         26 :                 if (rte_mp_reply(&mp_resp, peer) < 0)
     455                 :          0 :                         VDEV_LOG(ERR, "Failed to reply a scan request");
     456                 :            :                 break;
     457                 :          1 :         case VDEV_SCAN_ONE:
     458                 :          1 :                 VDEV_LOG(INFO, "receive vdev, %s", in->name);
     459                 :          1 :                 ret = insert_vdev(in->name, NULL, NULL, false);
     460         [ -  + ]:          1 :                 if (ret == -EEXIST)
     461                 :          0 :                         VDEV_LOG(DEBUG, "device already exist, %s", in->name);
     462         [ -  + ]:          1 :                 else if (ret < 0)
     463                 :          0 :                         VDEV_LOG(ERR, "failed to add vdev, %s", in->name);
     464                 :            :                 break;
     465                 :          0 :         default:
     466                 :          0 :                 VDEV_LOG(ERR, "vdev cannot recognize this message");
     467                 :            :         }
     468                 :            : 
     469                 :         27 :         return 0;
     470                 :            : }
     471                 :            : 
     472                 :            : static int
     473                 :        185 : vdev_scan(void)
     474                 :            : {
     475                 :            :         struct rte_vdev_device *dev;
     476                 :            :         struct rte_devargs *devargs;
     477                 :            :         struct vdev_custom_scan *custom_scan;
     478                 :            : 
     479         [ +  + ]:        185 :         if (rte_mp_action_register(VDEV_MP_KEY, vdev_action) < 0 &&
     480         [ +  - ]:          7 :             rte_errno != EEXIST) {
     481                 :            :                 /* for primary, unsupported IPC is not an error */
     482         [ +  - ]:          7 :                 if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
     483         [ +  - ]:          7 :                                 rte_errno == ENOTSUP)
     484                 :          7 :                         goto scan;
     485                 :          0 :                 VDEV_LOG(ERR, "Failed to add vdev mp action");
     486                 :          0 :                 return -1;
     487                 :            :         }
     488                 :            : 
     489         [ +  + ]:        178 :         if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
     490                 :            :                 struct rte_mp_msg mp_req, *mp_rep;
     491                 :            :                 struct rte_mp_reply mp_reply;
     492                 :         27 :                 struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
     493                 :            :                 struct vdev_param *req = (struct vdev_param *)mp_req.param;
     494                 :            :                 struct vdev_param *resp;
     495                 :            : 
     496                 :            :                 strlcpy(mp_req.name, VDEV_MP_KEY, sizeof(mp_req.name));
     497                 :         27 :                 mp_req.len_param = sizeof(*req);
     498                 :         27 :                 mp_req.num_fds = 0;
     499                 :         27 :                 req->type = VDEV_SCAN_REQ;
     500         [ +  + ]:         27 :                 if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0 &&
     501         [ +  - ]:         26 :                     mp_reply.nb_received == 1) {
     502                 :         26 :                         mp_rep = &mp_reply.msgs[0];
     503                 :            :                         resp = (struct vdev_param *)mp_rep->param;
     504                 :         26 :                         VDEV_LOG(INFO, "Received %d vdevs", resp->num);
     505                 :         26 :                         free(mp_reply.msgs);
     506                 :            :                 } else
     507                 :          1 :                         VDEV_LOG(ERR, "Failed to request vdev from primary");
     508                 :            : 
     509                 :            :                 /* Fall through to allow private vdevs in secondary process */
     510                 :            :         }
     511                 :            : 
     512                 :        185 : scan:
     513                 :            :         /* call custom scan callbacks if any */
     514                 :            :         rte_spinlock_lock(&vdev_custom_scan_lock);
     515         [ -  + ]:        185 :         TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
     516         [ #  # ]:          0 :                 if (custom_scan->callback != NULL)
     517                 :            :                         /*
     518                 :            :                          * the callback should update devargs list
     519                 :            :                          * by calling rte_devargs_insert() with
     520                 :            :                          *     devargs.bus = rte_bus_find_by_name("vdev");
     521                 :            :                          *     devargs.type = RTE_DEVTYPE_VIRTUAL;
     522                 :            :                          *     devargs.policy = RTE_DEV_ALLOWED;
     523                 :            :                          */
     524                 :          0 :                         custom_scan->callback(custom_scan->user_arg);
     525                 :            :         }
     526                 :            :         rte_spinlock_unlock(&vdev_custom_scan_lock);
     527                 :            : 
     528                 :            :         /* for virtual devices we scan the devargs_list populated via cmdline */
     529         [ +  + ]:        196 :         RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
     530                 :            : 
     531                 :         11 :                 dev = calloc(1, sizeof(*dev));
     532         [ +  - ]:         11 :                 if (!dev)
     533                 :            :                         return -1;
     534                 :            : 
     535                 :         11 :                 rte_spinlock_recursive_lock(&vdev_device_list_lock);
     536                 :            : 
     537         [ +  + ]:         11 :                 if (find_vdev(devargs->name)) {
     538                 :            :                         rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     539                 :          1 :                         free(dev);
     540                 :          1 :                         continue;
     541                 :            :                 }
     542                 :            : 
     543                 :         10 :                 dev->device.bus = &rte_vdev_bus;
     544                 :         10 :                 dev->device.devargs = devargs;
     545                 :         10 :                 dev->device.numa_node = SOCKET_ID_ANY;
     546                 :         10 :                 dev->device.name = devargs->name;
     547                 :            : 
     548         [ +  - ]:         10 :                 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
     549                 :            : 
     550                 :            :                 rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     551                 :            :         }
     552                 :            : 
     553                 :            :         return 0;
     554                 :            : }
     555                 :            : 
     556                 :            : static int
     557                 :        180 : vdev_probe(void)
     558                 :            : {
     559                 :            :         struct rte_vdev_device *dev;
     560                 :            :         int r, ret = 0;
     561                 :            : 
     562                 :            :         /* call the init function for each virtual device */
     563         [ +  + ]:        190 :         TAILQ_FOREACH(dev, &vdev_device_list, next) {
     564                 :            :                 /* we don't use the vdev lock here, as it's only used in DPDK
     565                 :            :                  * initialization; and we don't want to hold such a lock when
     566                 :            :                  * we call each driver probe.
     567                 :            :                  */
     568                 :            : 
     569                 :         10 :                 r = vdev_probe_all_drivers(dev);
     570         [ -  + ]:         10 :                 if (r != 0) {
     571         [ #  # ]:          0 :                         if (r == -EEXIST)
     572                 :          0 :                                 continue;
     573                 :          0 :                         VDEV_LOG(ERR, "failed to initialize %s device",
     574                 :            :                                 rte_vdev_device_name(dev));
     575                 :            :                         ret = -1;
     576                 :            :                 }
     577                 :            :         }
     578                 :            : 
     579                 :        180 :         return ret;
     580                 :            : }
     581                 :            : 
     582                 :            : static int
     583                 :        252 : vdev_cleanup(void)
     584                 :            : {
     585                 :            :         struct rte_vdev_device *dev, *tmp_dev;
     586                 :            :         int error = 0;
     587                 :            : 
     588         [ +  + ]:        265 :         RTE_TAILQ_FOREACH_SAFE(dev, &vdev_device_list, next, tmp_dev) {
     589                 :            :                 const struct rte_vdev_driver *drv;
     590                 :            :                 int ret = 0;
     591                 :            : 
     592         [ +  + ]:         13 :                 if (dev->device.driver == NULL)
     593                 :          1 :                         goto free;
     594                 :            : 
     595                 :         12 :                 drv = container_of(dev->device.driver, const struct rte_vdev_driver, driver);
     596                 :            : 
     597         [ -  + ]:         12 :                 if (drv->remove == NULL)
     598                 :          0 :                         goto free;
     599                 :            : 
     600                 :         12 :                 ret = drv->remove(dev);
     601         [ -  + ]:         12 :                 if (ret < 0)
     602                 :            :                         error = -1;
     603                 :            : 
     604                 :            :                 dev->device.driver = NULL;
     605                 :         13 : free:
     606                 :         13 :                 free(dev);
     607                 :            :         }
     608                 :            : 
     609                 :        252 :         return error;
     610                 :            : }
     611                 :            : 
     612                 :            : struct rte_device *
     613                 :         10 : rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
     614                 :            :                      const void *data)
     615                 :            : {
     616                 :            :         const struct rte_vdev_device *vstart;
     617                 :            :         struct rte_vdev_device *dev;
     618                 :            : 
     619                 :         10 :         rte_spinlock_recursive_lock(&vdev_device_list_lock);
     620         [ +  + ]:         10 :         if (start != NULL) {
     621                 :          2 :                 vstart = RTE_DEV_TO_VDEV_CONST(start);
     622                 :          2 :                 dev = TAILQ_NEXT(vstart, next);
     623                 :            :         } else {
     624                 :          8 :                 dev = TAILQ_FIRST(&vdev_device_list);
     625                 :            :         }
     626         [ +  + ]:         14 :         while (dev != NULL) {
     627         [ +  + ]:         12 :                 if (cmp(&dev->device, data) == 0)
     628                 :            :                         break;
     629                 :          4 :                 dev = TAILQ_NEXT(dev, next);
     630                 :            :         }
     631                 :            :         rte_spinlock_recursive_unlock(&vdev_device_list_lock);
     632                 :            : 
     633         [ +  + ]:         10 :         return dev ? &dev->device : NULL;
     634                 :            : }
     635                 :            : 
     636                 :            : static int
     637                 :          0 : vdev_plug(struct rte_device *dev)
     638                 :            : {
     639                 :          0 :         return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
     640                 :            : }
     641                 :            : 
     642                 :            : static int
     643                 :          0 : vdev_unplug(struct rte_device *dev)
     644                 :            : {
     645                 :          0 :         return rte_vdev_uninit(dev->name);
     646                 :            : }
     647                 :            : 
     648                 :            : static enum rte_iova_mode
     649                 :        185 : vdev_get_iommu_class(void)
     650                 :            : {
     651                 :            :         const char *name;
     652                 :            :         struct rte_vdev_device *dev;
     653                 :            :         struct rte_vdev_driver *driver;
     654                 :            : 
     655         [ +  + ]:        192 :         TAILQ_FOREACH(dev, &vdev_device_list, next) {
     656                 :            :                 name = rte_vdev_device_name(dev);
     657         [ -  + ]:          8 :                 if (vdev_parse(name, &driver))
     658                 :          0 :                         continue;
     659                 :            : 
     660         [ +  + ]:          8 :                 if (driver->drv_flags & RTE_VDEV_DRV_NEED_IOVA_AS_VA)
     661                 :            :                         return RTE_IOVA_VA;
     662                 :            :         }
     663                 :            : 
     664                 :            :         return RTE_IOVA_DC;
     665                 :            : }
     666                 :            : 
     667                 :            : static struct rte_bus rte_vdev_bus = {
     668                 :            :         .scan = vdev_scan,
     669                 :            :         .probe = vdev_probe,
     670                 :            :         .cleanup = vdev_cleanup,
     671                 :            :         .find_device = rte_vdev_find_device,
     672                 :            :         .plug = vdev_plug,
     673                 :            :         .unplug = vdev_unplug,
     674                 :            :         .parse = vdev_parse,
     675                 :            :         .dma_map = vdev_dma_map,
     676                 :            :         .dma_unmap = vdev_dma_unmap,
     677                 :            :         .get_iommu_class = vdev_get_iommu_class,
     678                 :            :         .dev_iterate = rte_vdev_dev_iterate,
     679                 :            : };
     680                 :            : 
     681                 :        252 : RTE_REGISTER_BUS(vdev, rte_vdev_bus);
     682         [ -  + ]:        252 : RTE_LOG_REGISTER_DEFAULT(vdev_logtype_bus, NOTICE);

Generated by: LCOV version 1.14