17b4f1e6bSMatan Azrad /* SPDX-License-Identifier: BSD-3-Clause 27b4f1e6bSMatan Azrad * Copyright 2019 Mellanox Technologies, Ltd 37b4f1e6bSMatan Azrad */ 47b4f1e6bSMatan Azrad 57b4f1e6bSMatan Azrad #include <dlfcn.h> 67b4f1e6bSMatan Azrad #include <unistd.h> 77b4f1e6bSMatan Azrad #include <string.h> 893e30982SMatan Azrad #include <stdio.h> 97b4f1e6bSMatan Azrad 107b4f1e6bSMatan Azrad #include <rte_errno.h> 117b4f1e6bSMatan Azrad 127b4f1e6bSMatan Azrad #include "mlx5_common.h" 137b4f1e6bSMatan Azrad #include "mlx5_common_utils.h" 147b4f1e6bSMatan Azrad #include "mlx5_glue.h" 157b4f1e6bSMatan Azrad 167b4f1e6bSMatan Azrad 177b4f1e6bSMatan Azrad int mlx5_common_logtype; 187b4f1e6bSMatan Azrad 197b4f1e6bSMatan Azrad 2093e30982SMatan Azrad /** 2193e30982SMatan Azrad * Get PCI information by sysfs device path. 2293e30982SMatan Azrad * 2393e30982SMatan Azrad * @param dev_path 2493e30982SMatan Azrad * Pointer to device sysfs folder name. 2593e30982SMatan Azrad * @param[out] pci_addr 2693e30982SMatan Azrad * PCI bus address output buffer. 2793e30982SMatan Azrad * 2893e30982SMatan Azrad * @return 2993e30982SMatan Azrad * 0 on success, a negative errno value otherwise and rte_errno is set. 3093e30982SMatan Azrad */ 3193e30982SMatan Azrad int 3293e30982SMatan Azrad mlx5_dev_to_pci_addr(const char *dev_path, 3393e30982SMatan Azrad struct rte_pci_addr *pci_addr) 3493e30982SMatan Azrad { 3593e30982SMatan Azrad FILE *file; 3693e30982SMatan Azrad char line[32]; 3793e30982SMatan Azrad MKSTR(path, "%s/device/uevent", dev_path); 3893e30982SMatan Azrad 3993e30982SMatan Azrad file = fopen(path, "rb"); 4093e30982SMatan Azrad if (file == NULL) { 4193e30982SMatan Azrad rte_errno = errno; 4293e30982SMatan Azrad return -rte_errno; 4393e30982SMatan Azrad } 4493e30982SMatan Azrad while (fgets(line, sizeof(line), file) == line) { 4593e30982SMatan Azrad size_t len = strlen(line); 4693e30982SMatan Azrad int ret; 4793e30982SMatan Azrad 4893e30982SMatan Azrad /* Truncate long lines. */ 4993e30982SMatan Azrad if (len == (sizeof(line) - 1)) 5093e30982SMatan Azrad while (line[(len - 1)] != '\n') { 5193e30982SMatan Azrad ret = fgetc(file); 5293e30982SMatan Azrad if (ret == EOF) 5393e30982SMatan Azrad break; 5493e30982SMatan Azrad line[(len - 1)] = ret; 5593e30982SMatan Azrad } 5693e30982SMatan Azrad /* Extract information. */ 5793e30982SMatan Azrad if (sscanf(line, 5893e30982SMatan Azrad "PCI_SLOT_NAME=" 5993e30982SMatan Azrad "%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n", 6093e30982SMatan Azrad &pci_addr->domain, 6193e30982SMatan Azrad &pci_addr->bus, 6293e30982SMatan Azrad &pci_addr->devid, 6393e30982SMatan Azrad &pci_addr->function) == 4) { 6493e30982SMatan Azrad ret = 0; 6593e30982SMatan Azrad break; 6693e30982SMatan Azrad } 6793e30982SMatan Azrad } 6893e30982SMatan Azrad fclose(file); 6993e30982SMatan Azrad return 0; 7093e30982SMatan Azrad } 7193e30982SMatan Azrad 72*d768f324SMatan Azrad static int 73*d768f324SMatan Azrad mlx5_class_check_handler(__rte_unused const char *key, const char *value, 74*d768f324SMatan Azrad void *opaque) 75*d768f324SMatan Azrad { 76*d768f324SMatan Azrad enum mlx5_class *ret = opaque; 77*d768f324SMatan Azrad 78*d768f324SMatan Azrad if (strcmp(value, "vdpa") == 0) { 79*d768f324SMatan Azrad *ret = MLX5_CLASS_VDPA; 80*d768f324SMatan Azrad } else if (strcmp(value, "net") == 0) { 81*d768f324SMatan Azrad *ret = MLX5_CLASS_NET; 82*d768f324SMatan Azrad } else { 83*d768f324SMatan Azrad DRV_LOG(ERR, "Invalid mlx5 class %s. Maybe typo in device" 84*d768f324SMatan Azrad " class argument setting?", value); 85*d768f324SMatan Azrad *ret = MLX5_CLASS_INVALID; 86*d768f324SMatan Azrad } 87*d768f324SMatan Azrad return 0; 88*d768f324SMatan Azrad } 89*d768f324SMatan Azrad 90*d768f324SMatan Azrad enum mlx5_class 91*d768f324SMatan Azrad mlx5_class_get(struct rte_devargs *devargs) 92*d768f324SMatan Azrad { 93*d768f324SMatan Azrad struct rte_kvargs *kvlist; 94*d768f324SMatan Azrad const char *key = MLX5_CLASS_ARG_NAME; 95*d768f324SMatan Azrad enum mlx5_class ret = MLX5_CLASS_NET; 96*d768f324SMatan Azrad 97*d768f324SMatan Azrad if (devargs == NULL) 98*d768f324SMatan Azrad return ret; 99*d768f324SMatan Azrad kvlist = rte_kvargs_parse(devargs->args, NULL); 100*d768f324SMatan Azrad if (kvlist == NULL) 101*d768f324SMatan Azrad return ret; 102*d768f324SMatan Azrad if (rte_kvargs_count(kvlist, key)) 103*d768f324SMatan Azrad rte_kvargs_process(kvlist, key, mlx5_class_check_handler, &ret); 104*d768f324SMatan Azrad rte_kvargs_free(kvlist); 105*d768f324SMatan Azrad return ret; 106*d768f324SMatan Azrad } 107*d768f324SMatan Azrad 1087b4f1e6bSMatan Azrad #ifdef RTE_IBVERBS_LINK_DLOPEN 1097b4f1e6bSMatan Azrad 1107b4f1e6bSMatan Azrad /** 1117b4f1e6bSMatan Azrad * Suffix RTE_EAL_PMD_PATH with "-glue". 1127b4f1e6bSMatan Azrad * 1137b4f1e6bSMatan Azrad * This function performs a sanity check on RTE_EAL_PMD_PATH before 1147b4f1e6bSMatan Azrad * suffixing its last component. 1157b4f1e6bSMatan Azrad * 1167b4f1e6bSMatan Azrad * @param buf[out] 1177b4f1e6bSMatan Azrad * Output buffer, should be large enough otherwise NULL is returned. 1187b4f1e6bSMatan Azrad * @param size 1197b4f1e6bSMatan Azrad * Size of @p out. 1207b4f1e6bSMatan Azrad * 1217b4f1e6bSMatan Azrad * @return 1227b4f1e6bSMatan Azrad * Pointer to @p buf or @p NULL in case suffix cannot be appended. 1237b4f1e6bSMatan Azrad */ 1247b4f1e6bSMatan Azrad static char * 1257b4f1e6bSMatan Azrad mlx5_glue_path(char *buf, size_t size) 1267b4f1e6bSMatan Azrad { 1277b4f1e6bSMatan Azrad static const char *const bad[] = { "/", ".", "..", NULL }; 1287b4f1e6bSMatan Azrad const char *path = RTE_EAL_PMD_PATH; 1297b4f1e6bSMatan Azrad size_t len = strlen(path); 1307b4f1e6bSMatan Azrad size_t off; 1317b4f1e6bSMatan Azrad int i; 1327b4f1e6bSMatan Azrad 1337b4f1e6bSMatan Azrad while (len && path[len - 1] == '/') 1347b4f1e6bSMatan Azrad --len; 1357b4f1e6bSMatan Azrad for (off = len; off && path[off - 1] != '/'; --off) 1367b4f1e6bSMatan Azrad ; 1377b4f1e6bSMatan Azrad for (i = 0; bad[i]; ++i) 1387b4f1e6bSMatan Azrad if (!strncmp(path + off, bad[i], (int)(len - off))) 1397b4f1e6bSMatan Azrad goto error; 1407b4f1e6bSMatan Azrad i = snprintf(buf, size, "%.*s-glue", (int)len, path); 1417b4f1e6bSMatan Azrad if (i == -1 || (size_t)i >= size) 1427b4f1e6bSMatan Azrad goto error; 1437b4f1e6bSMatan Azrad return buf; 1447b4f1e6bSMatan Azrad error: 1457b4f1e6bSMatan Azrad RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of" 1467b4f1e6bSMatan Azrad " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please" 1477b4f1e6bSMatan Azrad " re-configure DPDK"); 1487b4f1e6bSMatan Azrad return NULL; 1497b4f1e6bSMatan Azrad } 1507b4f1e6bSMatan Azrad #endif 1517b4f1e6bSMatan Azrad 1527b4f1e6bSMatan Azrad /** 1537b4f1e6bSMatan Azrad * Initialization routine for run-time dependency on rdma-core. 1547b4f1e6bSMatan Azrad */ 1557b4f1e6bSMatan Azrad RTE_INIT_PRIO(mlx5_glue_init, CLASS) 1567b4f1e6bSMatan Azrad { 1577b4f1e6bSMatan Azrad void *handle = NULL; 1587b4f1e6bSMatan Azrad 1597b4f1e6bSMatan Azrad /* Initialize common log type. */ 1607b4f1e6bSMatan Azrad mlx5_common_logtype = rte_log_register("pmd.common.mlx5"); 1617b4f1e6bSMatan Azrad if (mlx5_common_logtype >= 0) 1627b4f1e6bSMatan Azrad rte_log_set_level(mlx5_common_logtype, RTE_LOG_NOTICE); 1637b4f1e6bSMatan Azrad /* 1647b4f1e6bSMatan Azrad * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use 1657b4f1e6bSMatan Azrad * huge pages. Calling ibv_fork_init() during init allows 1667b4f1e6bSMatan Azrad * applications to use fork() safely for purposes other than 1677b4f1e6bSMatan Azrad * using this PMD, which is not supported in forked processes. 1687b4f1e6bSMatan Azrad */ 1697b4f1e6bSMatan Azrad setenv("RDMAV_HUGEPAGES_SAFE", "1", 1); 1707b4f1e6bSMatan Azrad /* Match the size of Rx completion entry to the size of a cacheline. */ 1717b4f1e6bSMatan Azrad if (RTE_CACHE_LINE_SIZE == 128) 1727b4f1e6bSMatan Azrad setenv("MLX5_CQE_SIZE", "128", 0); 1737b4f1e6bSMatan Azrad /* 1747b4f1e6bSMatan Azrad * MLX5_DEVICE_FATAL_CLEANUP tells ibv_destroy functions to 1757b4f1e6bSMatan Azrad * cleanup all the Verbs resources even when the device was removed. 1767b4f1e6bSMatan Azrad */ 1777b4f1e6bSMatan Azrad setenv("MLX5_DEVICE_FATAL_CLEANUP", "1", 1); 1787b4f1e6bSMatan Azrad /* The glue initialization was done earlier by mlx5 common library. */ 1797b4f1e6bSMatan Azrad #ifdef RTE_IBVERBS_LINK_DLOPEN 1807b4f1e6bSMatan Azrad char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")]; 1817b4f1e6bSMatan Azrad const char *path[] = { 1827b4f1e6bSMatan Azrad /* 1837b4f1e6bSMatan Azrad * A basic security check is necessary before trusting 1847b4f1e6bSMatan Azrad * MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH. 1857b4f1e6bSMatan Azrad */ 1867b4f1e6bSMatan Azrad (geteuid() == getuid() && getegid() == getgid() ? 1877b4f1e6bSMatan Azrad getenv("MLX5_GLUE_PATH") : NULL), 1887b4f1e6bSMatan Azrad /* 1897b4f1e6bSMatan Azrad * When RTE_EAL_PMD_PATH is set, use its glue-suffixed 1907b4f1e6bSMatan Azrad * variant, otherwise let dlopen() look up libraries on its 1917b4f1e6bSMatan Azrad * own. 1927b4f1e6bSMatan Azrad */ 1937b4f1e6bSMatan Azrad (*RTE_EAL_PMD_PATH ? 1947b4f1e6bSMatan Azrad mlx5_glue_path(glue_path, sizeof(glue_path)) : ""), 1957b4f1e6bSMatan Azrad }; 1967b4f1e6bSMatan Azrad unsigned int i = 0; 1977b4f1e6bSMatan Azrad void **sym; 1987b4f1e6bSMatan Azrad const char *dlmsg; 1997b4f1e6bSMatan Azrad 2007b4f1e6bSMatan Azrad while (!handle && i != RTE_DIM(path)) { 2017b4f1e6bSMatan Azrad const char *end; 2027b4f1e6bSMatan Azrad size_t len; 2037b4f1e6bSMatan Azrad int ret; 2047b4f1e6bSMatan Azrad 2057b4f1e6bSMatan Azrad if (!path[i]) { 2067b4f1e6bSMatan Azrad ++i; 2077b4f1e6bSMatan Azrad continue; 2087b4f1e6bSMatan Azrad } 2097b4f1e6bSMatan Azrad end = strpbrk(path[i], ":;"); 2107b4f1e6bSMatan Azrad if (!end) 2117b4f1e6bSMatan Azrad end = path[i] + strlen(path[i]); 2127b4f1e6bSMatan Azrad len = end - path[i]; 2137b4f1e6bSMatan Azrad ret = 0; 2147b4f1e6bSMatan Azrad do { 2157b4f1e6bSMatan Azrad char name[ret + 1]; 2167b4f1e6bSMatan Azrad 2177b4f1e6bSMatan Azrad ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE, 2187b4f1e6bSMatan Azrad (int)len, path[i], 2197b4f1e6bSMatan Azrad (!len || *(end - 1) == '/') ? "" : "/"); 2207b4f1e6bSMatan Azrad if (ret == -1) 2217b4f1e6bSMatan Azrad break; 2227b4f1e6bSMatan Azrad if (sizeof(name) != (size_t)ret + 1) 2237b4f1e6bSMatan Azrad continue; 2247b4f1e6bSMatan Azrad DRV_LOG(DEBUG, "Looking for rdma-core glue as " 2257b4f1e6bSMatan Azrad "\"%s\"", name); 2267b4f1e6bSMatan Azrad handle = dlopen(name, RTLD_LAZY); 2277b4f1e6bSMatan Azrad break; 2287b4f1e6bSMatan Azrad } while (1); 2297b4f1e6bSMatan Azrad path[i] = end + 1; 2307b4f1e6bSMatan Azrad if (!*end) 2317b4f1e6bSMatan Azrad ++i; 2327b4f1e6bSMatan Azrad } 2337b4f1e6bSMatan Azrad if (!handle) { 2347b4f1e6bSMatan Azrad rte_errno = EINVAL; 2357b4f1e6bSMatan Azrad dlmsg = dlerror(); 2367b4f1e6bSMatan Azrad if (dlmsg) 2377b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot load glue library: %s", dlmsg); 2387b4f1e6bSMatan Azrad goto glue_error; 2397b4f1e6bSMatan Azrad } 2407b4f1e6bSMatan Azrad sym = dlsym(handle, "mlx5_glue"); 2417b4f1e6bSMatan Azrad if (!sym || !*sym) { 2427b4f1e6bSMatan Azrad rte_errno = EINVAL; 2437b4f1e6bSMatan Azrad dlmsg = dlerror(); 2447b4f1e6bSMatan Azrad if (dlmsg) 2457b4f1e6bSMatan Azrad DRV_LOG(ERR, "Cannot resolve glue symbol: %s", dlmsg); 2467b4f1e6bSMatan Azrad goto glue_error; 2477b4f1e6bSMatan Azrad } 2487b4f1e6bSMatan Azrad mlx5_glue = *sym; 2497b4f1e6bSMatan Azrad #endif /* RTE_IBVERBS_LINK_DLOPEN */ 2507b4f1e6bSMatan Azrad #ifndef NDEBUG 2517b4f1e6bSMatan Azrad /* Glue structure must not contain any NULL pointers. */ 2527b4f1e6bSMatan Azrad { 2537b4f1e6bSMatan Azrad unsigned int i; 2547b4f1e6bSMatan Azrad 2557b4f1e6bSMatan Azrad for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i) 2567b4f1e6bSMatan Azrad assert(((const void *const *)mlx5_glue)[i]); 2577b4f1e6bSMatan Azrad } 2587b4f1e6bSMatan Azrad #endif 2597b4f1e6bSMatan Azrad if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) { 2607b4f1e6bSMatan Azrad rte_errno = EINVAL; 2617b4f1e6bSMatan Azrad DRV_LOG(ERR, "rdma-core glue \"%s\" mismatch: \"%s\" is " 2627b4f1e6bSMatan Azrad "required", mlx5_glue->version, MLX5_GLUE_VERSION); 2637b4f1e6bSMatan Azrad goto glue_error; 2647b4f1e6bSMatan Azrad } 2657b4f1e6bSMatan Azrad mlx5_glue->fork_init(); 2667b4f1e6bSMatan Azrad return; 2677b4f1e6bSMatan Azrad glue_error: 2687b4f1e6bSMatan Azrad if (handle) 2697b4f1e6bSMatan Azrad dlclose(handle); 2707b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot initialize MLX5 common due to missing" 2717b4f1e6bSMatan Azrad " run-time dependency on rdma-core libraries (libibverbs," 2727b4f1e6bSMatan Azrad " libmlx5)"); 2737b4f1e6bSMatan Azrad mlx5_glue = NULL; 2747b4f1e6bSMatan Azrad return; 2757b4f1e6bSMatan Azrad } 276