17b4f1e6bSMatan Azrad /* SPDX-License-Identifier: BSD-3-Clause 27b4f1e6bSMatan Azrad * Copyright 2019 Mellanox Technologies, Ltd 37b4f1e6bSMatan Azrad */ 47b4f1e6bSMatan Azrad 57b4f1e6bSMatan Azrad #include <unistd.h> 67b4f1e6bSMatan Azrad #include <string.h> 793e30982SMatan Azrad #include <stdio.h> 8a6e7cd81STonghao Zhang #ifdef RTE_IBVERBS_LINK_DLOPEN 9a6e7cd81STonghao Zhang #include <dlfcn.h> 10a6e7cd81STonghao Zhang #endif 117b4f1e6bSMatan Azrad 127b4f1e6bSMatan Azrad #include <rte_errno.h> 137b4f1e6bSMatan Azrad 147b4f1e6bSMatan Azrad #include "mlx5_common.h" 157b4f1e6bSMatan Azrad #include "mlx5_common_utils.h" 167b4f1e6bSMatan Azrad #include "mlx5_glue.h" 177b4f1e6bSMatan Azrad 187b4f1e6bSMatan Azrad 197b4f1e6bSMatan Azrad int mlx5_common_logtype; 207b4f1e6bSMatan Azrad 217b4f1e6bSMatan Azrad 2293e30982SMatan Azrad /** 2393e30982SMatan Azrad * Get PCI information by sysfs device path. 2493e30982SMatan Azrad * 2593e30982SMatan Azrad * @param dev_path 2693e30982SMatan Azrad * Pointer to device sysfs folder name. 2793e30982SMatan Azrad * @param[out] pci_addr 2893e30982SMatan Azrad * PCI bus address output buffer. 2993e30982SMatan Azrad * 3093e30982SMatan Azrad * @return 3193e30982SMatan Azrad * 0 on success, a negative errno value otherwise and rte_errno is set. 3293e30982SMatan Azrad */ 3393e30982SMatan Azrad int 3493e30982SMatan Azrad mlx5_dev_to_pci_addr(const char *dev_path, 3593e30982SMatan Azrad struct rte_pci_addr *pci_addr) 3693e30982SMatan Azrad { 3793e30982SMatan Azrad FILE *file; 3893e30982SMatan Azrad char line[32]; 3993e30982SMatan Azrad MKSTR(path, "%s/device/uevent", dev_path); 4093e30982SMatan Azrad 4193e30982SMatan Azrad file = fopen(path, "rb"); 4293e30982SMatan Azrad if (file == NULL) { 4393e30982SMatan Azrad rte_errno = errno; 4493e30982SMatan Azrad return -rte_errno; 4593e30982SMatan Azrad } 4693e30982SMatan Azrad while (fgets(line, sizeof(line), file) == line) { 4793e30982SMatan Azrad size_t len = strlen(line); 4893e30982SMatan Azrad int ret; 4993e30982SMatan Azrad 5093e30982SMatan Azrad /* Truncate long lines. */ 5193e30982SMatan Azrad if (len == (sizeof(line) - 1)) 5293e30982SMatan Azrad while (line[(len - 1)] != '\n') { 5393e30982SMatan Azrad ret = fgetc(file); 5493e30982SMatan Azrad if (ret == EOF) 5593e30982SMatan Azrad break; 5693e30982SMatan Azrad line[(len - 1)] = ret; 5793e30982SMatan Azrad } 5893e30982SMatan Azrad /* Extract information. */ 5993e30982SMatan Azrad if (sscanf(line, 6093e30982SMatan Azrad "PCI_SLOT_NAME=" 6193e30982SMatan Azrad "%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n", 6293e30982SMatan Azrad &pci_addr->domain, 6393e30982SMatan Azrad &pci_addr->bus, 6493e30982SMatan Azrad &pci_addr->devid, 6593e30982SMatan Azrad &pci_addr->function) == 4) { 6693e30982SMatan Azrad ret = 0; 6793e30982SMatan Azrad break; 6893e30982SMatan Azrad } 6993e30982SMatan Azrad } 7093e30982SMatan Azrad fclose(file); 7193e30982SMatan Azrad return 0; 7293e30982SMatan Azrad } 7393e30982SMatan Azrad 74d768f324SMatan Azrad static int 75d768f324SMatan Azrad mlx5_class_check_handler(__rte_unused const char *key, const char *value, 76d768f324SMatan Azrad void *opaque) 77d768f324SMatan Azrad { 78d768f324SMatan Azrad enum mlx5_class *ret = opaque; 79d768f324SMatan Azrad 80d768f324SMatan Azrad if (strcmp(value, "vdpa") == 0) { 81d768f324SMatan Azrad *ret = MLX5_CLASS_VDPA; 82d768f324SMatan Azrad } else if (strcmp(value, "net") == 0) { 83d768f324SMatan Azrad *ret = MLX5_CLASS_NET; 84d768f324SMatan Azrad } else { 85d768f324SMatan Azrad DRV_LOG(ERR, "Invalid mlx5 class %s. Maybe typo in device" 86d768f324SMatan Azrad " class argument setting?", value); 87d768f324SMatan Azrad *ret = MLX5_CLASS_INVALID; 88d768f324SMatan Azrad } 89d768f324SMatan Azrad return 0; 90d768f324SMatan Azrad } 91d768f324SMatan Azrad 92d768f324SMatan Azrad enum mlx5_class 93d768f324SMatan Azrad mlx5_class_get(struct rte_devargs *devargs) 94d768f324SMatan Azrad { 95d768f324SMatan Azrad struct rte_kvargs *kvlist; 96d768f324SMatan Azrad const char *key = MLX5_CLASS_ARG_NAME; 97d768f324SMatan Azrad enum mlx5_class ret = MLX5_CLASS_NET; 98d768f324SMatan Azrad 99d768f324SMatan Azrad if (devargs == NULL) 100d768f324SMatan Azrad return ret; 101d768f324SMatan Azrad kvlist = rte_kvargs_parse(devargs->args, NULL); 102d768f324SMatan Azrad if (kvlist == NULL) 103d768f324SMatan Azrad return ret; 104d768f324SMatan Azrad if (rte_kvargs_count(kvlist, key)) 105d768f324SMatan Azrad rte_kvargs_process(kvlist, key, mlx5_class_check_handler, &ret); 106d768f324SMatan Azrad rte_kvargs_free(kvlist); 107d768f324SMatan Azrad return ret; 108d768f324SMatan Azrad } 109d768f324SMatan Azrad 110654810b5SMatan Azrad /** 111654810b5SMatan Azrad * Extract port name, as a number, from sysfs or netlink information. 112654810b5SMatan Azrad * 113654810b5SMatan Azrad * @param[in] port_name_in 114654810b5SMatan Azrad * String representing the port name. 115654810b5SMatan Azrad * @param[out] port_info_out 116654810b5SMatan Azrad * Port information, including port name as a number and port name 117654810b5SMatan Azrad * type if recognized 118654810b5SMatan Azrad * 119654810b5SMatan Azrad * @return 120654810b5SMatan Azrad * port_name field set according to recognized name format. 121654810b5SMatan Azrad */ 122654810b5SMatan Azrad void 123654810b5SMatan Azrad mlx5_translate_port_name(const char *port_name_in, 124654810b5SMatan Azrad struct mlx5_switch_info *port_info_out) 125654810b5SMatan Azrad { 126654810b5SMatan Azrad char pf_c1, pf_c2, vf_c1, vf_c2; 127654810b5SMatan Azrad char *end; 128654810b5SMatan Azrad int sc_items; 129654810b5SMatan Azrad 130654810b5SMatan Azrad /* 131654810b5SMatan Azrad * Check for port-name as a string of the form pf0vf0 132654810b5SMatan Azrad * (support kernel ver >= 5.0 or OFED ver >= 4.6). 133654810b5SMatan Azrad */ 134654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%c%d%c%c%d", 135654810b5SMatan Azrad &pf_c1, &pf_c2, &port_info_out->pf_num, 136654810b5SMatan Azrad &vf_c1, &vf_c2, &port_info_out->port_name); 137654810b5SMatan Azrad if (sc_items == 6 && 138654810b5SMatan Azrad pf_c1 == 'p' && pf_c2 == 'f' && 139654810b5SMatan Azrad vf_c1 == 'v' && vf_c2 == 'f') { 140654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_PFVF; 141654810b5SMatan Azrad return; 142654810b5SMatan Azrad } 143654810b5SMatan Azrad /* 144654810b5SMatan Azrad * Check for port-name as a string of the form p0 145654810b5SMatan Azrad * (support kernel ver >= 5.0, or OFED ver >= 4.6). 146654810b5SMatan Azrad */ 147654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%d", 148654810b5SMatan Azrad &pf_c1, &port_info_out->port_name); 149654810b5SMatan Azrad if (sc_items == 2 && pf_c1 == 'p') { 150654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UPLINK; 151654810b5SMatan Azrad return; 152654810b5SMatan Azrad } 153654810b5SMatan Azrad /* Check for port-name as a number (support kernel ver < 5.0 */ 154654810b5SMatan Azrad errno = 0; 155654810b5SMatan Azrad port_info_out->port_name = strtol(port_name_in, &end, 0); 156654810b5SMatan Azrad if (!errno && 157654810b5SMatan Azrad (size_t)(end - port_name_in) == strlen(port_name_in)) { 158654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_LEGACY; 159654810b5SMatan Azrad return; 160654810b5SMatan Azrad } 161654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN; 162654810b5SMatan Azrad return; 163654810b5SMatan Azrad } 164654810b5SMatan Azrad 165*83c99c36SThomas Monjalon #ifdef MLX5_GLUE 1667b4f1e6bSMatan Azrad 1677b4f1e6bSMatan Azrad /** 1687b4f1e6bSMatan Azrad * Suffix RTE_EAL_PMD_PATH with "-glue". 1697b4f1e6bSMatan Azrad * 1707b4f1e6bSMatan Azrad * This function performs a sanity check on RTE_EAL_PMD_PATH before 1717b4f1e6bSMatan Azrad * suffixing its last component. 1727b4f1e6bSMatan Azrad * 1737b4f1e6bSMatan Azrad * @param buf[out] 1747b4f1e6bSMatan Azrad * Output buffer, should be large enough otherwise NULL is returned. 1757b4f1e6bSMatan Azrad * @param size 1767b4f1e6bSMatan Azrad * Size of @p out. 1777b4f1e6bSMatan Azrad * 1787b4f1e6bSMatan Azrad * @return 1797b4f1e6bSMatan Azrad * Pointer to @p buf or @p NULL in case suffix cannot be appended. 1807b4f1e6bSMatan Azrad */ 1817b4f1e6bSMatan Azrad static char * 1827b4f1e6bSMatan Azrad mlx5_glue_path(char *buf, size_t size) 1837b4f1e6bSMatan Azrad { 1847b4f1e6bSMatan Azrad static const char *const bad[] = { "/", ".", "..", NULL }; 1857b4f1e6bSMatan Azrad const char *path = RTE_EAL_PMD_PATH; 1867b4f1e6bSMatan Azrad size_t len = strlen(path); 1877b4f1e6bSMatan Azrad size_t off; 1887b4f1e6bSMatan Azrad int i; 1897b4f1e6bSMatan Azrad 1907b4f1e6bSMatan Azrad while (len && path[len - 1] == '/') 1917b4f1e6bSMatan Azrad --len; 1927b4f1e6bSMatan Azrad for (off = len; off && path[off - 1] != '/'; --off) 1937b4f1e6bSMatan Azrad ; 1947b4f1e6bSMatan Azrad for (i = 0; bad[i]; ++i) 1957b4f1e6bSMatan Azrad if (!strncmp(path + off, bad[i], (int)(len - off))) 1967b4f1e6bSMatan Azrad goto error; 1977b4f1e6bSMatan Azrad i = snprintf(buf, size, "%.*s-glue", (int)len, path); 1987b4f1e6bSMatan Azrad if (i == -1 || (size_t)i >= size) 1997b4f1e6bSMatan Azrad goto error; 2007b4f1e6bSMatan Azrad return buf; 2017b4f1e6bSMatan Azrad error: 2027b4f1e6bSMatan Azrad RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of" 2037b4f1e6bSMatan Azrad " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please" 2047b4f1e6bSMatan Azrad " re-configure DPDK"); 2057b4f1e6bSMatan Azrad return NULL; 2067b4f1e6bSMatan Azrad } 2077b4f1e6bSMatan Azrad 208*83c99c36SThomas Monjalon static int 209*83c99c36SThomas Monjalon mlx5_glue_dlopen(void) 2107b4f1e6bSMatan Azrad { 2117b4f1e6bSMatan Azrad char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")]; 212a6e7cd81STonghao Zhang void *handle = NULL; 213a6e7cd81STonghao Zhang 2147b4f1e6bSMatan Azrad const char *path[] = { 2157b4f1e6bSMatan Azrad /* 2167b4f1e6bSMatan Azrad * A basic security check is necessary before trusting 2177b4f1e6bSMatan Azrad * MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH. 2187b4f1e6bSMatan Azrad */ 2197b4f1e6bSMatan Azrad (geteuid() == getuid() && getegid() == getgid() ? 2207b4f1e6bSMatan Azrad getenv("MLX5_GLUE_PATH") : NULL), 2217b4f1e6bSMatan Azrad /* 2227b4f1e6bSMatan Azrad * When RTE_EAL_PMD_PATH is set, use its glue-suffixed 2237b4f1e6bSMatan Azrad * variant, otherwise let dlopen() look up libraries on its 2247b4f1e6bSMatan Azrad * own. 2257b4f1e6bSMatan Azrad */ 2267b4f1e6bSMatan Azrad (*RTE_EAL_PMD_PATH ? 2277b4f1e6bSMatan Azrad mlx5_glue_path(glue_path, sizeof(glue_path)) : ""), 2287b4f1e6bSMatan Azrad }; 2297b4f1e6bSMatan Azrad unsigned int i = 0; 2307b4f1e6bSMatan Azrad void **sym; 2317b4f1e6bSMatan Azrad const char *dlmsg; 2327b4f1e6bSMatan Azrad 2337b4f1e6bSMatan Azrad while (!handle && i != RTE_DIM(path)) { 2347b4f1e6bSMatan Azrad const char *end; 2357b4f1e6bSMatan Azrad size_t len; 2367b4f1e6bSMatan Azrad int ret; 2377b4f1e6bSMatan Azrad 2387b4f1e6bSMatan Azrad if (!path[i]) { 2397b4f1e6bSMatan Azrad ++i; 2407b4f1e6bSMatan Azrad continue; 2417b4f1e6bSMatan Azrad } 2427b4f1e6bSMatan Azrad end = strpbrk(path[i], ":;"); 2437b4f1e6bSMatan Azrad if (!end) 2447b4f1e6bSMatan Azrad end = path[i] + strlen(path[i]); 2457b4f1e6bSMatan Azrad len = end - path[i]; 2467b4f1e6bSMatan Azrad ret = 0; 2477b4f1e6bSMatan Azrad do { 2487b4f1e6bSMatan Azrad char name[ret + 1]; 2497b4f1e6bSMatan Azrad 2507b4f1e6bSMatan Azrad ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE, 2517b4f1e6bSMatan Azrad (int)len, path[i], 2527b4f1e6bSMatan Azrad (!len || *(end - 1) == '/') ? "" : "/"); 2537b4f1e6bSMatan Azrad if (ret == -1) 2547b4f1e6bSMatan Azrad break; 2557b4f1e6bSMatan Azrad if (sizeof(name) != (size_t)ret + 1) 2567b4f1e6bSMatan Azrad continue; 2577b4f1e6bSMatan Azrad DRV_LOG(DEBUG, "Looking for rdma-core glue as " 2587b4f1e6bSMatan Azrad "\"%s\"", name); 2597b4f1e6bSMatan Azrad handle = dlopen(name, RTLD_LAZY); 2607b4f1e6bSMatan Azrad break; 2617b4f1e6bSMatan Azrad } while (1); 2627b4f1e6bSMatan Azrad path[i] = end + 1; 2637b4f1e6bSMatan Azrad if (!*end) 2647b4f1e6bSMatan Azrad ++i; 2657b4f1e6bSMatan Azrad } 2667b4f1e6bSMatan Azrad if (!handle) { 2677b4f1e6bSMatan Azrad rte_errno = EINVAL; 2687b4f1e6bSMatan Azrad dlmsg = dlerror(); 2697b4f1e6bSMatan Azrad if (dlmsg) 2707b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot load glue library: %s", dlmsg); 2717b4f1e6bSMatan Azrad goto glue_error; 2727b4f1e6bSMatan Azrad } 2737b4f1e6bSMatan Azrad sym = dlsym(handle, "mlx5_glue"); 2747b4f1e6bSMatan Azrad if (!sym || !*sym) { 2757b4f1e6bSMatan Azrad rte_errno = EINVAL; 2767b4f1e6bSMatan Azrad dlmsg = dlerror(); 2777b4f1e6bSMatan Azrad if (dlmsg) 2787b4f1e6bSMatan Azrad DRV_LOG(ERR, "Cannot resolve glue symbol: %s", dlmsg); 2797b4f1e6bSMatan Azrad goto glue_error; 2807b4f1e6bSMatan Azrad } 2817b4f1e6bSMatan Azrad mlx5_glue = *sym; 282*83c99c36SThomas Monjalon return 0; 283*83c99c36SThomas Monjalon 284*83c99c36SThomas Monjalon glue_error: 285*83c99c36SThomas Monjalon if (handle) 286*83c99c36SThomas Monjalon dlclose(handle); 287*83c99c36SThomas Monjalon return -1; 288*83c99c36SThomas Monjalon } 289*83c99c36SThomas Monjalon 290*83c99c36SThomas Monjalon #endif 291*83c99c36SThomas Monjalon 292*83c99c36SThomas Monjalon RTE_INIT_PRIO(mlx5_log_init, LOG) 293*83c99c36SThomas Monjalon { 294*83c99c36SThomas Monjalon mlx5_common_logtype = rte_log_register("pmd.common.mlx5"); 295*83c99c36SThomas Monjalon if (mlx5_common_logtype >= 0) 296*83c99c36SThomas Monjalon rte_log_set_level(mlx5_common_logtype, RTE_LOG_NOTICE); 297*83c99c36SThomas Monjalon } 298*83c99c36SThomas Monjalon 299*83c99c36SThomas Monjalon /** 300*83c99c36SThomas Monjalon * Initialization routine for run-time dependency on rdma-core. 301*83c99c36SThomas Monjalon */ 302*83c99c36SThomas Monjalon RTE_INIT_PRIO(mlx5_glue_init, CLASS) 303*83c99c36SThomas Monjalon { 304*83c99c36SThomas Monjalon /* 305*83c99c36SThomas Monjalon * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use 306*83c99c36SThomas Monjalon * huge pages. Calling ibv_fork_init() during init allows 307*83c99c36SThomas Monjalon * applications to use fork() safely for purposes other than 308*83c99c36SThomas Monjalon * using this PMD, which is not supported in forked processes. 309*83c99c36SThomas Monjalon */ 310*83c99c36SThomas Monjalon setenv("RDMAV_HUGEPAGES_SAFE", "1", 1); 311*83c99c36SThomas Monjalon /* Match the size of Rx completion entry to the size of a cacheline. */ 312*83c99c36SThomas Monjalon if (RTE_CACHE_LINE_SIZE == 128) 313*83c99c36SThomas Monjalon setenv("MLX5_CQE_SIZE", "128", 0); 314*83c99c36SThomas Monjalon /* 315*83c99c36SThomas Monjalon * MLX5_DEVICE_FATAL_CLEANUP tells ibv_destroy functions to 316*83c99c36SThomas Monjalon * cleanup all the Verbs resources even when the device was removed. 317*83c99c36SThomas Monjalon */ 318*83c99c36SThomas Monjalon setenv("MLX5_DEVICE_FATAL_CLEANUP", "1", 1); 319*83c99c36SThomas Monjalon 320*83c99c36SThomas Monjalon #ifdef MLX5_GLUE 321*83c99c36SThomas Monjalon if (mlx5_glue_dlopen() != 0) 322*83c99c36SThomas Monjalon goto glue_error; 323*83c99c36SThomas Monjalon #endif 324*83c99c36SThomas Monjalon 3250afacb04SAlexander Kozyrev #ifdef RTE_LIBRTE_MLX5_DEBUG 3267b4f1e6bSMatan Azrad /* Glue structure must not contain any NULL pointers. */ 3277b4f1e6bSMatan Azrad { 3287b4f1e6bSMatan Azrad unsigned int i; 3297b4f1e6bSMatan Azrad 3307b4f1e6bSMatan Azrad for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i) 3318e46d4e1SAlexander Kozyrev MLX5_ASSERT(((const void *const *)mlx5_glue)[i]); 3327b4f1e6bSMatan Azrad } 3337b4f1e6bSMatan Azrad #endif 3347b4f1e6bSMatan Azrad if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) { 3357b4f1e6bSMatan Azrad rte_errno = EINVAL; 3367b4f1e6bSMatan Azrad DRV_LOG(ERR, "rdma-core glue \"%s\" mismatch: \"%s\" is " 3377b4f1e6bSMatan Azrad "required", mlx5_glue->version, MLX5_GLUE_VERSION); 3387b4f1e6bSMatan Azrad goto glue_error; 3397b4f1e6bSMatan Azrad } 3407b4f1e6bSMatan Azrad mlx5_glue->fork_init(); 3417b4f1e6bSMatan Azrad return; 342*83c99c36SThomas Monjalon 3437b4f1e6bSMatan Azrad glue_error: 3447b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot initialize MLX5 common due to missing" 3457b4f1e6bSMatan Azrad " run-time dependency on rdma-core libraries (libibverbs," 3467b4f1e6bSMatan Azrad " libmlx5)"); 3477b4f1e6bSMatan Azrad mlx5_glue = NULL; 3487b4f1e6bSMatan Azrad return; 3497b4f1e6bSMatan Azrad } 350