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> 87b4f1e6bSMatan Azrad 97b4f1e6bSMatan Azrad #include <rte_errno.h> 10262c7ad0SOri Kam #include <rte_mempool.h> 11ad435d32SXueming Li #include <rte_class.h> 12ad435d32SXueming Li #include <rte_malloc.h> 137b4f1e6bSMatan Azrad 147b4f1e6bSMatan Azrad #include "mlx5_common.h" 15262c7ad0SOri Kam #include "mlx5_common_os.h" 1625245d5dSShiri Kuzin #include "mlx5_common_log.h" 17ad435d32SXueming Li #include "mlx5_common_private.h" 187b4f1e6bSMatan Azrad 194c204fe5SShiri Kuzin uint8_t haswell_broadwell_cpu; 204c204fe5SShiri Kuzin 214c204fe5SShiri Kuzin /* In case this is an x86_64 intel processor to check if 224c204fe5SShiri Kuzin * we should use relaxed ordering. 234c204fe5SShiri Kuzin */ 244c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 254c204fe5SShiri Kuzin /** 264c204fe5SShiri Kuzin * This function returns processor identification and feature information 274c204fe5SShiri Kuzin * into the registers. 284c204fe5SShiri Kuzin * 294c204fe5SShiri Kuzin * @param eax, ebx, ecx, edx 304c204fe5SShiri Kuzin * Pointers to the registers that will hold cpu information. 314c204fe5SShiri Kuzin * @param level 324c204fe5SShiri Kuzin * The main category of information returned. 334c204fe5SShiri Kuzin */ 344c204fe5SShiri Kuzin static inline void mlx5_cpu_id(unsigned int level, 354c204fe5SShiri Kuzin unsigned int *eax, unsigned int *ebx, 364c204fe5SShiri Kuzin unsigned int *ecx, unsigned int *edx) 374c204fe5SShiri Kuzin { 384c204fe5SShiri Kuzin __asm__("cpuid\n\t" 394c204fe5SShiri Kuzin : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 404c204fe5SShiri Kuzin : "0" (level)); 414c204fe5SShiri Kuzin } 424c204fe5SShiri Kuzin #endif 434c204fe5SShiri Kuzin 44eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE) 4583c99c36SThomas Monjalon 46ad435d32SXueming Li /* Head of list of drivers. */ 47ad435d32SXueming Li static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list = 48ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(drivers_list); 49ad435d32SXueming Li 50ad435d32SXueming Li /* Head of devices. */ 51ad435d32SXueming Li static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list = 52ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(devices_list); 53dc26c9c2SMichael Baum static pthread_mutex_t devices_list_lock; 54ad435d32SXueming Li 55ad435d32SXueming Li static const struct { 56ad435d32SXueming Li const char *name; 57ad435d32SXueming Li unsigned int drv_class; 58ad435d32SXueming Li } mlx5_classes[] = { 59ad435d32SXueming Li { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA }, 60ad435d32SXueming Li { .name = "eth", .drv_class = MLX5_CLASS_ETH }, 61ad435d32SXueming Li /* Keep class "net" for backward compatibility. */ 62ad435d32SXueming Li { .name = "net", .drv_class = MLX5_CLASS_ETH }, 63ad435d32SXueming Li { .name = "regex", .drv_class = MLX5_CLASS_REGEX }, 64ad435d32SXueming Li { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS }, 65ad435d32SXueming Li { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO }, 66ad435d32SXueming Li }; 67ad435d32SXueming Li 68ad435d32SXueming Li static int 69ad435d32SXueming Li class_name_to_value(const char *class_name) 70ad435d32SXueming Li { 71ad435d32SXueming Li unsigned int i; 72ad435d32SXueming Li 73ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 74ad435d32SXueming Li if (strcmp(class_name, mlx5_classes[i].name) == 0) 75ad435d32SXueming Li return mlx5_classes[i].drv_class; 76ad435d32SXueming Li } 77ad435d32SXueming Li return -EINVAL; 78ad435d32SXueming Li } 79ad435d32SXueming Li 80ad435d32SXueming Li static struct mlx5_class_driver * 81ad435d32SXueming Li driver_get(uint32_t class) 82ad435d32SXueming Li { 83ad435d32SXueming Li struct mlx5_class_driver *driver; 84ad435d32SXueming Li 85ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 86ad435d32SXueming Li if ((uint32_t)driver->drv_class == class) 87ad435d32SXueming Li return driver; 88ad435d32SXueming Li } 89ad435d32SXueming Li return NULL; 90ad435d32SXueming Li } 91ad435d32SXueming Li 92ad435d32SXueming Li static int 93ad435d32SXueming Li devargs_class_handler(__rte_unused const char *key, 94ad435d32SXueming Li const char *class_names, void *opaque) 95ad435d32SXueming Li { 96ad435d32SXueming Li int *ret = opaque; 97ad435d32SXueming Li int class_val; 98ad435d32SXueming Li char *scratch; 99ad435d32SXueming Li char *found; 100ad435d32SXueming Li char *refstr = NULL; 101ad435d32SXueming Li 102ad435d32SXueming Li *ret = 0; 103ad435d32SXueming Li scratch = strdup(class_names); 104ad435d32SXueming Li if (scratch == NULL) { 105ad435d32SXueming Li *ret = -ENOMEM; 106ad435d32SXueming Li return *ret; 107ad435d32SXueming Li } 108ad435d32SXueming Li found = strtok_r(scratch, ":", &refstr); 109ad435d32SXueming Li if (found == NULL) 110ad435d32SXueming Li /* Empty string. */ 111ad435d32SXueming Li goto err; 112ad435d32SXueming Li do { 113ad435d32SXueming Li /* Extract each individual class name. Multiple 114ad435d32SXueming Li * classes can be supplied as class=net:regex:foo:bar. 115ad435d32SXueming Li */ 116ad435d32SXueming Li class_val = class_name_to_value(found); 117ad435d32SXueming Li /* Check if its a valid class. */ 118ad435d32SXueming Li if (class_val < 0) { 119ad435d32SXueming Li *ret = -EINVAL; 120ad435d32SXueming Li goto err; 121ad435d32SXueming Li } 122ad435d32SXueming Li *ret |= class_val; 123ad435d32SXueming Li found = strtok_r(NULL, ":", &refstr); 124ad435d32SXueming Li } while (found != NULL); 125ad435d32SXueming Li err: 126ad435d32SXueming Li free(scratch); 127ad435d32SXueming Li if (*ret < 0) 128ad435d32SXueming Li DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names); 129ad435d32SXueming Li return *ret; 130ad435d32SXueming Li } 131ad435d32SXueming Li 132ad435d32SXueming Li static int 133ad435d32SXueming Li parse_class_options(const struct rte_devargs *devargs) 134ad435d32SXueming Li { 135ad435d32SXueming Li struct rte_kvargs *kvlist; 136ad435d32SXueming Li int ret = 0; 137ad435d32SXueming Li 138ad435d32SXueming Li if (devargs == NULL) 139ad435d32SXueming Li return 0; 140ad435d32SXueming Li if (devargs->cls != NULL && devargs->cls->name != NULL) 141ad435d32SXueming Li /* Global syntax, only one class type. */ 142ad435d32SXueming Li return class_name_to_value(devargs->cls->name); 143ad435d32SXueming Li /* Legacy devargs support multiple classes. */ 144ad435d32SXueming Li kvlist = rte_kvargs_parse(devargs->args, NULL); 145ad435d32SXueming Li if (kvlist == NULL) 146ad435d32SXueming Li return 0; 147ad435d32SXueming Li rte_kvargs_process(kvlist, RTE_DEVARGS_KEY_CLASS, 148ad435d32SXueming Li devargs_class_handler, &ret); 149ad435d32SXueming Li rte_kvargs_free(kvlist); 150ad435d32SXueming Li return ret; 151ad435d32SXueming Li } 152ad435d32SXueming Li 153ad435d32SXueming Li static const unsigned int mlx5_class_invalid_combinations[] = { 154ad435d32SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_VDPA, 155ad435d32SXueming Li /* New class combination should be added here. */ 156ad435d32SXueming Li }; 157ad435d32SXueming Li 158ad435d32SXueming Li static int 159ad435d32SXueming Li is_valid_class_combination(uint32_t user_classes) 160ad435d32SXueming Li { 161ad435d32SXueming Li unsigned int i; 162ad435d32SXueming Li 163ad435d32SXueming Li /* Verify if user specified unsupported combination. */ 164ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) { 165ad435d32SXueming Li if ((mlx5_class_invalid_combinations[i] & user_classes) == 166ad435d32SXueming Li mlx5_class_invalid_combinations[i]) 167ad435d32SXueming Li return -EINVAL; 168ad435d32SXueming Li } 169ad435d32SXueming Li /* Not found any invalid class combination. */ 170ad435d32SXueming Li return 0; 171ad435d32SXueming Li } 172ad435d32SXueming Li 173ad435d32SXueming Li static bool 174ad435d32SXueming Li device_class_enabled(const struct mlx5_common_device *device, uint32_t class) 175ad435d32SXueming Li { 176ad435d32SXueming Li return (device->classes_loaded & class) > 0; 177ad435d32SXueming Li } 178ad435d32SXueming Li 179ad435d32SXueming Li static bool 180ad435d32SXueming Li mlx5_bus_match(const struct mlx5_class_driver *drv, 181ad435d32SXueming Li const struct rte_device *dev) 182ad435d32SXueming Li { 183ad435d32SXueming Li if (mlx5_dev_is_pci(dev)) 184ad435d32SXueming Li return mlx5_dev_pci_match(drv, dev); 185ad435d32SXueming Li return true; 186ad435d32SXueming Li } 187ad435d32SXueming Li 188ad435d32SXueming Li static struct mlx5_common_device * 189ad435d32SXueming Li to_mlx5_device(const struct rte_device *rte_dev) 190ad435d32SXueming Li { 191ad435d32SXueming Li struct mlx5_common_device *dev; 192ad435d32SXueming Li 193ad435d32SXueming Li TAILQ_FOREACH(dev, &devices_list, next) { 194ad435d32SXueming Li if (rte_dev == dev->dev) 195ad435d32SXueming Li return dev; 196ad435d32SXueming Li } 197ad435d32SXueming Li return NULL; 198ad435d32SXueming Li } 199ad435d32SXueming Li 2004d567938SThomas Monjalon int 2014d567938SThomas Monjalon mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size) 2024d567938SThomas Monjalon { 2034d567938SThomas Monjalon struct rte_pci_addr pci_addr = { 0 }; 2044d567938SThomas Monjalon int ret; 2054d567938SThomas Monjalon 2064d567938SThomas Monjalon if (mlx5_dev_is_pci(dev)) { 2074d567938SThomas Monjalon /* Input might be <BDF>, format PCI address to <DBDF>. */ 2084d567938SThomas Monjalon ret = rte_pci_addr_parse(dev->name, &pci_addr); 2094d567938SThomas Monjalon if (ret != 0) 2104d567938SThomas Monjalon return -ENODEV; 2114d567938SThomas Monjalon rte_pci_device_name(&pci_addr, addr, size); 2124d567938SThomas Monjalon return 0; 2134d567938SThomas Monjalon } 2144d567938SThomas Monjalon #ifdef RTE_EXEC_ENV_LINUX 2154d567938SThomas Monjalon return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev), 2164d567938SThomas Monjalon addr, size); 2174d567938SThomas Monjalon #else 2184d567938SThomas Monjalon rte_errno = ENODEV; 2194d567938SThomas Monjalon return -rte_errno; 2204d567938SThomas Monjalon #endif 2214d567938SThomas Monjalon } 2224d567938SThomas Monjalon 223ad435d32SXueming Li static void 224ad435d32SXueming Li dev_release(struct mlx5_common_device *dev) 225ad435d32SXueming Li { 226dc26c9c2SMichael Baum pthread_mutex_lock(&devices_list_lock); 227ad435d32SXueming Li TAILQ_REMOVE(&devices_list, dev, next); 228dc26c9c2SMichael Baum pthread_mutex_unlock(&devices_list_lock); 229ad435d32SXueming Li rte_free(dev); 230ad435d32SXueming Li } 231ad435d32SXueming Li 232ad435d32SXueming Li static int 233ad435d32SXueming Li drivers_remove(struct mlx5_common_device *dev, uint32_t enabled_classes) 234ad435d32SXueming Li { 235ad435d32SXueming Li struct mlx5_class_driver *driver; 236ad435d32SXueming Li int local_ret = -ENODEV; 237ad435d32SXueming Li unsigned int i = 0; 238ad435d32SXueming Li int ret = 0; 239ad435d32SXueming Li 240ad435d32SXueming Li enabled_classes &= dev->classes_loaded; 241ad435d32SXueming Li while (enabled_classes) { 242ad435d32SXueming Li driver = driver_get(RTE_BIT64(i)); 243ad435d32SXueming Li if (driver != NULL) { 244ad435d32SXueming Li local_ret = driver->remove(dev->dev); 245ad435d32SXueming Li if (local_ret == 0) 246ad435d32SXueming Li dev->classes_loaded &= ~RTE_BIT64(i); 247ad435d32SXueming Li else if (ret == 0) 248ad435d32SXueming Li ret = local_ret; 249ad435d32SXueming Li } 250ad435d32SXueming Li enabled_classes &= ~RTE_BIT64(i); 251ad435d32SXueming Li i++; 252ad435d32SXueming Li } 253ad435d32SXueming Li if (local_ret != 0 && ret == 0) 254ad435d32SXueming Li ret = local_ret; 255ad435d32SXueming Li return ret; 256ad435d32SXueming Li } 257ad435d32SXueming Li 258ad435d32SXueming Li static int 259ad435d32SXueming Li drivers_probe(struct mlx5_common_device *dev, uint32_t user_classes) 260ad435d32SXueming Li { 261ad435d32SXueming Li struct mlx5_class_driver *driver; 262ad435d32SXueming Li uint32_t enabled_classes = 0; 263ad435d32SXueming Li bool already_loaded; 264ad435d32SXueming Li int ret; 265ad435d32SXueming Li 266ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 267ad435d32SXueming Li if ((driver->drv_class & user_classes) == 0) 268ad435d32SXueming Li continue; 269ad435d32SXueming Li if (!mlx5_bus_match(driver, dev->dev)) 270ad435d32SXueming Li continue; 271ad435d32SXueming Li already_loaded = dev->classes_loaded & driver->drv_class; 272ad435d32SXueming Li if (already_loaded && driver->probe_again == 0) { 273ad435d32SXueming Li DRV_LOG(ERR, "Device %s is already probed", 274ad435d32SXueming Li dev->dev->name); 275ad435d32SXueming Li ret = -EEXIST; 276ad435d32SXueming Li goto probe_err; 277ad435d32SXueming Li } 278ad435d32SXueming Li ret = driver->probe(dev->dev); 279ad435d32SXueming Li if (ret < 0) { 280ad435d32SXueming Li DRV_LOG(ERR, "Failed to load driver %s", 281ad435d32SXueming Li driver->name); 282ad435d32SXueming Li goto probe_err; 283ad435d32SXueming Li } 284ad435d32SXueming Li enabled_classes |= driver->drv_class; 285ad435d32SXueming Li } 286ad435d32SXueming Li dev->classes_loaded |= enabled_classes; 287ad435d32SXueming Li return 0; 288ad435d32SXueming Li probe_err: 289ad435d32SXueming Li /* Only unload drivers which are enabled which were enabled 290ad435d32SXueming Li * in this probe instance. 291ad435d32SXueming Li */ 292ad435d32SXueming Li drivers_remove(dev, enabled_classes); 293ad435d32SXueming Li return ret; 294ad435d32SXueming Li } 295ad435d32SXueming Li 296ad435d32SXueming Li int 297ad435d32SXueming Li mlx5_common_dev_probe(struct rte_device *eal_dev) 298ad435d32SXueming Li { 299ad435d32SXueming Li struct mlx5_common_device *dev; 300ad435d32SXueming Li uint32_t classes = 0; 301ad435d32SXueming Li bool new_device = false; 302ad435d32SXueming Li int ret; 303ad435d32SXueming Li 304ad435d32SXueming Li DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name); 305ad435d32SXueming Li ret = parse_class_options(eal_dev->devargs); 306ad435d32SXueming Li if (ret < 0) { 307ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 class type: %s", 308ad435d32SXueming Li eal_dev->devargs->args); 309ad435d32SXueming Li return ret; 310ad435d32SXueming Li } 311ad435d32SXueming Li classes = ret; 312ad435d32SXueming Li if (classes == 0) 313ad435d32SXueming Li /* Default to net class. */ 314ad435d32SXueming Li classes = MLX5_CLASS_ETH; 315ad435d32SXueming Li dev = to_mlx5_device(eal_dev); 316ad435d32SXueming Li if (!dev) { 317ad435d32SXueming Li dev = rte_zmalloc("mlx5_common_device", sizeof(*dev), 0); 318ad435d32SXueming Li if (!dev) 319ad435d32SXueming Li return -ENOMEM; 320ad435d32SXueming Li dev->dev = eal_dev; 321dc26c9c2SMichael Baum pthread_mutex_lock(&devices_list_lock); 322ad435d32SXueming Li TAILQ_INSERT_HEAD(&devices_list, dev, next); 323dc26c9c2SMichael Baum pthread_mutex_unlock(&devices_list_lock); 324ad435d32SXueming Li new_device = true; 325288d7c3fSMichael Baum } 326288d7c3fSMichael Baum /* 327288d7c3fSMichael Baum * Validate combination here. 328288d7c3fSMichael Baum * For new device, the classes_loaded field is 0 and it check only 329288d7c3fSMichael Baum * the classes given as user device arguments. 330288d7c3fSMichael Baum */ 331288d7c3fSMichael Baum ret = is_valid_class_combination(classes | dev->classes_loaded); 332ad435d32SXueming Li if (ret != 0) { 333ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 classes combination."); 334288d7c3fSMichael Baum goto class_err; 335ad435d32SXueming Li } 336ad435d32SXueming Li ret = drivers_probe(dev, classes); 337ad435d32SXueming Li if (ret) 338ad435d32SXueming Li goto class_err; 339ad435d32SXueming Li return 0; 340ad435d32SXueming Li class_err: 341ad435d32SXueming Li if (new_device) 342ad435d32SXueming Li dev_release(dev); 343ad435d32SXueming Li return ret; 344ad435d32SXueming Li } 345ad435d32SXueming Li 346ad435d32SXueming Li int 347ad435d32SXueming Li mlx5_common_dev_remove(struct rte_device *eal_dev) 348ad435d32SXueming Li { 349ad435d32SXueming Li struct mlx5_common_device *dev; 350ad435d32SXueming Li int ret; 351ad435d32SXueming Li 352ad435d32SXueming Li dev = to_mlx5_device(eal_dev); 353ad435d32SXueming Li if (!dev) 354ad435d32SXueming Li return -ENODEV; 355ad435d32SXueming Li /* Matching device found, cleanup and unload drivers. */ 356ad435d32SXueming Li ret = drivers_remove(dev, dev->classes_loaded); 357*dffae63dSMichael Baum if (ret == 0) 358ad435d32SXueming Li dev_release(dev); 359ad435d32SXueming Li return ret; 360ad435d32SXueming Li } 361ad435d32SXueming Li 362ad435d32SXueming Li int 363ad435d32SXueming Li mlx5_common_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, 364ad435d32SXueming Li size_t len) 365ad435d32SXueming Li { 366ad435d32SXueming Li struct mlx5_class_driver *driver = NULL; 367ad435d32SXueming Li struct mlx5_class_driver *temp; 368ad435d32SXueming Li struct mlx5_common_device *mdev; 369ad435d32SXueming Li int ret = -EINVAL; 370ad435d32SXueming Li 371ad435d32SXueming Li mdev = to_mlx5_device(dev); 372ad435d32SXueming Li if (!mdev) 373ad435d32SXueming Li return -ENODEV; 374ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 375ad435d32SXueming Li if (!device_class_enabled(mdev, driver->drv_class) || 376ad435d32SXueming Li driver->dma_map == NULL) 377ad435d32SXueming Li continue; 378ad435d32SXueming Li ret = driver->dma_map(dev, addr, iova, len); 379ad435d32SXueming Li if (ret) 380ad435d32SXueming Li goto map_err; 381ad435d32SXueming Li } 382ad435d32SXueming Li return ret; 383ad435d32SXueming Li map_err: 384ad435d32SXueming Li TAILQ_FOREACH(temp, &drivers_list, next) { 385ad435d32SXueming Li if (temp == driver) 386ad435d32SXueming Li break; 387ad435d32SXueming Li if (device_class_enabled(mdev, temp->drv_class) && 388ad435d32SXueming Li temp->dma_map && temp->dma_unmap) 389ad435d32SXueming Li temp->dma_unmap(dev, addr, iova, len); 390ad435d32SXueming Li } 391ad435d32SXueming Li return ret; 392ad435d32SXueming Li } 393ad435d32SXueming Li 394ad435d32SXueming Li int 395ad435d32SXueming Li mlx5_common_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, 396ad435d32SXueming Li size_t len) 397ad435d32SXueming Li { 398ad435d32SXueming Li struct mlx5_class_driver *driver; 399ad435d32SXueming Li struct mlx5_common_device *mdev; 400ad435d32SXueming Li int local_ret = -EINVAL; 401ad435d32SXueming Li int ret = 0; 402ad435d32SXueming Li 403ad435d32SXueming Li mdev = to_mlx5_device(dev); 404ad435d32SXueming Li if (!mdev) 405ad435d32SXueming Li return -ENODEV; 406ad435d32SXueming Li /* There is no unmap error recovery in current implementation. */ 407ad435d32SXueming Li TAILQ_FOREACH_REVERSE(driver, &drivers_list, mlx5_drivers, next) { 408ad435d32SXueming Li if (!device_class_enabled(mdev, driver->drv_class) || 409ad435d32SXueming Li driver->dma_unmap == NULL) 410ad435d32SXueming Li continue; 411ad435d32SXueming Li local_ret = driver->dma_unmap(dev, addr, iova, len); 412ad435d32SXueming Li if (local_ret && (ret == 0)) 413ad435d32SXueming Li ret = local_ret; 414ad435d32SXueming Li } 415ad435d32SXueming Li if (local_ret) 416ad435d32SXueming Li ret = local_ret; 417ad435d32SXueming Li return ret; 418ad435d32SXueming Li } 419ad435d32SXueming Li 420ad435d32SXueming Li void 421ad435d32SXueming Li mlx5_class_driver_register(struct mlx5_class_driver *driver) 422ad435d32SXueming Li { 423ad435d32SXueming Li mlx5_common_driver_on_register_pci(driver); 424ad435d32SXueming Li TAILQ_INSERT_TAIL(&drivers_list, driver, next); 425ad435d32SXueming Li } 426ad435d32SXueming Li 427ad435d32SXueming Li static void mlx5_common_driver_init(void) 428ad435d32SXueming Li { 429ad435d32SXueming Li mlx5_common_pci_init(); 430777b72a9SXueming Li #ifdef RTE_EXEC_ENV_LINUX 431777b72a9SXueming Li mlx5_common_auxiliary_init(); 432777b72a9SXueming Li #endif 433ad435d32SXueming Li } 434ad435d32SXueming Li 43582088001SParav Pandit static bool mlx5_common_initialized; 43682088001SParav Pandit 43783c99c36SThomas Monjalon /** 43882088001SParav Pandit * One time innitialization routine for run-time dependency on glue library 43982088001SParav Pandit * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 44082088001SParav Pandit * must invoke in its constructor. 44183c99c36SThomas Monjalon */ 44282088001SParav Pandit void 44382088001SParav Pandit mlx5_common_init(void) 44483c99c36SThomas Monjalon { 44582088001SParav Pandit if (mlx5_common_initialized) 44682088001SParav Pandit return; 44782088001SParav Pandit 448dc26c9c2SMichael Baum pthread_mutex_init(&devices_list_lock, NULL); 44979aa4307SOphir Munk mlx5_glue_constructor(); 450ad435d32SXueming Li mlx5_common_driver_init(); 45182088001SParav Pandit mlx5_common_initialized = true; 4527b4f1e6bSMatan Azrad } 4534c204fe5SShiri Kuzin 4544c204fe5SShiri Kuzin /** 4554c204fe5SShiri Kuzin * This function is responsible of initializing the variable 4564c204fe5SShiri Kuzin * haswell_broadwell_cpu by checking if the cpu is intel 4574c204fe5SShiri Kuzin * and reading the data returned from mlx5_cpu_id(). 4584c204fe5SShiri Kuzin * since haswell and broadwell cpus don't have improved performance 4594c204fe5SShiri Kuzin * when using relaxed ordering we want to check the cpu type before 4604c204fe5SShiri Kuzin * before deciding whether to enable RO or not. 4614c204fe5SShiri Kuzin * if the cpu is haswell or broadwell the variable will be set to 1 4624c204fe5SShiri Kuzin * otherwise it will be 0. 4634c204fe5SShiri Kuzin */ 4644c204fe5SShiri Kuzin RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 4654c204fe5SShiri Kuzin { 4664c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 4674c204fe5SShiri Kuzin unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 4684c204fe5SShiri Kuzin unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 4694c204fe5SShiri Kuzin unsigned int i, model, family, brand_id, vendor; 4704c204fe5SShiri Kuzin unsigned int signature_intel_ebx = 0x756e6547; 4714c204fe5SShiri Kuzin unsigned int extended_model; 4724c204fe5SShiri Kuzin unsigned int eax = 0; 4734c204fe5SShiri Kuzin unsigned int ebx = 0; 4744c204fe5SShiri Kuzin unsigned int ecx = 0; 4754c204fe5SShiri Kuzin unsigned int edx = 0; 4764c204fe5SShiri Kuzin int max_level; 4774c204fe5SShiri Kuzin 4784c204fe5SShiri Kuzin mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 4794c204fe5SShiri Kuzin vendor = ebx; 4804c204fe5SShiri Kuzin max_level = eax; 4814c204fe5SShiri Kuzin if (max_level < 1) { 4824c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 4834c204fe5SShiri Kuzin return; 4844c204fe5SShiri Kuzin } 4854c204fe5SShiri Kuzin mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 4864c204fe5SShiri Kuzin model = (eax >> 4) & 0x0f; 4874c204fe5SShiri Kuzin family = (eax >> 8) & 0x0f; 4884c204fe5SShiri Kuzin brand_id = ebx & 0xff; 4894c204fe5SShiri Kuzin extended_model = (eax >> 12) & 0xf0; 4904c204fe5SShiri Kuzin /* Check if the processor is Haswell or Broadwell */ 4914c204fe5SShiri Kuzin if (vendor == signature_intel_ebx) { 4924c204fe5SShiri Kuzin if (family == 0x06) 4934c204fe5SShiri Kuzin model += extended_model; 4944c204fe5SShiri Kuzin if (brand_id == 0 && family == 0x6) { 4954c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(broadwell_models); i++) 4964c204fe5SShiri Kuzin if (model == broadwell_models[i]) { 4974c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 4984c204fe5SShiri Kuzin return; 4994c204fe5SShiri Kuzin } 5004c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(haswell_models); i++) 5014c204fe5SShiri Kuzin if (model == haswell_models[i]) { 5024c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 5034c204fe5SShiri Kuzin return; 5044c204fe5SShiri Kuzin } 5054c204fe5SShiri Kuzin } 5064c204fe5SShiri Kuzin } 5074c204fe5SShiri Kuzin #endif 5084c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 5094c204fe5SShiri Kuzin } 510262c7ad0SOri Kam 511262c7ad0SOri Kam /** 5129cc0e99cSViacheslav Ovsiienko * Allocate the User Access Region with DevX on specified device. 5139cc0e99cSViacheslav Ovsiienko * 5149cc0e99cSViacheslav Ovsiienko * @param [in] ctx 5159cc0e99cSViacheslav Ovsiienko * Infiniband device context to perform allocation on. 5169cc0e99cSViacheslav Ovsiienko * @param [in] mapping 5179cc0e99cSViacheslav Ovsiienko * MLX5DV_UAR_ALLOC_TYPE_BF - allocate as cached memory with write-combining 5189cc0e99cSViacheslav Ovsiienko * attributes (if supported by the host), the 5199cc0e99cSViacheslav Ovsiienko * writes to the UAR registers must be followed 5209cc0e99cSViacheslav Ovsiienko * by write memory barrier. 5219cc0e99cSViacheslav Ovsiienko * MLX5DV_UAR_ALLOC_TYPE_NC - allocate as non-cached nenory, all writes are 5229cc0e99cSViacheslav Ovsiienko * promoted to the registers immediately, no 5239cc0e99cSViacheslav Ovsiienko * memory barriers needed. 5249cc0e99cSViacheslav Ovsiienko * mapping < 0 - the first attempt is performed with MLX5DV_UAR_ALLOC_TYPE_BF, 5259cc0e99cSViacheslav Ovsiienko * if this fails the next attempt with MLX5DV_UAR_ALLOC_TYPE_NC 5269cc0e99cSViacheslav Ovsiienko * is performed. The drivers specifying negative values should 5279cc0e99cSViacheslav Ovsiienko * always provide the write memory barrier operation after UAR 5289cc0e99cSViacheslav Ovsiienko * register writings. 5299cc0e99cSViacheslav Ovsiienko * If there is no definitions for the MLX5DV_UAR_ALLOC_TYPE_xx (older rdma 5309cc0e99cSViacheslav Ovsiienko * library headers), the caller can specify 0. 5319cc0e99cSViacheslav Ovsiienko * 5329cc0e99cSViacheslav Ovsiienko * @return 5339cc0e99cSViacheslav Ovsiienko * UAR object pointer on success, NULL otherwise and rte_errno is set. 5349cc0e99cSViacheslav Ovsiienko */ 5359cc0e99cSViacheslav Ovsiienko void * 5369cc0e99cSViacheslav Ovsiienko mlx5_devx_alloc_uar(void *ctx, int mapping) 5379cc0e99cSViacheslav Ovsiienko { 5389cc0e99cSViacheslav Ovsiienko void *uar; 5399cc0e99cSViacheslav Ovsiienko uint32_t retry, uar_mapping; 5409cc0e99cSViacheslav Ovsiienko void *base_addr; 5419cc0e99cSViacheslav Ovsiienko 5429cc0e99cSViacheslav Ovsiienko for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 5439cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 5449cc0e99cSViacheslav Ovsiienko /* Control the mapping type according to the settings. */ 5459cc0e99cSViacheslav Ovsiienko uar_mapping = (mapping < 0) ? 5469cc0e99cSViacheslav Ovsiienko MLX5DV_UAR_ALLOC_TYPE_NC : mapping; 5479cc0e99cSViacheslav Ovsiienko #else 5489cc0e99cSViacheslav Ovsiienko /* 5499cc0e99cSViacheslav Ovsiienko * It seems we have no way to control the memory mapping type 5509cc0e99cSViacheslav Ovsiienko * for the UAR, the default "Write-Combining" type is supposed. 5519cc0e99cSViacheslav Ovsiienko */ 5529cc0e99cSViacheslav Ovsiienko uar_mapping = 0; 5539cc0e99cSViacheslav Ovsiienko RTE_SET_USED(mapping); 5549cc0e99cSViacheslav Ovsiienko #endif 5559cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 5569cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 5579cc0e99cSViacheslav Ovsiienko if (!uar && 5589cc0e99cSViacheslav Ovsiienko mapping < 0 && 5599cc0e99cSViacheslav Ovsiienko uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 5609cc0e99cSViacheslav Ovsiienko /* 5619cc0e99cSViacheslav Ovsiienko * In some environments like virtual machine the 5629cc0e99cSViacheslav Ovsiienko * Write Combining mapped might be not supported and 5639cc0e99cSViacheslav Ovsiienko * UAR allocation fails. We tried "Non-Cached" mapping 5649cc0e99cSViacheslav Ovsiienko * for the case. 5659cc0e99cSViacheslav Ovsiienko */ 5669cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Failed to allocate DevX UAR (BF)"); 5679cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 5689cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 5699cc0e99cSViacheslav Ovsiienko } else if (!uar && 5709cc0e99cSViacheslav Ovsiienko mapping < 0 && 5719cc0e99cSViacheslav Ovsiienko uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 5729cc0e99cSViacheslav Ovsiienko /* 5739cc0e99cSViacheslav Ovsiienko * If Verbs/kernel does not support "Non-Cached" 5749cc0e99cSViacheslav Ovsiienko * try the "Write-Combining". 5759cc0e99cSViacheslav Ovsiienko */ 5769cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Failed to allocate DevX UAR (NC)"); 5779cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 5789cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 5799cc0e99cSViacheslav Ovsiienko } 5809cc0e99cSViacheslav Ovsiienko #endif 5819cc0e99cSViacheslav Ovsiienko if (!uar) { 5829cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 5839cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 5849cc0e99cSViacheslav Ovsiienko goto exit; 5859cc0e99cSViacheslav Ovsiienko } 5869cc0e99cSViacheslav Ovsiienko base_addr = mlx5_os_get_devx_uar_base_addr(uar); 5879cc0e99cSViacheslav Ovsiienko if (base_addr) 5889cc0e99cSViacheslav Ovsiienko break; 5899cc0e99cSViacheslav Ovsiienko /* 5909cc0e99cSViacheslav Ovsiienko * The UARs are allocated by rdma_core within the 5919cc0e99cSViacheslav Ovsiienko * IB device context, on context closure all UARs 5929cc0e99cSViacheslav Ovsiienko * will be freed, should be no memory/object leakage. 5939cc0e99cSViacheslav Ovsiienko */ 5949cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Retrying to allocate DevX UAR"); 5959cc0e99cSViacheslav Ovsiienko uar = NULL; 5969cc0e99cSViacheslav Ovsiienko } 5979cc0e99cSViacheslav Ovsiienko /* Check whether we finally succeeded with valid UAR allocation. */ 5989cc0e99cSViacheslav Ovsiienko if (!uar) { 5999cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 6009cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 6019cc0e99cSViacheslav Ovsiienko } 6029cc0e99cSViacheslav Ovsiienko /* 6039cc0e99cSViacheslav Ovsiienko * Return void * instead of struct mlx5dv_devx_uar * 6049cc0e99cSViacheslav Ovsiienko * is for compatibility with older rdma-core library headers. 6059cc0e99cSViacheslav Ovsiienko */ 6069cc0e99cSViacheslav Ovsiienko exit: 6079cc0e99cSViacheslav Ovsiienko return uar; 6089cc0e99cSViacheslav Ovsiienko } 609ad435d32SXueming Li 610ad435d32SXueming Li RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__); 611