xref: /dpdk/drivers/gpu/cuda/cuda.c (revision 0105d49e7e6e8e0442646f401f5bc61cf6a6ca14)
11306a73bSElena Agostini /* SPDX-License-Identifier: BSD-3-Clause
21306a73bSElena Agostini  * Copyright (c) 2021 NVIDIA Corporation & Affiliates
31306a73bSElena Agostini  */
41306a73bSElena Agostini 
51306a73bSElena Agostini #include <dlfcn.h>
61306a73bSElena Agostini 
71306a73bSElena Agostini #include <rte_malloc.h>
81306a73bSElena Agostini #include <rte_pci.h>
91306a73bSElena Agostini #include <rte_bus_pci.h>
101306a73bSElena Agostini #include <rte_byteorder.h>
111306a73bSElena Agostini #include <rte_dev.h>
121306a73bSElena Agostini 
131306a73bSElena Agostini #include <gpudev_driver.h>
1424c77594SElena Agostini 
151306a73bSElena Agostini #include <cuda.h>
161306a73bSElena Agostini #include <cudaTypedefs.h>
171306a73bSElena Agostini 
1824c77594SElena Agostini #include "common.h"
1924c77594SElena Agostini 
201306a73bSElena Agostini #define CUDA_DRIVER_MIN_VERSION 11040
211306a73bSElena Agostini #define CUDA_API_MIN_VERSION 3020
221306a73bSElena Agostini 
231306a73bSElena Agostini /* CUDA Driver functions loaded with dlsym() */
241306a73bSElena Agostini static CUresult CUDAAPI (*sym_cuInit)(unsigned int flags);
251306a73bSElena Agostini static CUresult CUDAAPI (*sym_cuDriverGetVersion)(int *driverVersion);
261306a73bSElena Agostini static CUresult CUDAAPI (*sym_cuGetProcAddress)(const char *symbol,
271306a73bSElena Agostini 		void **pfn, int cudaVersion, uint64_t flags);
281306a73bSElena Agostini 
291306a73bSElena Agostini /* CUDA Driver functions loaded with cuGetProcAddress for versioning */
301306a73bSElena Agostini static PFN_cuGetErrorString pfn_cuGetErrorString;
311306a73bSElena Agostini static PFN_cuGetErrorName pfn_cuGetErrorName;
321306a73bSElena Agostini static PFN_cuPointerSetAttribute pfn_cuPointerSetAttribute;
331306a73bSElena Agostini static PFN_cuDeviceGetAttribute pfn_cuDeviceGetAttribute;
341306a73bSElena Agostini static PFN_cuDeviceGetByPCIBusId pfn_cuDeviceGetByPCIBusId;
351306a73bSElena Agostini static PFN_cuDevicePrimaryCtxRetain pfn_cuDevicePrimaryCtxRetain;
361306a73bSElena Agostini static PFN_cuDevicePrimaryCtxRelease pfn_cuDevicePrimaryCtxRelease;
371306a73bSElena Agostini static PFN_cuDeviceTotalMem pfn_cuDeviceTotalMem;
381306a73bSElena Agostini static PFN_cuDeviceGetName pfn_cuDeviceGetName;
391306a73bSElena Agostini static PFN_cuCtxGetApiVersion pfn_cuCtxGetApiVersion;
401306a73bSElena Agostini static PFN_cuCtxSetCurrent pfn_cuCtxSetCurrent;
411306a73bSElena Agostini static PFN_cuCtxGetCurrent pfn_cuCtxGetCurrent;
421306a73bSElena Agostini static PFN_cuCtxGetDevice pfn_cuCtxGetDevice;
431306a73bSElena Agostini static PFN_cuCtxGetExecAffinity pfn_cuCtxGetExecAffinity;
441306a73bSElena Agostini static PFN_cuMemAlloc pfn_cuMemAlloc;
451306a73bSElena Agostini static PFN_cuMemFree pfn_cuMemFree;
461306a73bSElena Agostini static PFN_cuMemHostRegister pfn_cuMemHostRegister;
471306a73bSElena Agostini static PFN_cuMemHostUnregister pfn_cuMemHostUnregister;
481306a73bSElena Agostini static PFN_cuMemHostGetDevicePointer pfn_cuMemHostGetDevicePointer;
491306a73bSElena Agostini static PFN_cuFlushGPUDirectRDMAWrites pfn_cuFlushGPUDirectRDMAWrites;
501306a73bSElena Agostini 
511306a73bSElena Agostini static void *cudalib;
521306a73bSElena Agostini static unsigned int cuda_api_version;
531306a73bSElena Agostini static int cuda_driver_version;
5424c77594SElena Agostini static gdr_t gdrc_h;
551306a73bSElena Agostini 
561306a73bSElena Agostini /* NVIDIA GPU vendor */
571306a73bSElena Agostini #define NVIDIA_GPU_VENDOR_ID (0x10de)
581306a73bSElena Agostini 
591306a73bSElena Agostini /* NVIDIA GPU device IDs */
601306a73bSElena Agostini #define NVIDIA_GPU_A100_40GB_DEVICE_ID (0x20f1)
611306a73bSElena Agostini #define NVIDIA_GPU_A100_80GB_DEVICE_ID (0x20b5)
6265ac1464SElena Agostini #define NVIDIA_GPU_A100_80GB_DPU_DEVICE_ID (0x20b8)
631306a73bSElena Agostini 
641306a73bSElena Agostini #define NVIDIA_GPU_A30_24GB_DEVICE_ID (0x20b7)
651306a73bSElena Agostini #define NVIDIA_GPU_A10_24GB_DEVICE_ID (0x2236)
661306a73bSElena Agostini 
6756b5bb50SElena Agostini #define NVIDIA_GPU_V100_32GB_SXM_DEVICE_ID (0x1db5)
6856b5bb50SElena Agostini #define NVIDIA_GPU_V100_32GB_PCIE_DEVICE_ID (0x1db6)
691306a73bSElena Agostini #define NVIDIA_GPU_V100_16GB_DEVICE_ID (0x1db4)
701306a73bSElena Agostini 
711306a73bSElena Agostini #define NVIDIA_GPU_T4_16GB_DEVICE_ID (0x1eb8)
721306a73bSElena Agostini 
731306a73bSElena Agostini #define CUDA_MAX_ALLOCATION_NUM 512
741306a73bSElena Agostini 
751306a73bSElena Agostini #define GPU_PAGE_SHIFT 16
761306a73bSElena Agostini #define GPU_PAGE_SIZE (1UL << GPU_PAGE_SHIFT)
771306a73bSElena Agostini 
7824c77594SElena Agostini RTE_LOG_REGISTER_DEFAULT(cuda_logtype, NOTICE);
791306a73bSElena Agostini 
801306a73bSElena Agostini /* NVIDIA GPU address map */
811306a73bSElena Agostini static const struct rte_pci_id pci_id_cuda_map[] = {
821306a73bSElena Agostini 	{
831306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
841306a73bSElena Agostini 				NVIDIA_GPU_A100_40GB_DEVICE_ID)
851306a73bSElena Agostini 	},
861306a73bSElena Agostini 	{
871306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
881306a73bSElena Agostini 				NVIDIA_GPU_A100_80GB_DEVICE_ID)
891306a73bSElena Agostini 	},
901306a73bSElena Agostini 	{
911306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
9265ac1464SElena Agostini 				NVIDIA_GPU_A100_80GB_DPU_DEVICE_ID)
9365ac1464SElena Agostini 	},
9465ac1464SElena Agostini 	{
9565ac1464SElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
961306a73bSElena Agostini 				NVIDIA_GPU_A30_24GB_DEVICE_ID)
971306a73bSElena Agostini 	},
981306a73bSElena Agostini 	{
991306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
1001306a73bSElena Agostini 				NVIDIA_GPU_A10_24GB_DEVICE_ID)
1011306a73bSElena Agostini 	},
1021306a73bSElena Agostini 	{
1031306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
10456b5bb50SElena Agostini 				NVIDIA_GPU_V100_32GB_SXM_DEVICE_ID)
10556b5bb50SElena Agostini 	},
10656b5bb50SElena Agostini 	{
10756b5bb50SElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
10856b5bb50SElena Agostini 				NVIDIA_GPU_V100_32GB_PCIE_DEVICE_ID)
1091306a73bSElena Agostini 	},
1101306a73bSElena Agostini 	{
1111306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
1121306a73bSElena Agostini 				NVIDIA_GPU_V100_16GB_DEVICE_ID)
1131306a73bSElena Agostini 	},
1141306a73bSElena Agostini 	{
1151306a73bSElena Agostini 		RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
1161306a73bSElena Agostini 				NVIDIA_GPU_T4_16GB_DEVICE_ID)
1171306a73bSElena Agostini 	},
1181306a73bSElena Agostini 	{
1191306a73bSElena Agostini 		.device_id = 0
1201306a73bSElena Agostini 	}
1211306a73bSElena Agostini };
1221306a73bSElena Agostini 
1231306a73bSElena Agostini /* Device private info */
1241306a73bSElena Agostini struct cuda_info {
1251306a73bSElena Agostini 	char gpu_name[RTE_DEV_NAME_MAX_LEN];
1261306a73bSElena Agostini 	CUdevice cu_dev;
1271306a73bSElena Agostini 	int gdr_supported;
1281306a73bSElena Agostini 	int gdr_write_ordering;
1291306a73bSElena Agostini 	int gdr_flush_type;
1301306a73bSElena Agostini };
1311306a73bSElena Agostini 
1321306a73bSElena Agostini /* Type of memory allocated by CUDA driver */
1331306a73bSElena Agostini enum mem_type {
1341306a73bSElena Agostini 	GPU_MEM = 0,
1351306a73bSElena Agostini 	CPU_REGISTERED,
1361306a73bSElena Agostini 	GPU_REGISTERED /* Not used yet */
1371306a73bSElena Agostini };
1381306a73bSElena Agostini 
1391306a73bSElena Agostini /* key associated to a memory address */
1401306a73bSElena Agostini typedef uintptr_t cuda_ptr_key;
1411306a73bSElena Agostini 
1421306a73bSElena Agostini /* Single entry of the memory list */
1431306a73bSElena Agostini struct mem_entry {
1441306a73bSElena Agostini 	CUdeviceptr ptr_d;
145c8557ed4SElena Agostini 	CUdeviceptr ptr_orig_d;
1461306a73bSElena Agostini 	void *ptr_h;
1471306a73bSElena Agostini 	size_t size;
148c8557ed4SElena Agostini 	size_t size_orig;
1491306a73bSElena Agostini 	struct rte_gpu *dev;
1501306a73bSElena Agostini 	CUcontext ctx;
1511306a73bSElena Agostini 	cuda_ptr_key pkey;
1521306a73bSElena Agostini 	enum mem_type mtype;
15324c77594SElena Agostini 	gdr_mh_t mh;
1541306a73bSElena Agostini 	struct mem_entry *prev;
1551306a73bSElena Agostini 	struct mem_entry *next;
1561306a73bSElena Agostini };
1571306a73bSElena Agostini 
1581306a73bSElena Agostini static struct mem_entry *mem_alloc_list_head;
1591306a73bSElena Agostini static struct mem_entry *mem_alloc_list_tail;
1601306a73bSElena Agostini static uint32_t mem_alloc_list_last_elem;
1611306a73bSElena Agostini 
1621306a73bSElena Agostini /* Load the CUDA symbols */
1631306a73bSElena Agostini 
1641306a73bSElena Agostini static int
1651306a73bSElena Agostini cuda_loader(void)
1661306a73bSElena Agostini {
1671306a73bSElena Agostini 	char cuda_path[1024];
1681306a73bSElena Agostini 
1691306a73bSElena Agostini 	if (getenv("CUDA_PATH_L") == NULL)
1701306a73bSElena Agostini 		snprintf(cuda_path, 1024, "%s", "libcuda.so");
1711306a73bSElena Agostini 	else
172*0105d49eSElena Agostini 		snprintf(cuda_path, 1024, "%s/%s", getenv("CUDA_PATH_L"), "libcuda.so");
1731306a73bSElena Agostini 
1741306a73bSElena Agostini 	cudalib = dlopen(cuda_path, RTLD_LAZY);
1751306a73bSElena Agostini 	if (cudalib == NULL) {
1761306a73bSElena Agostini 		rte_cuda_log(ERR, "Failed to find CUDA library in %s (CUDA_PATH_L=%s)",
1771306a73bSElena Agostini 				cuda_path, getenv("CUDA_PATH_L"));
1781306a73bSElena Agostini 		return -1;
1791306a73bSElena Agostini 	}
1801306a73bSElena Agostini 
1811306a73bSElena Agostini 	return 0;
1821306a73bSElena Agostini }
1831306a73bSElena Agostini 
1841306a73bSElena Agostini static int
1851306a73bSElena Agostini cuda_sym_func_loader(void)
1861306a73bSElena Agostini {
1871306a73bSElena Agostini 	if (cudalib == NULL)
1881306a73bSElena Agostini 		return -1;
1891306a73bSElena Agostini 
1901306a73bSElena Agostini 	sym_cuInit = dlsym(cudalib, "cuInit");
1911306a73bSElena Agostini 	if (sym_cuInit == NULL) {
1921306a73bSElena Agostini 		rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuInit");
1931306a73bSElena Agostini 		return -1;
1941306a73bSElena Agostini 	}
1951306a73bSElena Agostini 
1961306a73bSElena Agostini 	sym_cuDriverGetVersion = dlsym(cudalib, "cuDriverGetVersion");
1971306a73bSElena Agostini 	if (sym_cuDriverGetVersion == NULL) {
1981306a73bSElena Agostini 		rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuDriverGetVersion");
1991306a73bSElena Agostini 		return -1;
2001306a73bSElena Agostini 	}
2011306a73bSElena Agostini 
2021306a73bSElena Agostini 	sym_cuGetProcAddress = dlsym(cudalib, "cuGetProcAddress");
2031306a73bSElena Agostini 	if (sym_cuGetProcAddress == NULL) {
2041306a73bSElena Agostini 		rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuGetProcAddress");
2051306a73bSElena Agostini 		return -1;
2061306a73bSElena Agostini 	}
2071306a73bSElena Agostini 
2081306a73bSElena Agostini 	return 0;
2091306a73bSElena Agostini }
2101306a73bSElena Agostini 
2111306a73bSElena Agostini static int
2121306a73bSElena Agostini cuda_pfn_func_loader(void)
2131306a73bSElena Agostini {
2141306a73bSElena Agostini 	CUresult res;
2151306a73bSElena Agostini 
2161306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuGetErrorString",
2171306a73bSElena Agostini 			(void **) (&pfn_cuGetErrorString), cuda_driver_version, 0);
2181306a73bSElena Agostini 	if (res != 0) {
2191306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuGetErrorString failed with %d", res);
2201306a73bSElena Agostini 		return -1;
2211306a73bSElena Agostini 	}
2221306a73bSElena Agostini 
2231306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuGetErrorName",
2241306a73bSElena Agostini 			(void **)(&pfn_cuGetErrorName), cuda_driver_version, 0);
2251306a73bSElena Agostini 	if (res != 0) {
2261306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuGetErrorName failed with %d", res);
2271306a73bSElena Agostini 		return -1;
2281306a73bSElena Agostini 	}
2291306a73bSElena Agostini 
2301306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuPointerSetAttribute",
2311306a73bSElena Agostini 			(void **)(&pfn_cuPointerSetAttribute), cuda_driver_version, 0);
2321306a73bSElena Agostini 	if (res != 0) {
2331306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuPointerSetAttribute failed with %d", res);
2341306a73bSElena Agostini 		return -1;
2351306a73bSElena Agostini 	}
2361306a73bSElena Agostini 
2371306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDeviceGetAttribute",
2381306a73bSElena Agostini 			(void **)(&pfn_cuDeviceGetAttribute), cuda_driver_version, 0);
2391306a73bSElena Agostini 	if (res != 0) {
2401306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetAttribute failed with %d", res);
2411306a73bSElena Agostini 		return -1;
2421306a73bSElena Agostini 	}
2431306a73bSElena Agostini 
2441306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDeviceGetByPCIBusId",
2451306a73bSElena Agostini 			(void **)(&pfn_cuDeviceGetByPCIBusId), cuda_driver_version, 0);
2461306a73bSElena Agostini 	if (res != 0) {
2471306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetByPCIBusId failed with %d", res);
2481306a73bSElena Agostini 		return -1;
2491306a73bSElena Agostini 	}
2501306a73bSElena Agostini 
2511306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDeviceGetName",
2521306a73bSElena Agostini 			(void **)(&pfn_cuDeviceGetName), cuda_driver_version, 0);
2531306a73bSElena Agostini 	if (res != 0) {
2541306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetName failed with %d", res);
2551306a73bSElena Agostini 		return -1;
2561306a73bSElena Agostini 	}
2571306a73bSElena Agostini 
2581306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDevicePrimaryCtxRetain",
2591306a73bSElena Agostini 			(void **)(&pfn_cuDevicePrimaryCtxRetain), cuda_driver_version, 0);
2601306a73bSElena Agostini 	if (res != 0) {
2611306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDevicePrimaryCtxRetain failed with %d", res);
2621306a73bSElena Agostini 		return -1;
2631306a73bSElena Agostini 	}
2641306a73bSElena Agostini 
2651306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDevicePrimaryCtxRelease",
2661306a73bSElena Agostini 			(void **)(&pfn_cuDevicePrimaryCtxRelease), cuda_driver_version, 0);
2671306a73bSElena Agostini 	if (res != 0) {
2681306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDevicePrimaryCtxRelease failed with %d", res);
2691306a73bSElena Agostini 		return -1;
2701306a73bSElena Agostini 	}
2711306a73bSElena Agostini 
2721306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuDeviceTotalMem",
2731306a73bSElena Agostini 			(void **)(&pfn_cuDeviceTotalMem), cuda_driver_version, 0);
2741306a73bSElena Agostini 	if (res != 0) {
2751306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuDeviceTotalMem failed with %d", res);
2761306a73bSElena Agostini 		return -1;
2771306a73bSElena Agostini 	}
2781306a73bSElena Agostini 
2791306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuCtxGetApiVersion",
2801306a73bSElena Agostini 			(void **)(&pfn_cuCtxGetApiVersion), cuda_driver_version, 0);
2811306a73bSElena Agostini 	if (res != 0) {
2821306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetApiVersion failed with %d", res);
2831306a73bSElena Agostini 		return -1;
2841306a73bSElena Agostini 	}
2851306a73bSElena Agostini 
2861306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuCtxGetDevice",
2871306a73bSElena Agostini 			(void **)(&pfn_cuCtxGetDevice), cuda_driver_version, 0);
2881306a73bSElena Agostini 	if (res != 0) {
2891306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetDevice failed with %d", res);
2901306a73bSElena Agostini 		return -1;
2911306a73bSElena Agostini 	}
2921306a73bSElena Agostini 
2931306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuCtxSetCurrent",
2941306a73bSElena Agostini 			(void **)(&pfn_cuCtxSetCurrent), cuda_driver_version, 0);
2951306a73bSElena Agostini 	if (res != 0) {
2961306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuCtxSetCurrent failed with %d", res);
2971306a73bSElena Agostini 		return -1;
2981306a73bSElena Agostini 	}
2991306a73bSElena Agostini 
3001306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuCtxGetCurrent",
3011306a73bSElena Agostini 			(void **)(&pfn_cuCtxGetCurrent), cuda_driver_version, 0);
3021306a73bSElena Agostini 	if (res != 0) {
3031306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetCurrent failed with %d", res);
3041306a73bSElena Agostini 		return -1;
3051306a73bSElena Agostini 	}
3061306a73bSElena Agostini 
3071306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuCtxGetExecAffinity",
3081306a73bSElena Agostini 			(void **)(&pfn_cuCtxGetExecAffinity), cuda_driver_version, 0);
3091306a73bSElena Agostini 	if (res != 0) {
3101306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetExecAffinity failed with %d", res);
3111306a73bSElena Agostini 		return -1;
3121306a73bSElena Agostini 	}
3131306a73bSElena Agostini 
3141306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuMemAlloc",
3151306a73bSElena Agostini 			(void **)(&pfn_cuMemAlloc), cuda_driver_version, 0);
3161306a73bSElena Agostini 	if (res != 0) {
3171306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuMemAlloc failed with %d", res);
3181306a73bSElena Agostini 		return -1;
3191306a73bSElena Agostini 	}
3201306a73bSElena Agostini 
3211306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuMemFree",
3221306a73bSElena Agostini 			(void **)(&pfn_cuMemFree), cuda_driver_version, 0);
3231306a73bSElena Agostini 	if (res != 0) {
3241306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuMemFree failed with %d", res);
3251306a73bSElena Agostini 		return -1;
3261306a73bSElena Agostini 	}
3271306a73bSElena Agostini 
3281306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuMemHostRegister",
3291306a73bSElena Agostini 			(void **)(&pfn_cuMemHostRegister), cuda_driver_version, 0);
3301306a73bSElena Agostini 	if (res != 0) {
3311306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuMemHostRegister failed with %d", res);
3321306a73bSElena Agostini 		return -1;
3331306a73bSElena Agostini 	}
3341306a73bSElena Agostini 
3351306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuMemHostUnregister",
3361306a73bSElena Agostini 			(void **)(&pfn_cuMemHostUnregister), cuda_driver_version, 0);
3371306a73bSElena Agostini 	if (res != 0) {
3381306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuMemHostUnregister failed with %d", res);
3391306a73bSElena Agostini 		return -1;
3401306a73bSElena Agostini 	}
3411306a73bSElena Agostini 
3421306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuMemHostGetDevicePointer",
3431306a73bSElena Agostini 			(void **)(&pfn_cuMemHostGetDevicePointer), cuda_driver_version, 0);
3441306a73bSElena Agostini 	if (res != 0) {
3451306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve pfn_cuMemHostGetDevicePointer failed with %d", res);
3461306a73bSElena Agostini 		return -1;
3471306a73bSElena Agostini 	}
3481306a73bSElena Agostini 
3491306a73bSElena Agostini 	res = sym_cuGetProcAddress("cuFlushGPUDirectRDMAWrites",
3501306a73bSElena Agostini 			(void **)(&pfn_cuFlushGPUDirectRDMAWrites), cuda_driver_version, 0);
3511306a73bSElena Agostini 	if (res != 0) {
3521306a73bSElena Agostini 		rte_cuda_log(ERR, "Retrieve cuFlushGPUDirectRDMAWrites failed with %d", res);
3531306a73bSElena Agostini 		return -1;
3541306a73bSElena Agostini 	}
3551306a73bSElena Agostini 
3561306a73bSElena Agostini 	return 0;
3571306a73bSElena Agostini }
3581306a73bSElena Agostini 
3591306a73bSElena Agostini /* Generate a key from a memory pointer */
3601306a73bSElena Agostini static cuda_ptr_key
3611306a73bSElena Agostini get_hash_from_ptr(void *ptr)
3621306a73bSElena Agostini {
3631306a73bSElena Agostini 	return (uintptr_t)ptr;
3641306a73bSElena Agostini }
3651306a73bSElena Agostini 
3661306a73bSElena Agostini static uint32_t
3671306a73bSElena Agostini mem_list_count_item(void)
3681306a73bSElena Agostini {
3691306a73bSElena Agostini 	return mem_alloc_list_last_elem;
3701306a73bSElena Agostini }
3711306a73bSElena Agostini 
3721306a73bSElena Agostini /* Initiate list of memory allocations if not done yet */
3731306a73bSElena Agostini static struct mem_entry *
3741306a73bSElena Agostini mem_list_add_item(void)
3751306a73bSElena Agostini {
3761306a73bSElena Agostini 	/* Initiate list of memory allocations if not done yet */
3771306a73bSElena Agostini 	if (mem_alloc_list_head == NULL) {
3781306a73bSElena Agostini 		mem_alloc_list_head = rte_zmalloc(NULL,
3791306a73bSElena Agostini 				sizeof(struct mem_entry),
3801306a73bSElena Agostini 				RTE_CACHE_LINE_SIZE);
3811306a73bSElena Agostini 		if (mem_alloc_list_head == NULL) {
3821306a73bSElena Agostini 			rte_cuda_log(ERR, "Failed to allocate memory for memory list");
3831306a73bSElena Agostini 			return NULL;
3841306a73bSElena Agostini 		}
3851306a73bSElena Agostini 
3861306a73bSElena Agostini 		mem_alloc_list_head->next = NULL;
3871306a73bSElena Agostini 		mem_alloc_list_head->prev = NULL;
3881306a73bSElena Agostini 		mem_alloc_list_tail = mem_alloc_list_head;
3891306a73bSElena Agostini 	} else {
3901306a73bSElena Agostini 		struct mem_entry *mem_alloc_list_cur = rte_zmalloc(NULL,
3911306a73bSElena Agostini 				sizeof(struct mem_entry),
3921306a73bSElena Agostini 				RTE_CACHE_LINE_SIZE);
3931306a73bSElena Agostini 
3941306a73bSElena Agostini 		if (mem_alloc_list_cur == NULL) {
3951306a73bSElena Agostini 			rte_cuda_log(ERR, "Failed to allocate memory for memory list");
3961306a73bSElena Agostini 			return NULL;
3971306a73bSElena Agostini 		}
3981306a73bSElena Agostini 
3991306a73bSElena Agostini 		mem_alloc_list_tail->next = mem_alloc_list_cur;
4001306a73bSElena Agostini 		mem_alloc_list_cur->prev = mem_alloc_list_tail;
4011306a73bSElena Agostini 		mem_alloc_list_tail = mem_alloc_list_tail->next;
4021306a73bSElena Agostini 		mem_alloc_list_tail->next = NULL;
4031306a73bSElena Agostini 	}
4041306a73bSElena Agostini 
4051306a73bSElena Agostini 	mem_alloc_list_last_elem++;
4061306a73bSElena Agostini 
4071306a73bSElena Agostini 	return mem_alloc_list_tail;
4081306a73bSElena Agostini }
4091306a73bSElena Agostini 
4101306a73bSElena Agostini static struct mem_entry *
4111306a73bSElena Agostini mem_list_find_item(cuda_ptr_key pk)
4121306a73bSElena Agostini {
4131306a73bSElena Agostini 	struct mem_entry *mem_alloc_list_cur = NULL;
4141306a73bSElena Agostini 
4151306a73bSElena Agostini 	if (mem_alloc_list_head == NULL) {
4161306a73bSElena Agostini 		rte_cuda_log(ERR, "Memory list doesn't exist");
4171306a73bSElena Agostini 		return NULL;
4181306a73bSElena Agostini 	}
4191306a73bSElena Agostini 
4201306a73bSElena Agostini 	if (mem_list_count_item() == 0) {
4211306a73bSElena Agostini 		rte_cuda_log(ERR, "No items in memory list");
4221306a73bSElena Agostini 		return NULL;
4231306a73bSElena Agostini 	}
4241306a73bSElena Agostini 
4251306a73bSElena Agostini 	mem_alloc_list_cur = mem_alloc_list_head;
4261306a73bSElena Agostini 
4271306a73bSElena Agostini 	while (mem_alloc_list_cur != NULL) {
4281306a73bSElena Agostini 		if (mem_alloc_list_cur->pkey == pk)
4291306a73bSElena Agostini 			return mem_alloc_list_cur;
4301306a73bSElena Agostini 		mem_alloc_list_cur = mem_alloc_list_cur->next;
4311306a73bSElena Agostini 	}
4321306a73bSElena Agostini 
4331306a73bSElena Agostini 	return mem_alloc_list_cur;
4341306a73bSElena Agostini }
4351306a73bSElena Agostini 
4361306a73bSElena Agostini static int
4371306a73bSElena Agostini mem_list_del_item(cuda_ptr_key pk)
4381306a73bSElena Agostini {
4391306a73bSElena Agostini 	struct mem_entry *mem_alloc_list_cur = NULL;
4401306a73bSElena Agostini 
4411306a73bSElena Agostini 	mem_alloc_list_cur = mem_list_find_item(pk);
4421306a73bSElena Agostini 	if (mem_alloc_list_cur == NULL)
4431306a73bSElena Agostini 		return -EINVAL;
4441306a73bSElena Agostini 
4451306a73bSElena Agostini 	/* if key is in head */
44698ddd04cSElena Agostini 	if (mem_alloc_list_cur->prev == NULL) {
4471306a73bSElena Agostini 		mem_alloc_list_head = mem_alloc_list_cur->next;
44898ddd04cSElena Agostini 		if (mem_alloc_list_head != NULL)
44998ddd04cSElena Agostini 			mem_alloc_list_head->prev = NULL;
45098ddd04cSElena Agostini 	} else {
4511306a73bSElena Agostini 		mem_alloc_list_cur->prev->next = mem_alloc_list_cur->next;
4521306a73bSElena Agostini 		if (mem_alloc_list_cur->next != NULL)
4531306a73bSElena Agostini 			mem_alloc_list_cur->next->prev = mem_alloc_list_cur->prev;
4541306a73bSElena Agostini 	}
4551306a73bSElena Agostini 
4561306a73bSElena Agostini 	rte_free(mem_alloc_list_cur);
4571306a73bSElena Agostini 
4581306a73bSElena Agostini 	mem_alloc_list_last_elem--;
4591306a73bSElena Agostini 
4601306a73bSElena Agostini 	return 0;
4611306a73bSElena Agostini }
4621306a73bSElena Agostini 
4631306a73bSElena Agostini static int
4641306a73bSElena Agostini cuda_dev_info_get(struct rte_gpu *dev, struct rte_gpu_info *info)
4651306a73bSElena Agostini {
4661306a73bSElena Agostini 	int ret = 0;
4671306a73bSElena Agostini 	CUresult res;
4681306a73bSElena Agostini 	struct rte_gpu_info parent_info;
4691306a73bSElena Agostini 	CUexecAffinityParam affinityPrm;
4701306a73bSElena Agostini 	const char *err_string;
4711306a73bSElena Agostini 	struct cuda_info *private;
4721306a73bSElena Agostini 	CUcontext current_ctx;
4731306a73bSElena Agostini 	CUcontext input_ctx;
4741306a73bSElena Agostini 
47594220b39SElena Agostini 	if (dev == NULL) {
47694220b39SElena Agostini 		rte_errno = ENODEV;
47794220b39SElena Agostini 		return -rte_errno;
47894220b39SElena Agostini 	}
4791306a73bSElena Agostini 
4801306a73bSElena Agostini 	/* Child initialization time probably called by rte_gpu_add_child() */
4811306a73bSElena Agostini 	if (dev->mpshared->info.parent != RTE_GPU_ID_NONE &&
4821306a73bSElena Agostini 			dev->mpshared->dev_private == NULL) {
4831306a73bSElena Agostini 		/* Store current ctx */
4841306a73bSElena Agostini 		res = pfn_cuCtxGetCurrent(&current_ctx);
4851306a73bSElena Agostini 		if (res != 0) {
4861306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
4871306a73bSElena Agostini 			rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
4881306a73bSElena Agostini 					err_string);
48994220b39SElena Agostini 			rte_errno = EPERM;
49094220b39SElena Agostini 			return -rte_errno;
4911306a73bSElena Agostini 		}
4921306a73bSElena Agostini 
4931306a73bSElena Agostini 		/* Set child ctx as current ctx */
4941306a73bSElena Agostini 		input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
4951306a73bSElena Agostini 		res = pfn_cuCtxSetCurrent(input_ctx);
4961306a73bSElena Agostini 		if (res != 0) {
4971306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
4981306a73bSElena Agostini 			rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
4991306a73bSElena Agostini 					err_string);
50094220b39SElena Agostini 			rte_errno = EPERM;
50194220b39SElena Agostini 			return -rte_errno;
5021306a73bSElena Agostini 		}
5031306a73bSElena Agostini 
5041306a73bSElena Agostini 		/*
5051306a73bSElena Agostini 		 * Ctx capacity info
5061306a73bSElena Agostini 		 */
5071306a73bSElena Agostini 
5081306a73bSElena Agostini 		/* MPS compatible */
5091306a73bSElena Agostini 		res = pfn_cuCtxGetExecAffinity(&affinityPrm,
5101306a73bSElena Agostini 				CU_EXEC_AFFINITY_TYPE_SM_COUNT);
5111306a73bSElena Agostini 		if (res != 0) {
5121306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
5131306a73bSElena Agostini 			rte_cuda_log(ERR, "cuCtxGetExecAffinity failed with %s",
5141306a73bSElena Agostini 					err_string);
5151306a73bSElena Agostini 		}
5161306a73bSElena Agostini 		dev->mpshared->info.processor_count =
5171306a73bSElena Agostini 				(uint32_t)affinityPrm.param.smCount.val;
5181306a73bSElena Agostini 
5191306a73bSElena Agostini 		ret = rte_gpu_info_get(dev->mpshared->info.parent, &parent_info);
52094220b39SElena Agostini 		if (ret) {
52194220b39SElena Agostini 			rte_errno = ENODEV;
52294220b39SElena Agostini 			return -rte_errno;
52394220b39SElena Agostini 		}
5241306a73bSElena Agostini 		dev->mpshared->info.total_memory = parent_info.total_memory;
5251306a73bSElena Agostini 
5261306a73bSElena Agostini 		/*
5271306a73bSElena Agostini 		 * GPU Device private info
5281306a73bSElena Agostini 		 */
5291306a73bSElena Agostini 		dev->mpshared->dev_private = rte_zmalloc(NULL,
5301306a73bSElena Agostini 				sizeof(struct cuda_info),
5311306a73bSElena Agostini 				RTE_CACHE_LINE_SIZE);
5321306a73bSElena Agostini 		if (dev->mpshared->dev_private == NULL) {
5331306a73bSElena Agostini 			rte_cuda_log(ERR, "Failed to allocate memory for GPU process private");
53494220b39SElena Agostini 			rte_errno = EPERM;
53594220b39SElena Agostini 			return -rte_errno;
5361306a73bSElena Agostini 		}
5371306a73bSElena Agostini 
5381306a73bSElena Agostini 		private = (struct cuda_info *)dev->mpshared->dev_private;
5391306a73bSElena Agostini 
5401306a73bSElena Agostini 		res = pfn_cuCtxGetDevice(&(private->cu_dev));
5411306a73bSElena Agostini 		if (res != 0) {
5421306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
5431306a73bSElena Agostini 			rte_cuda_log(ERR, "cuCtxGetDevice failed with %s",
5441306a73bSElena Agostini 					err_string);
54594220b39SElena Agostini 			rte_errno = EPERM;
54694220b39SElena Agostini 			return -rte_errno;
5471306a73bSElena Agostini 		}
5481306a73bSElena Agostini 
5491306a73bSElena Agostini 		res = pfn_cuDeviceGetName(private->gpu_name,
5501306a73bSElena Agostini 				RTE_DEV_NAME_MAX_LEN, private->cu_dev);
5511306a73bSElena Agostini 		if (res != 0) {
5521306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
5531306a73bSElena Agostini 			rte_cuda_log(ERR, "cuDeviceGetName failed with %s",
5541306a73bSElena Agostini 					err_string);
55594220b39SElena Agostini 			rte_errno = EPERM;
55694220b39SElena Agostini 			return -rte_errno;
5571306a73bSElena Agostini 		}
5581306a73bSElena Agostini 
5591306a73bSElena Agostini 		/* Restore original ctx as current ctx */
5601306a73bSElena Agostini 		res = pfn_cuCtxSetCurrent(current_ctx);
5611306a73bSElena Agostini 		if (res != 0) {
5621306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
5631306a73bSElena Agostini 			rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
5641306a73bSElena Agostini 					err_string);
56594220b39SElena Agostini 			rte_errno = EPERM;
56694220b39SElena Agostini 			return -rte_errno;
5671306a73bSElena Agostini 		}
5681306a73bSElena Agostini 	}
5691306a73bSElena Agostini 
5701306a73bSElena Agostini 	*info = dev->mpshared->info;
5711306a73bSElena Agostini 
5721306a73bSElena Agostini 	return 0;
5731306a73bSElena Agostini }
5741306a73bSElena Agostini 
5751306a73bSElena Agostini /*
5761306a73bSElena Agostini  * GPU Memory
5771306a73bSElena Agostini  */
5781306a73bSElena Agostini 
5791306a73bSElena Agostini static int
580c8557ed4SElena Agostini cuda_mem_alloc(struct rte_gpu *dev, size_t size, unsigned int align, void **ptr)
5811306a73bSElena Agostini {
5821306a73bSElena Agostini 	CUresult res;
5831306a73bSElena Agostini 	const char *err_string;
5841306a73bSElena Agostini 	CUcontext current_ctx;
5851306a73bSElena Agostini 	CUcontext input_ctx;
5861306a73bSElena Agostini 	unsigned int flag = 1;
5871306a73bSElena Agostini 
5881306a73bSElena Agostini 	if (dev == NULL)
5891306a73bSElena Agostini 		return -ENODEV;
5901306a73bSElena Agostini 
5911306a73bSElena Agostini 	/* Store current ctx */
5921306a73bSElena Agostini 	res = pfn_cuCtxGetCurrent(&current_ctx);
5931306a73bSElena Agostini 	if (res != 0) {
5941306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
5951306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
5961306a73bSElena Agostini 				err_string);
59794220b39SElena Agostini 		rte_errno = EPERM;
59894220b39SElena Agostini 		return -rte_errno;
5991306a73bSElena Agostini 	}
6001306a73bSElena Agostini 
6011306a73bSElena Agostini 	/* Set child ctx as current ctx */
6021306a73bSElena Agostini 	input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
6031306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(input_ctx);
6041306a73bSElena Agostini 	if (res != 0) {
6051306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
6061306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
6071306a73bSElena Agostini 				err_string);
60894220b39SElena Agostini 		rte_errno = EPERM;
60994220b39SElena Agostini 		return -rte_errno;
6101306a73bSElena Agostini 	}
6111306a73bSElena Agostini 
6121306a73bSElena Agostini 	/* Get next memory list item */
6131306a73bSElena Agostini 	mem_alloc_list_tail = mem_list_add_item();
61494220b39SElena Agostini 	if (mem_alloc_list_tail == NULL) {
61594220b39SElena Agostini 		rte_errno = EPERM;
61694220b39SElena Agostini 		return -rte_errno;
61794220b39SElena Agostini 	}
6181306a73bSElena Agostini 
6191306a73bSElena Agostini 	/* Allocate memory */
6201306a73bSElena Agostini 	mem_alloc_list_tail->size = size;
621c8557ed4SElena Agostini 	mem_alloc_list_tail->size_orig = size + align;
622c8557ed4SElena Agostini 
623c8557ed4SElena Agostini 	res = pfn_cuMemAlloc(&(mem_alloc_list_tail->ptr_orig_d),
624c8557ed4SElena Agostini 			mem_alloc_list_tail->size_orig);
6251306a73bSElena Agostini 	if (res != 0) {
6261306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
6271306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
6281306a73bSElena Agostini 				err_string);
62994220b39SElena Agostini 		rte_errno = EPERM;
63094220b39SElena Agostini 		return -rte_errno;
6311306a73bSElena Agostini 	}
6321306a73bSElena Agostini 
633c8557ed4SElena Agostini 	/* Align memory address */
634c8557ed4SElena Agostini 	mem_alloc_list_tail->ptr_d = mem_alloc_list_tail->ptr_orig_d;
635c8557ed4SElena Agostini 	if (align && ((uintptr_t)mem_alloc_list_tail->ptr_d) % align)
636c8557ed4SElena Agostini 		mem_alloc_list_tail->ptr_d += (align -
637c8557ed4SElena Agostini 				(((uintptr_t)mem_alloc_list_tail->ptr_d) % align));
638c8557ed4SElena Agostini 
6391306a73bSElena Agostini 	/* GPUDirect RDMA attribute required */
6401306a73bSElena Agostini 	res = pfn_cuPointerSetAttribute(&flag,
6411306a73bSElena Agostini 			CU_POINTER_ATTRIBUTE_SYNC_MEMOPS,
6421306a73bSElena Agostini 			mem_alloc_list_tail->ptr_d);
6431306a73bSElena Agostini 	if (res != 0) {
6441306a73bSElena Agostini 		rte_cuda_log(ERR, "Could not set SYNC MEMOP attribute for "
6451306a73bSElena Agostini 				"GPU memory at  %"PRIu32", err %d",
6461306a73bSElena Agostini 				(uint32_t)mem_alloc_list_tail->ptr_d, res);
64794220b39SElena Agostini 		rte_errno = EPERM;
64894220b39SElena Agostini 		return -rte_errno;
6491306a73bSElena Agostini 	}
6501306a73bSElena Agostini 
6511306a73bSElena Agostini 	mem_alloc_list_tail->pkey = get_hash_from_ptr((void *)mem_alloc_list_tail->ptr_d);
6521306a73bSElena Agostini 	mem_alloc_list_tail->ptr_h = NULL;
6531306a73bSElena Agostini 	mem_alloc_list_tail->dev = dev;
6541306a73bSElena Agostini 	mem_alloc_list_tail->ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
6551306a73bSElena Agostini 	mem_alloc_list_tail->mtype = GPU_MEM;
6561306a73bSElena Agostini 
6571306a73bSElena Agostini 	/* Restore original ctx as current ctx */
6581306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(current_ctx);
6591306a73bSElena Agostini 	if (res != 0) {
6601306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
6611306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
6621306a73bSElena Agostini 				err_string);
66394220b39SElena Agostini 		rte_errno = EPERM;
66494220b39SElena Agostini 		return -rte_errno;
6651306a73bSElena Agostini 	}
6661306a73bSElena Agostini 
6671306a73bSElena Agostini 	*ptr = (void *)mem_alloc_list_tail->ptr_d;
6681306a73bSElena Agostini 
6691306a73bSElena Agostini 	return 0;
6701306a73bSElena Agostini }
6711306a73bSElena Agostini 
6721306a73bSElena Agostini static int
6731306a73bSElena Agostini cuda_mem_register(struct rte_gpu *dev, size_t size, void *ptr)
6741306a73bSElena Agostini {
6751306a73bSElena Agostini 	CUresult res;
6761306a73bSElena Agostini 	const char *err_string;
6771306a73bSElena Agostini 	CUcontext current_ctx;
6781306a73bSElena Agostini 	CUcontext input_ctx;
6791306a73bSElena Agostini 	unsigned int flag = 1;
6801306a73bSElena Agostini 	int use_ptr_h = 0;
6811306a73bSElena Agostini 
6821306a73bSElena Agostini 	if (dev == NULL)
6831306a73bSElena Agostini 		return -ENODEV;
6841306a73bSElena Agostini 
6851306a73bSElena Agostini 	/* Store current ctx */
6861306a73bSElena Agostini 	res = pfn_cuCtxGetCurrent(&current_ctx);
6871306a73bSElena Agostini 	if (res != 0) {
6881306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
6891306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
6901306a73bSElena Agostini 				err_string);
69194220b39SElena Agostini 		rte_errno = EPERM;
69294220b39SElena Agostini 		return -rte_errno;
6931306a73bSElena Agostini 	}
6941306a73bSElena Agostini 
6951306a73bSElena Agostini 	/* Set child ctx as current ctx */
6961306a73bSElena Agostini 	input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
6971306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(input_ctx);
6981306a73bSElena Agostini 	if (res != 0) {
6991306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
7001306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
7011306a73bSElena Agostini 				err_string);
70294220b39SElena Agostini 		rte_errno = EPERM;
70394220b39SElena Agostini 		return -rte_errno;
7041306a73bSElena Agostini 	}
7051306a73bSElena Agostini 
7061306a73bSElena Agostini 	/* Get next memory list item */
7071306a73bSElena Agostini 	mem_alloc_list_tail = mem_list_add_item();
70894220b39SElena Agostini 	if (mem_alloc_list_tail == NULL) {
70994220b39SElena Agostini 		rte_errno = EPERM;
71094220b39SElena Agostini 		return -rte_errno;
71194220b39SElena Agostini 	}
7121306a73bSElena Agostini 
7131306a73bSElena Agostini 	/* Allocate memory */
7141306a73bSElena Agostini 	mem_alloc_list_tail->size = size;
7151306a73bSElena Agostini 	mem_alloc_list_tail->ptr_h = ptr;
7161306a73bSElena Agostini 
7171306a73bSElena Agostini 	res = pfn_cuMemHostRegister(mem_alloc_list_tail->ptr_h,
7181306a73bSElena Agostini 			mem_alloc_list_tail->size,
7191306a73bSElena Agostini 			CU_MEMHOSTREGISTER_PORTABLE |
7201306a73bSElena Agostini 			CU_MEMHOSTREGISTER_DEVICEMAP);
7211306a73bSElena Agostini 	if (res != 0) {
7221306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
7231306a73bSElena Agostini 		rte_cuda_log(ERR, "cuMemHostRegister failed with %s ptr %p size %zd",
7241306a73bSElena Agostini 				err_string,
7251306a73bSElena Agostini 				mem_alloc_list_tail->ptr_h,
7261306a73bSElena Agostini 				mem_alloc_list_tail->size);
72794220b39SElena Agostini 		rte_errno = EPERM;
72894220b39SElena Agostini 		return -rte_errno;
7291306a73bSElena Agostini 	}
7301306a73bSElena Agostini 
7311306a73bSElena Agostini 	res = pfn_cuDeviceGetAttribute(&(use_ptr_h),
7321306a73bSElena Agostini 			CU_DEVICE_ATTRIBUTE_CAN_USE_HOST_POINTER_FOR_REGISTERED_MEM,
7331306a73bSElena Agostini 			((struct cuda_info *)(dev->mpshared->dev_private))->cu_dev);
7341306a73bSElena Agostini 	if (res != 0) {
7351306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
7361306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
7371306a73bSElena Agostini 				err_string);
73894220b39SElena Agostini 		rte_errno = EPERM;
73994220b39SElena Agostini 		return -rte_errno;
7401306a73bSElena Agostini 	}
7411306a73bSElena Agostini 
7421306a73bSElena Agostini 	if (use_ptr_h == 0) {
7431306a73bSElena Agostini 		res = pfn_cuMemHostGetDevicePointer(&(mem_alloc_list_tail->ptr_d),
7441306a73bSElena Agostini 				mem_alloc_list_tail->ptr_h, 0);
7451306a73bSElena Agostini 		if (res != 0) {
7461306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
7471306a73bSElena Agostini 			rte_cuda_log(ERR, "cuMemHostGetDevicePointer failed with %s",
7481306a73bSElena Agostini 					err_string);
74994220b39SElena Agostini 			rte_errno = EPERM;
75094220b39SElena Agostini 			return -rte_errno;
7511306a73bSElena Agostini 		}
7521306a73bSElena Agostini 
7531306a73bSElena Agostini 		if ((uintptr_t)mem_alloc_list_tail->ptr_d !=
7541306a73bSElena Agostini 				(uintptr_t)mem_alloc_list_tail->ptr_h) {
7551306a73bSElena Agostini 			rte_cuda_log(ERR, "Host input pointer is different wrt GPU registered pointer");
75694220b39SElena Agostini 			rte_errno = ENOTSUP;
75794220b39SElena Agostini 			return -rte_errno;
7581306a73bSElena Agostini 		}
7591306a73bSElena Agostini 	} else {
7601306a73bSElena Agostini 		mem_alloc_list_tail->ptr_d = (CUdeviceptr)mem_alloc_list_tail->ptr_h;
7611306a73bSElena Agostini 	}
7621306a73bSElena Agostini 
7631306a73bSElena Agostini 	/* GPUDirect RDMA attribute required */
7641306a73bSElena Agostini 	res = pfn_cuPointerSetAttribute(&flag,
7651306a73bSElena Agostini 			CU_POINTER_ATTRIBUTE_SYNC_MEMOPS,
7661306a73bSElena Agostini 			mem_alloc_list_tail->ptr_d);
7671306a73bSElena Agostini 	if (res != 0) {
7681306a73bSElena Agostini 		rte_cuda_log(ERR, "Could not set SYNC MEMOP attribute for GPU memory at %"PRIu32
7691306a73bSElena Agostini 				", err %d", (uint32_t)mem_alloc_list_tail->ptr_d, res);
77094220b39SElena Agostini 		rte_errno = EPERM;
77194220b39SElena Agostini 		return -rte_errno;
7721306a73bSElena Agostini 	}
7731306a73bSElena Agostini 
7741306a73bSElena Agostini 	mem_alloc_list_tail->pkey = get_hash_from_ptr((void *)mem_alloc_list_tail->ptr_h);
7751306a73bSElena Agostini 	mem_alloc_list_tail->size = size;
7761306a73bSElena Agostini 	mem_alloc_list_tail->dev = dev;
7771306a73bSElena Agostini 	mem_alloc_list_tail->ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
7781306a73bSElena Agostini 	mem_alloc_list_tail->mtype = CPU_REGISTERED;
779c8557ed4SElena Agostini 	mem_alloc_list_tail->ptr_orig_d = mem_alloc_list_tail->ptr_d;
7801306a73bSElena Agostini 
7811306a73bSElena Agostini 	/* Restore original ctx as current ctx */
7821306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(current_ctx);
7831306a73bSElena Agostini 	if (res != 0) {
7841306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
7851306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
7861306a73bSElena Agostini 				err_string);
78794220b39SElena Agostini 		rte_errno = EPERM;
78894220b39SElena Agostini 		return -rte_errno;
7891306a73bSElena Agostini 	}
7901306a73bSElena Agostini 
7911306a73bSElena Agostini 	return 0;
7921306a73bSElena Agostini }
7931306a73bSElena Agostini 
7941306a73bSElena Agostini static int
79524c77594SElena Agostini cuda_mem_cpu_map(struct rte_gpu *dev, __rte_unused size_t size, void *ptr_in, void **ptr_out)
79624c77594SElena Agostini {
79724c77594SElena Agostini 	struct mem_entry *mem_item;
79824c77594SElena Agostini 	cuda_ptr_key hk;
79924c77594SElena Agostini 
80024c77594SElena Agostini 	if (dev == NULL)
80124c77594SElena Agostini 		return -ENODEV;
80224c77594SElena Agostini 
80324c77594SElena Agostini 	hk = get_hash_from_ptr((void *)ptr_in);
80424c77594SElena Agostini 
80524c77594SElena Agostini 	mem_item = mem_list_find_item(hk);
80624c77594SElena Agostini 	if (mem_item == NULL) {
80724c77594SElena Agostini 		rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory.", ptr_in);
80824c77594SElena Agostini 		rte_errno = EPERM;
80924c77594SElena Agostini 		return -rte_errno;
81024c77594SElena Agostini 	}
81124c77594SElena Agostini 
81224c77594SElena Agostini 	if (mem_item->mtype != GPU_MEM) {
81324c77594SElena Agostini 		rte_cuda_log(ERR, "Memory address 0x%p is not GPU memory type.", ptr_in);
81424c77594SElena Agostini 		rte_errno = EPERM;
81524c77594SElena Agostini 		return -rte_errno;
81624c77594SElena Agostini 	}
81724c77594SElena Agostini 
81824c77594SElena Agostini 	if (mem_item->size != size)
81924c77594SElena Agostini 		rte_cuda_log(WARNING,
82024c77594SElena Agostini 				"Can't expose memory area with size (%zd) different from original size (%zd).",
82124c77594SElena Agostini 				size, mem_item->size);
82224c77594SElena Agostini 
82324c77594SElena Agostini 	if (gdrcopy_pin(&gdrc_h, &(mem_item->mh), (uint64_t)mem_item->ptr_d,
82424c77594SElena Agostini 					mem_item->size, &(mem_item->ptr_h))) {
82524c77594SElena Agostini 		rte_cuda_log(ERR, "Error exposing GPU memory address 0x%p.", ptr_in);
82624c77594SElena Agostini 		rte_errno = EPERM;
82724c77594SElena Agostini 		return -rte_errno;
82824c77594SElena Agostini 	}
82924c77594SElena Agostini 
83024c77594SElena Agostini 	*ptr_out = mem_item->ptr_h;
83124c77594SElena Agostini 
83224c77594SElena Agostini 	return 0;
83324c77594SElena Agostini }
83424c77594SElena Agostini 
83524c77594SElena Agostini static int
8361306a73bSElena Agostini cuda_mem_free(struct rte_gpu *dev, void *ptr)
8371306a73bSElena Agostini {
8381306a73bSElena Agostini 	CUresult res;
8391306a73bSElena Agostini 	struct mem_entry *mem_item;
8401306a73bSElena Agostini 	const char *err_string;
8411306a73bSElena Agostini 	cuda_ptr_key hk;
8421306a73bSElena Agostini 
8431306a73bSElena Agostini 	if (dev == NULL)
8441306a73bSElena Agostini 		return -ENODEV;
8451306a73bSElena Agostini 
8461306a73bSElena Agostini 	hk = get_hash_from_ptr((void *)ptr);
8471306a73bSElena Agostini 
8481306a73bSElena Agostini 	mem_item = mem_list_find_item(hk);
8491306a73bSElena Agostini 	if (mem_item == NULL) {
8501306a73bSElena Agostini 		rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory", ptr);
85194220b39SElena Agostini 		rte_errno = EPERM;
85294220b39SElena Agostini 		return -rte_errno;
8531306a73bSElena Agostini 	}
8541306a73bSElena Agostini 
8551306a73bSElena Agostini 	if (mem_item->mtype == GPU_MEM) {
856c8557ed4SElena Agostini 		res = pfn_cuMemFree(mem_item->ptr_orig_d);
8571306a73bSElena Agostini 		if (res != 0) {
8581306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
8591306a73bSElena Agostini 			rte_cuda_log(ERR, "cuMemFree current failed with %s",
8601306a73bSElena Agostini 					err_string);
86194220b39SElena Agostini 			rte_errno = EPERM;
86294220b39SElena Agostini 			return -rte_errno;
8631306a73bSElena Agostini 		}
8641306a73bSElena Agostini 
8651306a73bSElena Agostini 		return mem_list_del_item(hk);
8661306a73bSElena Agostini 	}
8671306a73bSElena Agostini 
8681306a73bSElena Agostini 	rte_cuda_log(ERR, "Memory type %d not supported", mem_item->mtype);
8691306a73bSElena Agostini 
8701306a73bSElena Agostini 	return -EPERM;
8711306a73bSElena Agostini }
8721306a73bSElena Agostini 
8731306a73bSElena Agostini static int
8741306a73bSElena Agostini cuda_mem_unregister(struct rte_gpu *dev, void *ptr)
8751306a73bSElena Agostini {
8761306a73bSElena Agostini 	CUresult res;
8771306a73bSElena Agostini 	struct mem_entry *mem_item;
8781306a73bSElena Agostini 	const char *err_string;
8791306a73bSElena Agostini 	cuda_ptr_key hk;
8801306a73bSElena Agostini 
8811306a73bSElena Agostini 	if (dev == NULL)
8821306a73bSElena Agostini 		return -ENODEV;
8831306a73bSElena Agostini 
8841306a73bSElena Agostini 	hk = get_hash_from_ptr((void *)ptr);
8851306a73bSElena Agostini 
8861306a73bSElena Agostini 	mem_item = mem_list_find_item(hk);
8871306a73bSElena Agostini 	if (mem_item == NULL) {
8881306a73bSElena Agostini 		rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory", ptr);
88994220b39SElena Agostini 		rte_errno = EPERM;
89094220b39SElena Agostini 		return -rte_errno;
8911306a73bSElena Agostini 	}
8921306a73bSElena Agostini 
8931306a73bSElena Agostini 	if (mem_item->mtype == CPU_REGISTERED) {
8941306a73bSElena Agostini 		res = pfn_cuMemHostUnregister(ptr);
8951306a73bSElena Agostini 		if (res != 0) {
8961306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
8971306a73bSElena Agostini 			rte_cuda_log(ERR, "cuMemHostUnregister current failed with %s",
8981306a73bSElena Agostini 					err_string);
89994220b39SElena Agostini 			rte_errno = EPERM;
90094220b39SElena Agostini 			return -rte_errno;
9011306a73bSElena Agostini 		}
9021306a73bSElena Agostini 
9031306a73bSElena Agostini 		return mem_list_del_item(hk);
9041306a73bSElena Agostini 	}
9051306a73bSElena Agostini 
9061306a73bSElena Agostini 	rte_cuda_log(ERR, "Memory type %d not supported", mem_item->mtype);
9071306a73bSElena Agostini 
90894220b39SElena Agostini 	rte_errno = EPERM;
90994220b39SElena Agostini 	return -rte_errno;
9101306a73bSElena Agostini }
9111306a73bSElena Agostini 
9121306a73bSElena Agostini static int
91324c77594SElena Agostini cuda_mem_cpu_unmap(struct rte_gpu *dev, void *ptr_in)
91424c77594SElena Agostini {
91524c77594SElena Agostini 	struct mem_entry *mem_item;
91624c77594SElena Agostini 	cuda_ptr_key hk;
91724c77594SElena Agostini 
91824c77594SElena Agostini 	if (dev == NULL)
91924c77594SElena Agostini 		return -ENODEV;
92024c77594SElena Agostini 
92124c77594SElena Agostini 	hk = get_hash_from_ptr((void *)ptr_in);
92224c77594SElena Agostini 
92324c77594SElena Agostini 	mem_item = mem_list_find_item(hk);
92424c77594SElena Agostini 	if (mem_item == NULL) {
92524c77594SElena Agostini 		rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory.", ptr_in);
92624c77594SElena Agostini 		rte_errno = EPERM;
92724c77594SElena Agostini 		return -rte_errno;
92824c77594SElena Agostini 	}
92924c77594SElena Agostini 
93024c77594SElena Agostini 	if (gdrcopy_unpin(gdrc_h, mem_item->mh, (void *)mem_item->ptr_d,
93124c77594SElena Agostini 			mem_item->size)) {
93224c77594SElena Agostini 		rte_cuda_log(ERR, "Error unexposing GPU memory address 0x%p.", ptr_in);
93324c77594SElena Agostini 		rte_errno = EPERM;
93424c77594SElena Agostini 		return -rte_errno;
93524c77594SElena Agostini 	}
93624c77594SElena Agostini 
93724c77594SElena Agostini 	return 0;
93824c77594SElena Agostini }
93924c77594SElena Agostini 
94024c77594SElena Agostini static int
9411306a73bSElena Agostini cuda_dev_close(struct rte_gpu *dev)
9421306a73bSElena Agostini {
9431306a73bSElena Agostini 	if (dev == NULL)
9441306a73bSElena Agostini 		return -EINVAL;
9451306a73bSElena Agostini 
9461306a73bSElena Agostini 	rte_free(dev->mpshared->dev_private);
9471306a73bSElena Agostini 
9481306a73bSElena Agostini 	return 0;
9491306a73bSElena Agostini }
9501306a73bSElena Agostini 
9511306a73bSElena Agostini static int
9521306a73bSElena Agostini cuda_wmb(struct rte_gpu *dev)
9531306a73bSElena Agostini {
9541306a73bSElena Agostini 	CUresult res;
9551306a73bSElena Agostini 	const char *err_string;
9561306a73bSElena Agostini 	CUcontext current_ctx;
9571306a73bSElena Agostini 	CUcontext input_ctx;
9581306a73bSElena Agostini 	struct cuda_info *private;
9591306a73bSElena Agostini 
96094220b39SElena Agostini 	if (dev == NULL) {
96194220b39SElena Agostini 		rte_errno = ENODEV;
96294220b39SElena Agostini 		return -rte_errno;
96394220b39SElena Agostini 	}
9641306a73bSElena Agostini 
9651306a73bSElena Agostini 	private = (struct cuda_info *)dev->mpshared->dev_private;
9661306a73bSElena Agostini 
9671306a73bSElena Agostini 	if (private->gdr_write_ordering != CU_GPU_DIRECT_RDMA_WRITES_ORDERING_NONE) {
9681306a73bSElena Agostini 		/*
9691306a73bSElena Agostini 		 * No need to explicitly force the write ordering because
9701306a73bSElena Agostini 		 * the device natively supports it
9711306a73bSElena Agostini 		 */
9721306a73bSElena Agostini 		return 0;
9731306a73bSElena Agostini 	}
9741306a73bSElena Agostini 
9751306a73bSElena Agostini 	if (private->gdr_flush_type != CU_FLUSH_GPU_DIRECT_RDMA_WRITES_OPTION_HOST) {
9761306a73bSElena Agostini 		/*
9771306a73bSElena Agostini 		 * Can't flush GDR writes with cuFlushGPUDirectRDMAWrites CUDA function.
9781306a73bSElena Agostini 		 * Application needs to use alternative methods.
9791306a73bSElena Agostini 		 */
9801306a73bSElena Agostini 		rte_cuda_log(WARNING, "Can't flush GDR writes with cuFlushGPUDirectRDMAWrites CUDA function."
9811306a73bSElena Agostini 				"Application needs to use alternative methods.");
98294220b39SElena Agostini 
98394220b39SElena Agostini 		rte_errno = ENOTSUP;
98494220b39SElena Agostini 		return -rte_errno;
9851306a73bSElena Agostini 	}
9861306a73bSElena Agostini 
9871306a73bSElena Agostini 	/* Store current ctx */
9881306a73bSElena Agostini 	res = pfn_cuCtxGetCurrent(&current_ctx);
9891306a73bSElena Agostini 	if (res != 0) {
9901306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
9911306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
9921306a73bSElena Agostini 				err_string);
99394220b39SElena Agostini 		rte_errno = EPERM;
99494220b39SElena Agostini 		return -rte_errno;
9951306a73bSElena Agostini 	}
9961306a73bSElena Agostini 
9971306a73bSElena Agostini 	/* Set child ctx as current ctx */
9981306a73bSElena Agostini 	input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
9991306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(input_ctx);
10001306a73bSElena Agostini 	if (res != 0) {
10011306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
10021306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
10031306a73bSElena Agostini 				err_string);
100494220b39SElena Agostini 		rte_errno = EPERM;
100594220b39SElena Agostini 		return -rte_errno;
10061306a73bSElena Agostini 	}
10071306a73bSElena Agostini 
10081306a73bSElena Agostini 	res = pfn_cuFlushGPUDirectRDMAWrites(CU_FLUSH_GPU_DIRECT_RDMA_WRITES_TARGET_CURRENT_CTX,
10091306a73bSElena Agostini 			CU_FLUSH_GPU_DIRECT_RDMA_WRITES_TO_ALL_DEVICES);
10101306a73bSElena Agostini 	if (res != 0) {
10111306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
10121306a73bSElena Agostini 		rte_cuda_log(ERR, "cuFlushGPUDirectRDMAWrites current failed with %s",
10131306a73bSElena Agostini 				err_string);
101494220b39SElena Agostini 		rte_errno = EPERM;
101594220b39SElena Agostini 		return -rte_errno;
10161306a73bSElena Agostini 	}
10171306a73bSElena Agostini 
10181306a73bSElena Agostini 	/* Restore original ctx as current ctx */
10191306a73bSElena Agostini 	res = pfn_cuCtxSetCurrent(current_ctx);
10201306a73bSElena Agostini 	if (res != 0) {
10211306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
10221306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
10231306a73bSElena Agostini 				err_string);
102494220b39SElena Agostini 		rte_errno = EPERM;
102594220b39SElena Agostini 		return -rte_errno;
10261306a73bSElena Agostini 	}
10271306a73bSElena Agostini 
10281306a73bSElena Agostini 	return 0;
10291306a73bSElena Agostini }
10301306a73bSElena Agostini 
10311306a73bSElena Agostini static int
10321306a73bSElena Agostini cuda_gpu_probe(__rte_unused struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
10331306a73bSElena Agostini {
10341306a73bSElena Agostini 	struct rte_gpu *dev = NULL;
10351306a73bSElena Agostini 	CUresult res;
10361306a73bSElena Agostini 	CUdevice cu_dev_id;
10371306a73bSElena Agostini 	CUcontext pctx;
10381306a73bSElena Agostini 	char dev_name[RTE_DEV_NAME_MAX_LEN];
10391306a73bSElena Agostini 	const char *err_string;
10401306a73bSElena Agostini 	int processor_count = 0;
10411306a73bSElena Agostini 	struct cuda_info *private;
10421306a73bSElena Agostini 
10431306a73bSElena Agostini 	if (pci_dev == NULL) {
10441306a73bSElena Agostini 		rte_cuda_log(ERR, "NULL PCI device");
104594220b39SElena Agostini 		rte_errno = ENODEV;
104694220b39SElena Agostini 		return -rte_errno;
10471306a73bSElena Agostini 	}
10481306a73bSElena Agostini 
10491306a73bSElena Agostini 	rte_pci_device_name(&pci_dev->addr, dev_name, sizeof(dev_name));
10501306a73bSElena Agostini 
10511306a73bSElena Agostini 	/* Allocate memory to be used privately by drivers */
10521306a73bSElena Agostini 	dev = rte_gpu_allocate(pci_dev->device.name);
105394220b39SElena Agostini 	if (dev == NULL) {
105494220b39SElena Agostini 		rte_errno = ENODEV;
105594220b39SElena Agostini 		return -rte_errno;
105694220b39SElena Agostini 	}
10571306a73bSElena Agostini 
10581306a73bSElena Agostini 	/* Initialize values only for the first CUDA driver call */
10591306a73bSElena Agostini 	if (dev->mpshared->info.dev_id == 0) {
10601306a73bSElena Agostini 		mem_alloc_list_head = NULL;
10611306a73bSElena Agostini 		mem_alloc_list_tail = NULL;
10621306a73bSElena Agostini 		mem_alloc_list_last_elem = 0;
10631306a73bSElena Agostini 
10641306a73bSElena Agostini 		/* Load libcuda.so library */
10651306a73bSElena Agostini 		if (cuda_loader()) {
10661306a73bSElena Agostini 			rte_cuda_log(ERR, "CUDA Driver library not found");
106794220b39SElena Agostini 			rte_errno = ENOTSUP;
106894220b39SElena Agostini 			return -rte_errno;
10691306a73bSElena Agostini 		}
10701306a73bSElena Agostini 
10711306a73bSElena Agostini 		/* Load initial CUDA functions */
10721306a73bSElena Agostini 		if (cuda_sym_func_loader()) {
10731306a73bSElena Agostini 			rte_cuda_log(ERR, "CUDA functions not found in library");
107494220b39SElena Agostini 			rte_errno = ENOTSUP;
107594220b39SElena Agostini 			return -rte_errno;
10761306a73bSElena Agostini 		}
10771306a73bSElena Agostini 
10781306a73bSElena Agostini 		/*
10791306a73bSElena Agostini 		 * Required to initialize the CUDA Driver.
10801306a73bSElena Agostini 		 * Multiple calls of cuInit() will return immediately
10811306a73bSElena Agostini 		 * without making any relevant change
10821306a73bSElena Agostini 		 */
10831306a73bSElena Agostini 		sym_cuInit(0);
10841306a73bSElena Agostini 
10851306a73bSElena Agostini 		res = sym_cuDriverGetVersion(&cuda_driver_version);
10861306a73bSElena Agostini 		if (res != 0) {
10871306a73bSElena Agostini 			rte_cuda_log(ERR, "cuDriverGetVersion failed with %d", res);
108894220b39SElena Agostini 			rte_errno = ENOTSUP;
108994220b39SElena Agostini 			return -rte_errno;
10901306a73bSElena Agostini 		}
10911306a73bSElena Agostini 
10921306a73bSElena Agostini 		if (cuda_driver_version < CUDA_DRIVER_MIN_VERSION) {
10931306a73bSElena Agostini 			rte_cuda_log(ERR, "CUDA Driver version found is %d. "
10941306a73bSElena Agostini 					"Minimum requirement is %d",
10951306a73bSElena Agostini 					cuda_driver_version,
10961306a73bSElena Agostini 					CUDA_DRIVER_MIN_VERSION);
109794220b39SElena Agostini 			rte_errno = ENOTSUP;
109894220b39SElena Agostini 			return -rte_errno;
10991306a73bSElena Agostini 		}
11001306a73bSElena Agostini 
11011306a73bSElena Agostini 		if (cuda_pfn_func_loader()) {
11021306a73bSElena Agostini 			rte_cuda_log(ERR, "CUDA PFN functions not found in library");
110394220b39SElena Agostini 			rte_errno = ENOTSUP;
110494220b39SElena Agostini 			return -rte_errno;
11051306a73bSElena Agostini 		}
110624c77594SElena Agostini 
110724c77594SElena Agostini 		gdrc_h = NULL;
11081306a73bSElena Agostini 	}
11091306a73bSElena Agostini 
11101306a73bSElena Agostini 	/* Fill HW specific part of device structure */
11111306a73bSElena Agostini 	dev->device = &pci_dev->device;
11121306a73bSElena Agostini 	dev->mpshared->info.numa_node = pci_dev->device.numa_node;
11131306a73bSElena Agostini 
11141306a73bSElena Agostini 	/* Get NVIDIA GPU Device descriptor */
11151306a73bSElena Agostini 	res = pfn_cuDeviceGetByPCIBusId(&cu_dev_id, dev->device->name);
11161306a73bSElena Agostini 	if (res != 0) {
11171306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
11181306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceGetByPCIBusId name %s failed with %d: %s",
11191306a73bSElena Agostini 				dev->device->name, res, err_string);
112094220b39SElena Agostini 		rte_errno = EPERM;
112194220b39SElena Agostini 		return -rte_errno;
11221306a73bSElena Agostini 	}
11231306a73bSElena Agostini 
11241306a73bSElena Agostini 	res = pfn_cuDevicePrimaryCtxRetain(&pctx, cu_dev_id);
11251306a73bSElena Agostini 	if (res != 0) {
11261306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
11271306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDevicePrimaryCtxRetain name %s failed with %d: %s",
11281306a73bSElena Agostini 				dev->device->name, res, err_string);
112994220b39SElena Agostini 		rte_errno = EPERM;
113094220b39SElena Agostini 		return -rte_errno;
11311306a73bSElena Agostini 	}
11321306a73bSElena Agostini 
11331306a73bSElena Agostini 	res = pfn_cuCtxGetApiVersion(pctx, &cuda_api_version);
11341306a73bSElena Agostini 	if (res != 0) {
11351306a73bSElena Agostini 		rte_cuda_log(ERR, "cuCtxGetApiVersion failed with %d", res);
113694220b39SElena Agostini 		rte_errno = ENOTSUP;
113794220b39SElena Agostini 		return -rte_errno;
11381306a73bSElena Agostini 	}
11391306a73bSElena Agostini 
11401306a73bSElena Agostini 	if (cuda_api_version < CUDA_API_MIN_VERSION) {
11411306a73bSElena Agostini 		rte_cuda_log(ERR, "CUDA API version found is %d Minimum requirement is %d",
11421306a73bSElena Agostini 				cuda_api_version, CUDA_API_MIN_VERSION);
114394220b39SElena Agostini 		rte_errno = ENOTSUP;
114494220b39SElena Agostini 		return -rte_errno;
11451306a73bSElena Agostini 	}
11461306a73bSElena Agostini 
11471306a73bSElena Agostini 	dev->mpshared->info.context = (uint64_t)pctx;
11481306a73bSElena Agostini 
11491306a73bSElena Agostini 	/*
11501306a73bSElena Agostini 	 * GPU Device generic info
11511306a73bSElena Agostini 	 */
11521306a73bSElena Agostini 
11531306a73bSElena Agostini 	/* Processor count */
11541306a73bSElena Agostini 	res = pfn_cuDeviceGetAttribute(&(processor_count),
11551306a73bSElena Agostini 			CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
11561306a73bSElena Agostini 			cu_dev_id);
11571306a73bSElena Agostini 	if (res != 0) {
11581306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
11591306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
11601306a73bSElena Agostini 				err_string);
116194220b39SElena Agostini 		rte_errno = EPERM;
116294220b39SElena Agostini 		return -rte_errno;
11631306a73bSElena Agostini 	}
11641306a73bSElena Agostini 	dev->mpshared->info.processor_count = (uint32_t)processor_count;
11651306a73bSElena Agostini 
11661306a73bSElena Agostini 	/* Total memory */
11671306a73bSElena Agostini 	res = pfn_cuDeviceTotalMem(&dev->mpshared->info.total_memory, cu_dev_id);
11681306a73bSElena Agostini 	if (res != 0) {
11691306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
11701306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceTotalMem failed with %s",
11711306a73bSElena Agostini 				err_string);
117294220b39SElena Agostini 		rte_errno = EPERM;
117394220b39SElena Agostini 		return -rte_errno;
11741306a73bSElena Agostini 	}
11751306a73bSElena Agostini 
11761306a73bSElena Agostini 	/*
11771306a73bSElena Agostini 	 * GPU Device private info
11781306a73bSElena Agostini 	 */
11791306a73bSElena Agostini 	dev->mpshared->dev_private = rte_zmalloc(NULL,
11801306a73bSElena Agostini 			sizeof(struct cuda_info),
11811306a73bSElena Agostini 			RTE_CACHE_LINE_SIZE);
11821306a73bSElena Agostini 	if (dev->mpshared->dev_private == NULL) {
11831306a73bSElena Agostini 		rte_cuda_log(ERR, "Failed to allocate memory for GPU process private");
118494220b39SElena Agostini 		rte_errno = EPERM;
118594220b39SElena Agostini 		return -rte_errno;
11861306a73bSElena Agostini 	}
11871306a73bSElena Agostini 
11881306a73bSElena Agostini 	private = (struct cuda_info *)dev->mpshared->dev_private;
11891306a73bSElena Agostini 	private->cu_dev = cu_dev_id;
11901306a73bSElena Agostini 	res = pfn_cuDeviceGetName(private->gpu_name,
11911306a73bSElena Agostini 			RTE_DEV_NAME_MAX_LEN,
11921306a73bSElena Agostini 			cu_dev_id);
11931306a73bSElena Agostini 	if (res != 0) {
11941306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
11951306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceGetName failed with %s",
11961306a73bSElena Agostini 				err_string);
119794220b39SElena Agostini 		rte_errno = EPERM;
119894220b39SElena Agostini 		return -rte_errno;
11991306a73bSElena Agostini 	}
12001306a73bSElena Agostini 
12011306a73bSElena Agostini 	res = pfn_cuDeviceGetAttribute(&(private->gdr_supported),
12021306a73bSElena Agostini 			CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_SUPPORTED,
12031306a73bSElena Agostini 			cu_dev_id);
12041306a73bSElena Agostini 	if (res != 0) {
12051306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
12061306a73bSElena Agostini 		rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
12071306a73bSElena Agostini 				err_string);
120894220b39SElena Agostini 		rte_errno = EPERM;
120994220b39SElena Agostini 		return -rte_errno;
12101306a73bSElena Agostini 	}
12111306a73bSElena Agostini 
12121306a73bSElena Agostini 	if (private->gdr_supported == 0)
12131306a73bSElena Agostini 		rte_cuda_log(WARNING, "GPU %s doesn't support GPUDirect RDMA",
12141306a73bSElena Agostini 				pci_dev->device.name);
12151306a73bSElena Agostini 
12161306a73bSElena Agostini 	res = pfn_cuDeviceGetAttribute(&(private->gdr_write_ordering),
12171306a73bSElena Agostini 			CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_WRITES_ORDERING,
12181306a73bSElena Agostini 			cu_dev_id);
12191306a73bSElena Agostini 	if (res != 0) {
12201306a73bSElena Agostini 		pfn_cuGetErrorString(res, &(err_string));
12211306a73bSElena Agostini 		rte_cuda_log(ERR,
12221306a73bSElena Agostini 				"cuDeviceGetAttribute failed with %s",
12231306a73bSElena Agostini 				err_string);
122494220b39SElena Agostini 		rte_errno = EPERM;
122594220b39SElena Agostini 		return -rte_errno;
12261306a73bSElena Agostini 	}
12271306a73bSElena Agostini 
12281306a73bSElena Agostini 	if (private->gdr_write_ordering == CU_GPU_DIRECT_RDMA_WRITES_ORDERING_NONE) {
12291306a73bSElena Agostini 		res = pfn_cuDeviceGetAttribute(&(private->gdr_flush_type),
12301306a73bSElena Agostini 				CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_FLUSH_WRITES_OPTIONS,
12311306a73bSElena Agostini 				cu_dev_id);
12321306a73bSElena Agostini 		if (res != 0) {
12331306a73bSElena Agostini 			pfn_cuGetErrorString(res, &(err_string));
12341306a73bSElena Agostini 			rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
12351306a73bSElena Agostini 					err_string);
123694220b39SElena Agostini 			rte_errno = EPERM;
123794220b39SElena Agostini 			return -rte_errno;
12381306a73bSElena Agostini 		}
12391306a73bSElena Agostini 
12401306a73bSElena Agostini 		if (private->gdr_flush_type != CU_FLUSH_GPU_DIRECT_RDMA_WRITES_OPTION_HOST)
12411306a73bSElena Agostini 			rte_cuda_log(ERR, "GPUDirect RDMA flush writes API is not supported");
12421306a73bSElena Agostini 	}
12431306a73bSElena Agostini 
12441306a73bSElena Agostini 	dev->ops.dev_info_get = cuda_dev_info_get;
12451306a73bSElena Agostini 	dev->ops.dev_close = cuda_dev_close;
12461306a73bSElena Agostini 	dev->ops.mem_alloc = cuda_mem_alloc;
12471306a73bSElena Agostini 	dev->ops.mem_free = cuda_mem_free;
12481306a73bSElena Agostini 	dev->ops.mem_register = cuda_mem_register;
12491306a73bSElena Agostini 	dev->ops.mem_unregister = cuda_mem_unregister;
125024c77594SElena Agostini 	dev->ops.mem_cpu_map = cuda_mem_cpu_map;
125124c77594SElena Agostini 	dev->ops.mem_cpu_unmap = cuda_mem_cpu_unmap;
12521306a73bSElena Agostini 	dev->ops.wmb = cuda_wmb;
12531306a73bSElena Agostini 
12541306a73bSElena Agostini 	rte_gpu_complete_new(dev);
12551306a73bSElena Agostini 
12561306a73bSElena Agostini 	rte_cuda_debug("dev id = %u name = %s",
12571306a73bSElena Agostini 			dev->mpshared->info.dev_id, private->gpu_name);
12581306a73bSElena Agostini 
12591306a73bSElena Agostini 	return 0;
12601306a73bSElena Agostini }
12611306a73bSElena Agostini 
12621306a73bSElena Agostini static int
12631306a73bSElena Agostini cuda_gpu_remove(struct rte_pci_device *pci_dev)
12641306a73bSElena Agostini {
12651306a73bSElena Agostini 	struct rte_gpu *dev;
12661306a73bSElena Agostini 	int ret;
12671306a73bSElena Agostini 	uint8_t gpu_id;
12681306a73bSElena Agostini 
126994220b39SElena Agostini 	if (pci_dev == NULL) {
127094220b39SElena Agostini 		rte_errno = ENODEV;
127194220b39SElena Agostini 		return -rte_errno;
127294220b39SElena Agostini 	}
12731306a73bSElena Agostini 
12741306a73bSElena Agostini 	dev = rte_gpu_get_by_name(pci_dev->device.name);
12751306a73bSElena Agostini 	if (dev == NULL) {
12761306a73bSElena Agostini 		rte_cuda_log(ERR, "Couldn't find HW dev \"%s\" to uninitialise it",
12771306a73bSElena Agostini 				pci_dev->device.name);
127894220b39SElena Agostini 		rte_errno = ENODEV;
127994220b39SElena Agostini 		return -rte_errno;
12801306a73bSElena Agostini 	}
12811306a73bSElena Agostini 	gpu_id = dev->mpshared->info.dev_id;
12821306a73bSElena Agostini 
12831306a73bSElena Agostini 	/* release dev from library */
12841306a73bSElena Agostini 	ret = rte_gpu_release(dev);
12851306a73bSElena Agostini 	if (ret)
12861306a73bSElena Agostini 		rte_cuda_log(ERR, "Device %i failed to uninit: %i", gpu_id, ret);
12871306a73bSElena Agostini 
12881306a73bSElena Agostini 	rte_cuda_debug("Destroyed dev = %u", gpu_id);
12891306a73bSElena Agostini 
12901306a73bSElena Agostini 	return 0;
12911306a73bSElena Agostini }
12921306a73bSElena Agostini 
12931306a73bSElena Agostini static struct rte_pci_driver rte_cuda_driver = {
12941306a73bSElena Agostini 	.id_table = pci_id_cuda_map,
12951306a73bSElena Agostini 	.drv_flags = RTE_PCI_DRV_WC_ACTIVATE,
12961306a73bSElena Agostini 	.probe = cuda_gpu_probe,
12971306a73bSElena Agostini 	.remove = cuda_gpu_remove,
12981306a73bSElena Agostini };
12991306a73bSElena Agostini 
13001306a73bSElena Agostini RTE_PMD_REGISTER_PCI(gpu_cuda, rte_cuda_driver);
13011306a73bSElena Agostini RTE_PMD_REGISTER_PCI_TABLE(gpu_cuda, pci_id_cuda_map);
13021306a73bSElena Agostini RTE_PMD_REGISTER_KMOD_DEP(gpu_cuda, "* nvidia & (nv_peer_mem | nvpeer_mem)");
1303