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 72d768f324SMatan Azrad static int 73d768f324SMatan Azrad mlx5_class_check_handler(__rte_unused const char *key, const char *value, 74d768f324SMatan Azrad void *opaque) 75d768f324SMatan Azrad { 76d768f324SMatan Azrad enum mlx5_class *ret = opaque; 77d768f324SMatan Azrad 78d768f324SMatan Azrad if (strcmp(value, "vdpa") == 0) { 79d768f324SMatan Azrad *ret = MLX5_CLASS_VDPA; 80d768f324SMatan Azrad } else if (strcmp(value, "net") == 0) { 81d768f324SMatan Azrad *ret = MLX5_CLASS_NET; 82d768f324SMatan Azrad } else { 83d768f324SMatan Azrad DRV_LOG(ERR, "Invalid mlx5 class %s. Maybe typo in device" 84d768f324SMatan Azrad " class argument setting?", value); 85d768f324SMatan Azrad *ret = MLX5_CLASS_INVALID; 86d768f324SMatan Azrad } 87d768f324SMatan Azrad return 0; 88d768f324SMatan Azrad } 89d768f324SMatan Azrad 90d768f324SMatan Azrad enum mlx5_class 91d768f324SMatan Azrad mlx5_class_get(struct rte_devargs *devargs) 92d768f324SMatan Azrad { 93d768f324SMatan Azrad struct rte_kvargs *kvlist; 94d768f324SMatan Azrad const char *key = MLX5_CLASS_ARG_NAME; 95d768f324SMatan Azrad enum mlx5_class ret = MLX5_CLASS_NET; 96d768f324SMatan Azrad 97d768f324SMatan Azrad if (devargs == NULL) 98d768f324SMatan Azrad return ret; 99d768f324SMatan Azrad kvlist = rte_kvargs_parse(devargs->args, NULL); 100d768f324SMatan Azrad if (kvlist == NULL) 101d768f324SMatan Azrad return ret; 102d768f324SMatan Azrad if (rte_kvargs_count(kvlist, key)) 103d768f324SMatan Azrad rte_kvargs_process(kvlist, key, mlx5_class_check_handler, &ret); 104d768f324SMatan Azrad rte_kvargs_free(kvlist); 105d768f324SMatan Azrad return ret; 106d768f324SMatan Azrad } 107d768f324SMatan Azrad 108654810b5SMatan Azrad /** 109654810b5SMatan Azrad * Extract port name, as a number, from sysfs or netlink information. 110654810b5SMatan Azrad * 111654810b5SMatan Azrad * @param[in] port_name_in 112654810b5SMatan Azrad * String representing the port name. 113654810b5SMatan Azrad * @param[out] port_info_out 114654810b5SMatan Azrad * Port information, including port name as a number and port name 115654810b5SMatan Azrad * type if recognized 116654810b5SMatan Azrad * 117654810b5SMatan Azrad * @return 118654810b5SMatan Azrad * port_name field set according to recognized name format. 119654810b5SMatan Azrad */ 120654810b5SMatan Azrad void 121654810b5SMatan Azrad mlx5_translate_port_name(const char *port_name_in, 122654810b5SMatan Azrad struct mlx5_switch_info *port_info_out) 123654810b5SMatan Azrad { 124654810b5SMatan Azrad char pf_c1, pf_c2, vf_c1, vf_c2; 125654810b5SMatan Azrad char *end; 126654810b5SMatan Azrad int sc_items; 127654810b5SMatan Azrad 128654810b5SMatan Azrad /* 129654810b5SMatan Azrad * Check for port-name as a string of the form pf0vf0 130654810b5SMatan Azrad * (support kernel ver >= 5.0 or OFED ver >= 4.6). 131654810b5SMatan Azrad */ 132654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%c%d%c%c%d", 133654810b5SMatan Azrad &pf_c1, &pf_c2, &port_info_out->pf_num, 134654810b5SMatan Azrad &vf_c1, &vf_c2, &port_info_out->port_name); 135654810b5SMatan Azrad if (sc_items == 6 && 136654810b5SMatan Azrad pf_c1 == 'p' && pf_c2 == 'f' && 137654810b5SMatan Azrad vf_c1 == 'v' && vf_c2 == 'f') { 138654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_PFVF; 139654810b5SMatan Azrad return; 140654810b5SMatan Azrad } 141654810b5SMatan Azrad /* 142654810b5SMatan Azrad * Check for port-name as a string of the form p0 143654810b5SMatan Azrad * (support kernel ver >= 5.0, or OFED ver >= 4.6). 144654810b5SMatan Azrad */ 145654810b5SMatan Azrad sc_items = sscanf(port_name_in, "%c%d", 146654810b5SMatan Azrad &pf_c1, &port_info_out->port_name); 147654810b5SMatan Azrad if (sc_items == 2 && pf_c1 == 'p') { 148654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UPLINK; 149654810b5SMatan Azrad return; 150654810b5SMatan Azrad } 151654810b5SMatan Azrad /* Check for port-name as a number (support kernel ver < 5.0 */ 152654810b5SMatan Azrad errno = 0; 153654810b5SMatan Azrad port_info_out->port_name = strtol(port_name_in, &end, 0); 154654810b5SMatan Azrad if (!errno && 155654810b5SMatan Azrad (size_t)(end - port_name_in) == strlen(port_name_in)) { 156654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_LEGACY; 157654810b5SMatan Azrad return; 158654810b5SMatan Azrad } 159654810b5SMatan Azrad port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN; 160654810b5SMatan Azrad return; 161654810b5SMatan Azrad } 162654810b5SMatan Azrad 1637b4f1e6bSMatan Azrad #ifdef RTE_IBVERBS_LINK_DLOPEN 1647b4f1e6bSMatan Azrad 1657b4f1e6bSMatan Azrad /** 1667b4f1e6bSMatan Azrad * Suffix RTE_EAL_PMD_PATH with "-glue". 1677b4f1e6bSMatan Azrad * 1687b4f1e6bSMatan Azrad * This function performs a sanity check on RTE_EAL_PMD_PATH before 1697b4f1e6bSMatan Azrad * suffixing its last component. 1707b4f1e6bSMatan Azrad * 1717b4f1e6bSMatan Azrad * @param buf[out] 1727b4f1e6bSMatan Azrad * Output buffer, should be large enough otherwise NULL is returned. 1737b4f1e6bSMatan Azrad * @param size 1747b4f1e6bSMatan Azrad * Size of @p out. 1757b4f1e6bSMatan Azrad * 1767b4f1e6bSMatan Azrad * @return 1777b4f1e6bSMatan Azrad * Pointer to @p buf or @p NULL in case suffix cannot be appended. 1787b4f1e6bSMatan Azrad */ 1797b4f1e6bSMatan Azrad static char * 1807b4f1e6bSMatan Azrad mlx5_glue_path(char *buf, size_t size) 1817b4f1e6bSMatan Azrad { 1827b4f1e6bSMatan Azrad static const char *const bad[] = { "/", ".", "..", NULL }; 1837b4f1e6bSMatan Azrad const char *path = RTE_EAL_PMD_PATH; 1847b4f1e6bSMatan Azrad size_t len = strlen(path); 1857b4f1e6bSMatan Azrad size_t off; 1867b4f1e6bSMatan Azrad int i; 1877b4f1e6bSMatan Azrad 1887b4f1e6bSMatan Azrad while (len && path[len - 1] == '/') 1897b4f1e6bSMatan Azrad --len; 1907b4f1e6bSMatan Azrad for (off = len; off && path[off - 1] != '/'; --off) 1917b4f1e6bSMatan Azrad ; 1927b4f1e6bSMatan Azrad for (i = 0; bad[i]; ++i) 1937b4f1e6bSMatan Azrad if (!strncmp(path + off, bad[i], (int)(len - off))) 1947b4f1e6bSMatan Azrad goto error; 1957b4f1e6bSMatan Azrad i = snprintf(buf, size, "%.*s-glue", (int)len, path); 1967b4f1e6bSMatan Azrad if (i == -1 || (size_t)i >= size) 1977b4f1e6bSMatan Azrad goto error; 1987b4f1e6bSMatan Azrad return buf; 1997b4f1e6bSMatan Azrad error: 2007b4f1e6bSMatan Azrad RTE_LOG(ERR, PMD, "unable to append \"-glue\" to last component of" 2017b4f1e6bSMatan Azrad " RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"), please" 2027b4f1e6bSMatan Azrad " re-configure DPDK"); 2037b4f1e6bSMatan Azrad return NULL; 2047b4f1e6bSMatan Azrad } 2057b4f1e6bSMatan Azrad #endif 2067b4f1e6bSMatan Azrad 2077b4f1e6bSMatan Azrad /** 2087b4f1e6bSMatan Azrad * Initialization routine for run-time dependency on rdma-core. 2097b4f1e6bSMatan Azrad */ 2107b4f1e6bSMatan Azrad RTE_INIT_PRIO(mlx5_glue_init, CLASS) 2117b4f1e6bSMatan Azrad { 2127b4f1e6bSMatan Azrad void *handle = NULL; 2137b4f1e6bSMatan Azrad 2147b4f1e6bSMatan Azrad /* Initialize common log type. */ 2157b4f1e6bSMatan Azrad mlx5_common_logtype = rte_log_register("pmd.common.mlx5"); 2167b4f1e6bSMatan Azrad if (mlx5_common_logtype >= 0) 2177b4f1e6bSMatan Azrad rte_log_set_level(mlx5_common_logtype, RTE_LOG_NOTICE); 2187b4f1e6bSMatan Azrad /* 2197b4f1e6bSMatan Azrad * RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use 2207b4f1e6bSMatan Azrad * huge pages. Calling ibv_fork_init() during init allows 2217b4f1e6bSMatan Azrad * applications to use fork() safely for purposes other than 2227b4f1e6bSMatan Azrad * using this PMD, which is not supported in forked processes. 2237b4f1e6bSMatan Azrad */ 2247b4f1e6bSMatan Azrad setenv("RDMAV_HUGEPAGES_SAFE", "1", 1); 2257b4f1e6bSMatan Azrad /* Match the size of Rx completion entry to the size of a cacheline. */ 2267b4f1e6bSMatan Azrad if (RTE_CACHE_LINE_SIZE == 128) 2277b4f1e6bSMatan Azrad setenv("MLX5_CQE_SIZE", "128", 0); 2287b4f1e6bSMatan Azrad /* 2297b4f1e6bSMatan Azrad * MLX5_DEVICE_FATAL_CLEANUP tells ibv_destroy functions to 2307b4f1e6bSMatan Azrad * cleanup all the Verbs resources even when the device was removed. 2317b4f1e6bSMatan Azrad */ 2327b4f1e6bSMatan Azrad setenv("MLX5_DEVICE_FATAL_CLEANUP", "1", 1); 2337b4f1e6bSMatan Azrad /* The glue initialization was done earlier by mlx5 common library. */ 2347b4f1e6bSMatan Azrad #ifdef RTE_IBVERBS_LINK_DLOPEN 2357b4f1e6bSMatan Azrad char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")]; 2367b4f1e6bSMatan Azrad const char *path[] = { 2377b4f1e6bSMatan Azrad /* 2387b4f1e6bSMatan Azrad * A basic security check is necessary before trusting 2397b4f1e6bSMatan Azrad * MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH. 2407b4f1e6bSMatan Azrad */ 2417b4f1e6bSMatan Azrad (geteuid() == getuid() && getegid() == getgid() ? 2427b4f1e6bSMatan Azrad getenv("MLX5_GLUE_PATH") : NULL), 2437b4f1e6bSMatan Azrad /* 2447b4f1e6bSMatan Azrad * When RTE_EAL_PMD_PATH is set, use its glue-suffixed 2457b4f1e6bSMatan Azrad * variant, otherwise let dlopen() look up libraries on its 2467b4f1e6bSMatan Azrad * own. 2477b4f1e6bSMatan Azrad */ 2487b4f1e6bSMatan Azrad (*RTE_EAL_PMD_PATH ? 2497b4f1e6bSMatan Azrad mlx5_glue_path(glue_path, sizeof(glue_path)) : ""), 2507b4f1e6bSMatan Azrad }; 2517b4f1e6bSMatan Azrad unsigned int i = 0; 2527b4f1e6bSMatan Azrad void **sym; 2537b4f1e6bSMatan Azrad const char *dlmsg; 2547b4f1e6bSMatan Azrad 2557b4f1e6bSMatan Azrad while (!handle && i != RTE_DIM(path)) { 2567b4f1e6bSMatan Azrad const char *end; 2577b4f1e6bSMatan Azrad size_t len; 2587b4f1e6bSMatan Azrad int ret; 2597b4f1e6bSMatan Azrad 2607b4f1e6bSMatan Azrad if (!path[i]) { 2617b4f1e6bSMatan Azrad ++i; 2627b4f1e6bSMatan Azrad continue; 2637b4f1e6bSMatan Azrad } 2647b4f1e6bSMatan Azrad end = strpbrk(path[i], ":;"); 2657b4f1e6bSMatan Azrad if (!end) 2667b4f1e6bSMatan Azrad end = path[i] + strlen(path[i]); 2677b4f1e6bSMatan Azrad len = end - path[i]; 2687b4f1e6bSMatan Azrad ret = 0; 2697b4f1e6bSMatan Azrad do { 2707b4f1e6bSMatan Azrad char name[ret + 1]; 2717b4f1e6bSMatan Azrad 2727b4f1e6bSMatan Azrad ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE, 2737b4f1e6bSMatan Azrad (int)len, path[i], 2747b4f1e6bSMatan Azrad (!len || *(end - 1) == '/') ? "" : "/"); 2757b4f1e6bSMatan Azrad if (ret == -1) 2767b4f1e6bSMatan Azrad break; 2777b4f1e6bSMatan Azrad if (sizeof(name) != (size_t)ret + 1) 2787b4f1e6bSMatan Azrad continue; 2797b4f1e6bSMatan Azrad DRV_LOG(DEBUG, "Looking for rdma-core glue as " 2807b4f1e6bSMatan Azrad "\"%s\"", name); 2817b4f1e6bSMatan Azrad handle = dlopen(name, RTLD_LAZY); 2827b4f1e6bSMatan Azrad break; 2837b4f1e6bSMatan Azrad } while (1); 2847b4f1e6bSMatan Azrad path[i] = end + 1; 2857b4f1e6bSMatan Azrad if (!*end) 2867b4f1e6bSMatan Azrad ++i; 2877b4f1e6bSMatan Azrad } 2887b4f1e6bSMatan Azrad if (!handle) { 2897b4f1e6bSMatan Azrad rte_errno = EINVAL; 2907b4f1e6bSMatan Azrad dlmsg = dlerror(); 2917b4f1e6bSMatan Azrad if (dlmsg) 2927b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot load glue library: %s", dlmsg); 2937b4f1e6bSMatan Azrad goto glue_error; 2947b4f1e6bSMatan Azrad } 2957b4f1e6bSMatan Azrad sym = dlsym(handle, "mlx5_glue"); 2967b4f1e6bSMatan Azrad if (!sym || !*sym) { 2977b4f1e6bSMatan Azrad rte_errno = EINVAL; 2987b4f1e6bSMatan Azrad dlmsg = dlerror(); 2997b4f1e6bSMatan Azrad if (dlmsg) 3007b4f1e6bSMatan Azrad DRV_LOG(ERR, "Cannot resolve glue symbol: %s", dlmsg); 3017b4f1e6bSMatan Azrad goto glue_error; 3027b4f1e6bSMatan Azrad } 3037b4f1e6bSMatan Azrad mlx5_glue = *sym; 3047b4f1e6bSMatan Azrad #endif /* RTE_IBVERBS_LINK_DLOPEN */ 305*0afacb04SAlexander Kozyrev #ifdef RTE_LIBRTE_MLX5_DEBUG 3067b4f1e6bSMatan Azrad /* Glue structure must not contain any NULL pointers. */ 3077b4f1e6bSMatan Azrad { 3087b4f1e6bSMatan Azrad unsigned int i; 3097b4f1e6bSMatan Azrad 3107b4f1e6bSMatan Azrad for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i) 3117b4f1e6bSMatan Azrad assert(((const void *const *)mlx5_glue)[i]); 3127b4f1e6bSMatan Azrad } 3137b4f1e6bSMatan Azrad #endif 3147b4f1e6bSMatan Azrad if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) { 3157b4f1e6bSMatan Azrad rte_errno = EINVAL; 3167b4f1e6bSMatan Azrad DRV_LOG(ERR, "rdma-core glue \"%s\" mismatch: \"%s\" is " 3177b4f1e6bSMatan Azrad "required", mlx5_glue->version, MLX5_GLUE_VERSION); 3187b4f1e6bSMatan Azrad goto glue_error; 3197b4f1e6bSMatan Azrad } 3207b4f1e6bSMatan Azrad mlx5_glue->fork_init(); 3217b4f1e6bSMatan Azrad return; 3227b4f1e6bSMatan Azrad glue_error: 3237b4f1e6bSMatan Azrad if (handle) 3247b4f1e6bSMatan Azrad dlclose(handle); 3257b4f1e6bSMatan Azrad DRV_LOG(WARNING, "Cannot initialize MLX5 common due to missing" 3267b4f1e6bSMatan Azrad " run-time dependency on rdma-core libraries (libibverbs," 3277b4f1e6bSMatan Azrad " libmlx5)"); 3287b4f1e6bSMatan Azrad mlx5_glue = NULL; 3297b4f1e6bSMatan Azrad return; 3307b4f1e6bSMatan Azrad } 331