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 21*2889d382SThomas Monjalon #ifdef MLX5_GLUE 22*2889d382SThomas Monjalon const struct mlx5_glue *mlx5_glue; 23*2889d382SThomas Monjalon #endif 247b4f1e6bSMatan Azrad 2593e30982SMatan Azrad /** 2693e30982SMatan Azrad * Get PCI information by sysfs device path. 2793e30982SMatan Azrad * 2893e30982SMatan Azrad * @param dev_path 2993e30982SMatan Azrad * Pointer to device sysfs folder name. 3093e30982SMatan Azrad * @param[out] pci_addr 3193e30982SMatan Azrad * PCI bus address output buffer. 3293e30982SMatan Azrad * 3393e30982SMatan Azrad * @return 3493e30982SMatan Azrad * 0 on success, a negative errno value otherwise and rte_errno is set. 3593e30982SMatan Azrad */ 3693e30982SMatan Azrad int 3793e30982SMatan Azrad mlx5_dev_to_pci_addr(const char *dev_path, 3893e30982SMatan Azrad struct rte_pci_addr *pci_addr) 3993e30982SMatan Azrad { 4093e30982SMatan Azrad FILE *file; 4193e30982SMatan Azrad char line[32]; 4293e30982SMatan Azrad MKSTR(path, "%s/device/uevent", dev_path); 4393e30982SMatan Azrad 4493e30982SMatan Azrad file = fopen(path, "rb"); 4593e30982SMatan Azrad if (file == NULL) { 4693e30982SMatan Azrad rte_errno = errno; 4793e30982SMatan Azrad return -rte_errno; 4893e30982SMatan Azrad } 4993e30982SMatan Azrad while (fgets(line, sizeof(line), file) == line) { 5093e30982SMatan Azrad size_t len = strlen(line); 5193e30982SMatan Azrad int ret; 5293e30982SMatan Azrad 5393e30982SMatan Azrad /* Truncate long lines. */ 5493e30982SMatan Azrad if (len == (sizeof(line) - 1)) 5593e30982SMatan Azrad while (line[(len - 1)] != '\n') { 5693e30982SMatan Azrad ret = fgetc(file); 5793e30982SMatan Azrad if (ret == EOF) 5893e30982SMatan Azrad break; 5993e30982SMatan Azrad line[(len - 1)] = ret; 6093e30982SMatan Azrad } 6193e30982SMatan Azrad /* Extract information. */ 6293e30982SMatan Azrad if (sscanf(line, 6393e30982SMatan Azrad "PCI_SLOT_NAME=" 6493e30982SMatan Azrad "%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n", 6593e30982SMatan Azrad &pci_addr->domain, 6693e30982SMatan Azrad &pci_addr->bus, 6793e30982SMatan Azrad &pci_addr->devid, 6893e30982SMatan Azrad &pci_addr->function) == 4) { 6993e30982SMatan Azrad ret = 0; 7093e30982SMatan Azrad break; 7193e30982SMatan Azrad } 7293e30982SMatan Azrad } 7393e30982SMatan Azrad fclose(file); 7493e30982SMatan Azrad return 0; 7593e30982SMatan Azrad } 7693e30982SMatan Azrad 77d768f324SMatan Azrad static int 78d768f324SMatan Azrad mlx5_class_check_handler(__rte_unused const char *key, const char *value, 79d768f324SMatan Azrad void *opaque) 80d768f324SMatan Azrad { 81d768f324SMatan Azrad enum mlx5_class *ret = opaque; 82d768f324SMatan Azrad 83d768f324SMatan Azrad if (strcmp(value, "vdpa") == 0) { 84d768f324SMatan Azrad *ret = MLX5_CLASS_VDPA; 85d768f324SMatan Azrad } else if (strcmp(value, "net") == 0) { 86d768f324SMatan Azrad *ret = MLX5_CLASS_NET; 87d768f324SMatan Azrad } else { 88d768f324SMatan Azrad DRV_LOG(ERR, "Invalid mlx5 class %s. Maybe typo in device" 89d768f324SMatan Azrad " class argument setting?", value); 90d768f324SMatan Azrad *ret = MLX5_CLASS_INVALID; 91d768f324SMatan Azrad } 92d768f324SMatan Azrad return 0; 93d768f324SMatan Azrad } 94d768f324SMatan Azrad 95d768f324SMatan Azrad enum mlx5_class 96d768f324SMatan Azrad mlx5_class_get(struct rte_devargs *devargs) 97d768f324SMatan Azrad { 98d768f324SMatan Azrad struct rte_kvargs *kvlist; 99d768f324SMatan Azrad const char *key = MLX5_CLASS_ARG_NAME; 100d768f324SMatan Azrad enum mlx5_class ret = MLX5_CLASS_NET; 101d768f324SMatan Azrad 102d768f324SMatan Azrad if (devargs == NULL) 103d768f324SMatan Azrad return ret; 104d768f324SMatan Azrad kvlist = rte_kvargs_parse(devargs->args, NULL); 105d768f324SMatan Azrad if (kvlist == NULL) 106d768f324SMatan Azrad return ret; 107d768f324SMatan Azrad if (rte_kvargs_count(kvlist, key)) 108d768f324SMatan Azrad rte_kvargs_process(kvlist, key, mlx5_class_check_handler, &ret); 109d768f324SMatan Azrad rte_kvargs_free(kvlist); 110d768f324SMatan Azrad return ret; 111d768f324SMatan Azrad } 112d768f324SMatan Azrad 113654810b5SMatan Azrad /** 114654810b5SMatan Azrad * Extract port name, as a number, from sysfs or netlink information. 115654810b5SMatan Azrad * 116654810b5SMatan Azrad * @param[in] port_name_in 117654810b5SMatan Azrad * String representing the port name. 118654810b5SMatan Azrad * @param[out] port_info_out 119654810b5SMatan Azrad * Port information, including port name as a number and port name 120654810b5SMatan Azrad * type if recognized 121654810b5SMatan Azrad * 122654810b5SMatan Azrad * @return 123654810b5SMatan Azrad * port_name field set according to recognized name format. 124654810b5SMatan Azrad */ 125654810b5SMatan Azrad void 126654810b5SMatan Azrad mlx5_translate_port_name(const char *port_name_in, 127654810b5SMatan Azrad struct mlx5_switch_info *port_info_out) 128654810b5SMatan Azrad { 129654810b5SMatan Azrad char pf_c1, pf_c2, vf_c1, vf_c2; 130654810b5SMatan Azrad char *end; 131654810b5SMatan Azrad int sc_items; 132654810b5SMatan Azrad 133654810b5SMatan Azrad /* 134654810b5SMatan Azrad * Check for port-name as a string of the form pf0vf0 135654810b5SMatan Azrad * (support kernel ver >= 5.0 or OFED ver >= 4.6). 136654810b5SMatan Azrad */ 137654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%c%d%c%c%d", 138654810b5SMatan Azrad &pf_c1, &pf_c2, &port_info_out->pf_num, 139654810b5SMatan Azrad &vf_c1, &vf_c2, &port_info_out->port_name); 140654810b5SMatan Azrad if (sc_items == 6 && 141654810b5SMatan Azrad pf_c1 == 'p' && pf_c2 == 'f' && 142654810b5SMatan Azrad vf_c1 == 'v' && vf_c2 == 'f') { 143654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_PFVF; 144654810b5SMatan Azrad return; 145654810b5SMatan Azrad } 146654810b5SMatan Azrad /* 147654810b5SMatan Azrad * Check for port-name as a string of the form p0 148654810b5SMatan Azrad * (support kernel ver >= 5.0, or OFED ver >= 4.6). 149654810b5SMatan Azrad */ 150654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%d", 151654810b5SMatan Azrad &pf_c1, &port_info_out->port_name); 152654810b5SMatan Azrad if (sc_items == 2 && pf_c1 == 'p') { 153654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UPLINK; 154654810b5SMatan Azrad return; 155654810b5SMatan Azrad } 156654810b5SMatan Azrad /* Check for port-name as a number (support kernel ver < 5.0 */ 157654810b5SMatan Azrad errno = 0; 158654810b5SMatan Azrad port_info_out->port_name = strtol(port_name_in, &end, 0); 159654810b5SMatan Azrad if (!errno && 160654810b5SMatan Azrad (size_t)(end - port_name_in) == strlen(port_name_in)) { 161654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_LEGACY; 162654810b5SMatan Azrad return; 163654810b5SMatan Azrad } 164654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN; 165654810b5SMatan Azrad return; 166654810b5SMatan Azrad } 167654810b5SMatan Azrad 16883c99c36SThomas Monjalon #ifdef MLX5_GLUE 1697b4f1e6bSMatan Azrad 1707b4f1e6bSMatan Azrad /** 1717b4f1e6bSMatan Azrad * Suffix RTE_EAL_PMD_PATH with "-glue". 1727b4f1e6bSMatan Azrad * 1737b4f1e6bSMatan Azrad * This function performs a sanity check on RTE_EAL_PMD_PATH before 1747b4f1e6bSMatan Azrad * suffixing its last component. 1757b4f1e6bSMatan Azrad * 1767b4f1e6bSMatan Azrad * @param buf[out] 1777b4f1e6bSMatan Azrad * Output buffer, should be large enough otherwise NULL is returned. 1787b4f1e6bSMatan Azrad * @param size 1797b4f1e6bSMatan Azrad * Size of @p out. 1807b4f1e6bSMatan Azrad * 1817b4f1e6bSMatan Azrad * @return 1827b4f1e6bSMatan Azrad * Pointer to @p buf or @p NULL in case suffix cannot be appended. 1837b4f1e6bSMatan Azrad */ 1847b4f1e6bSMatan Azrad static char * 1857b4f1e6bSMatan Azrad mlx5_glue_path(char *buf, size_t size) 1867b4f1e6bSMatan Azrad { 1877b4f1e6bSMatan Azrad static const char *const bad[] = { "/", ".", "..", NULL }; 1887b4f1e6bSMatan Azrad const char *path = RTE_EAL_PMD_PATH; 1897b4f1e6bSMatan Azrad size_t len = strlen(path); 1907b4f1e6bSMatan Azrad size_t off; 1917b4f1e6bSMatan Azrad int i; 1927b4f1e6bSMatan Azrad 1937b4f1e6bSMatan Azrad while (len && path[len - 1] == '/') 1947b4f1e6bSMatan Azrad --len; 1957b4f1e6bSMatan Azrad for (off = len; off && path[off - 1] != '/'; --off) 1967b4f1e6bSMatan Azrad ; 1977b4f1e6bSMatan Azrad for (i = 0; bad[i]; ++i) 1987b4f1e6bSMatan Azrad if (!strncmp(path + off, bad[i], (int)(len - off))) 1997b4f1e6bSMatan Azrad goto error; 2007b4f1e6bSMatan Azrad i = snprintf(buf, size, "%.*s-glue", (int)len, path); 2017b4f1e6bSMatan Azrad if (i == -1 || (size_t)i >= size) 2027b4f1e6bSMatan Azrad goto error; 2037b4f1e6bSMatan Azrad return buf; 2047b4f1e6bSMatan Azrad error: 2057b4f1e6bSMatan Azrad RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of" 2067b4f1e6bSMatan Azrad " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please" 2077b4f1e6bSMatan Azrad " re-configure DPDK"); 2087b4f1e6bSMatan Azrad return NULL; 2097b4f1e6bSMatan Azrad } 2107b4f1e6bSMatan Azrad 21183c99c36SThomas Monjalon static int 21283c99c36SThomas Monjalon mlx5_glue_dlopen(void) 2137b4f1e6bSMatan Azrad { 2147b4f1e6bSMatan Azrad char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")]; 215a6e7cd81STonghao Zhang void *handle = NULL; 216a6e7cd81STonghao Zhang 2177b4f1e6bSMatan Azrad const char *path[] = { 2187b4f1e6bSMatan Azrad /* 2197b4f1e6bSMatan Azrad * A basic security check is necessary before trusting 2207b4f1e6bSMatan Azrad * MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH. 2217b4f1e6bSMatan Azrad */ 2227b4f1e6bSMatan Azrad (geteuid() == getuid() && getegid() == getgid() ? 2237b4f1e6bSMatan Azrad getenv("MLX5_GLUE_PATH") : NULL), 2247b4f1e6bSMatan Azrad /* 2257b4f1e6bSMatan Azrad * When RTE_EAL_PMD_PATH is set, use its glue-suffixed 2267b4f1e6bSMatan Azrad * variant, otherwise let dlopen() look up libraries on its 2277b4f1e6bSMatan Azrad * own. 2287b4f1e6bSMatan Azrad */ 2297b4f1e6bSMatan Azrad (*RTE_EAL_PMD_PATH ? 2307b4f1e6bSMatan Azrad mlx5_glue_path(glue_path, sizeof(glue_path)) : ""), 2317b4f1e6bSMatan Azrad }; 2327b4f1e6bSMatan Azrad unsigned int i = 0; 2337b4f1e6bSMatan Azrad void **sym; 2347b4f1e6bSMatan Azrad const char *dlmsg; 2357b4f1e6bSMatan Azrad 2367b4f1e6bSMatan Azrad while (!handle && i != RTE_DIM(path)) { 2377b4f1e6bSMatan Azrad const char *end; 2387b4f1e6bSMatan Azrad size_t len; 2397b4f1e6bSMatan Azrad int ret; 2407b4f1e6bSMatan Azrad 2417b4f1e6bSMatan Azrad if (!path[i]) { 2427b4f1e6bSMatan Azrad ++i; 2437b4f1e6bSMatan Azrad continue; 2447b4f1e6bSMatan Azrad } 2457b4f1e6bSMatan Azrad end = strpbrk(path[i], ":;"); 2467b4f1e6bSMatan Azrad if (!end) 2477b4f1e6bSMatan Azrad end = path[i] + strlen(path[i]); 2487b4f1e6bSMatan Azrad len = end - path[i]; 2497b4f1e6bSMatan Azrad ret = 0; 2507b4f1e6bSMatan Azrad do { 2517b4f1e6bSMatan Azrad char name[ret + 1]; 2527b4f1e6bSMatan Azrad 2537b4f1e6bSMatan Azrad ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE, 2547b4f1e6bSMatan Azrad (int)len, path[i], 2557b4f1e6bSMatan Azrad (!len || *(end - 1) == '/') ? "" : "/"); 2567b4f1e6bSMatan Azrad if (ret == -1) 2577b4f1e6bSMatan Azrad break; 2587b4f1e6bSMatan Azrad if (sizeof(name) != (size_t)ret + 1) 2597b4f1e6bSMatan Azrad continue; 2607b4f1e6bSMatan Azrad DRV_LOG(DEBUG, "Looking for rdma-core glue as " 2617b4f1e6bSMatan Azrad "\"%s\"", name); 2627b4f1e6bSMatan Azrad handle = dlopen(name, RTLD_LAZY); 2637b4f1e6bSMatan Azrad break; 2647b4f1e6bSMatan Azrad } while (1); 2657b4f1e6bSMatan Azrad path[i] = end + 1; 2667b4f1e6bSMatan Azrad if (!*end) 2677b4f1e6bSMatan Azrad ++i; 2687b4f1e6bSMatan Azrad } 2697b4f1e6bSMatan Azrad if (!handle) { 2707b4f1e6bSMatan Azrad rte_errno = EINVAL; 2717b4f1e6bSMatan Azrad dlmsg = dlerror(); 2727b4f1e6bSMatan Azrad if (dlmsg) 2737b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot load glue library: %s", dlmsg); 2747b4f1e6bSMatan Azrad goto glue_error; 2757b4f1e6bSMatan Azrad } 2767b4f1e6bSMatan Azrad sym = dlsym(handle, "mlx5_glue"); 2777b4f1e6bSMatan Azrad if (!sym || !*sym) { 2787b4f1e6bSMatan Azrad rte_errno = EINVAL; 2797b4f1e6bSMatan Azrad dlmsg = dlerror(); 2807b4f1e6bSMatan Azrad if (dlmsg) 2817b4f1e6bSMatan Azrad DRV_LOG(ERR, "Cannot resolve glue symbol: %s", dlmsg); 2827b4f1e6bSMatan Azrad goto glue_error; 2837b4f1e6bSMatan Azrad } 2847b4f1e6bSMatan Azrad mlx5_glue = *sym; 28583c99c36SThomas Monjalon return 0; 28683c99c36SThomas Monjalon 28783c99c36SThomas Monjalon glue_error: 28883c99c36SThomas Monjalon if (handle) 28983c99c36SThomas Monjalon dlclose(handle); 29083c99c36SThomas Monjalon return -1; 29183c99c36SThomas Monjalon } 29283c99c36SThomas Monjalon 29383c99c36SThomas Monjalon #endif 29483c99c36SThomas Monjalon 29583c99c36SThomas Monjalon RTE_INIT_PRIO(mlx5_log_init, LOG) 29683c99c36SThomas Monjalon { 29783c99c36SThomas Monjalon mlx5_common_logtype = rte_log_register("pmd.common.mlx5"); 29883c99c36SThomas Monjalon if (mlx5_common_logtype >= 0) 29983c99c36SThomas Monjalon rte_log_set_level(mlx5_common_logtype, RTE_LOG_NOTICE); 30083c99c36SThomas Monjalon } 30183c99c36SThomas Monjalon 30283c99c36SThomas Monjalon /** 30383c99c36SThomas Monjalon * Initialization routine for run-time dependency on rdma-core. 30483c99c36SThomas Monjalon */ 30583c99c36SThomas Monjalon RTE_INIT_PRIO(mlx5_glue_init, CLASS) 30683c99c36SThomas Monjalon { 30783c99c36SThomas Monjalon /* 30883c99c36SThomas Monjalon * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use 30983c99c36SThomas Monjalon * huge pages. Calling ibv_fork_init() during init allows 31083c99c36SThomas Monjalon * applications to use fork() safely for purposes other than 31183c99c36SThomas Monjalon * using this PMD, which is not supported in forked processes. 31283c99c36SThomas Monjalon */ 31383c99c36SThomas Monjalon setenv("RDMAV_HUGEPAGES_SAFE", "1", 1); 31483c99c36SThomas Monjalon /* Match the size of Rx completion entry to the size of a cacheline. */ 31583c99c36SThomas Monjalon if (RTE_CACHE_LINE_SIZE == 128) 31683c99c36SThomas Monjalon setenv("MLX5_CQE_SIZE", "128", 0); 31783c99c36SThomas Monjalon /* 31883c99c36SThomas Monjalon * MLX5_DEVICE_FATAL_CLEANUP tells ibv_destroy functions to 31983c99c36SThomas Monjalon * cleanup all the Verbs resources even when the device was removed. 32083c99c36SThomas Monjalon */ 32183c99c36SThomas Monjalon setenv("MLX5_DEVICE_FATAL_CLEANUP", "1", 1); 32283c99c36SThomas Monjalon 32383c99c36SThomas Monjalon #ifdef MLX5_GLUE 32483c99c36SThomas Monjalon if (mlx5_glue_dlopen() != 0) 32583c99c36SThomas Monjalon goto glue_error; 32683c99c36SThomas Monjalon #endif 32783c99c36SThomas Monjalon 3280afacb04SAlexander Kozyrev #ifdef RTE_LIBRTE_MLX5_DEBUG 3297b4f1e6bSMatan Azrad /* Glue structure must not contain any NULL pointers. */ 3307b4f1e6bSMatan Azrad { 3317b4f1e6bSMatan Azrad unsigned int i; 3327b4f1e6bSMatan Azrad 3337b4f1e6bSMatan Azrad for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i) 3348e46d4e1SAlexander Kozyrev MLX5_ASSERT(((const void *const *)mlx5_glue)[i]); 3357b4f1e6bSMatan Azrad } 3367b4f1e6bSMatan Azrad #endif 3377b4f1e6bSMatan Azrad if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) { 3387b4f1e6bSMatan Azrad rte_errno = EINVAL; 3397b4f1e6bSMatan Azrad DRV_LOG(ERR, "rdma-core glue \"%s\" mismatch: \"%s\" is " 3407b4f1e6bSMatan Azrad "required", mlx5_glue->version, MLX5_GLUE_VERSION); 3417b4f1e6bSMatan Azrad goto glue_error; 3427b4f1e6bSMatan Azrad } 3437b4f1e6bSMatan Azrad mlx5_glue->fork_init(); 3447b4f1e6bSMatan Azrad return; 34583c99c36SThomas Monjalon 3467b4f1e6bSMatan Azrad glue_error: 3477b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot initialize MLX5 common due to missing" 3487b4f1e6bSMatan Azrad " run-time dependency on rdma-core libraries (libibverbs," 3497b4f1e6bSMatan Azrad " libmlx5)"); 3507b4f1e6bSMatan Azrad mlx5_glue = NULL; 3517b4f1e6bSMatan Azrad return; 3527b4f1e6bSMatan Azrad } 353