1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2021 NVIDIA Corporation & Affiliates
7 #include <rte_malloc.h>
9 #include <rte_bus_pci.h>
10 #include <rte_byteorder.h>
13 #include <gpudev_driver.h>
16 #include <cudaTypedefs.h>
20 #define CUDA_DRIVER_MIN_VERSION 11040
21 #define CUDA_API_MIN_VERSION 3020
23 /* CUDA Driver functions loaded with dlsym() */
24 static CUresult CUDAAPI (*sym_cuInit)(unsigned int flags);
25 static CUresult CUDAAPI (*sym_cuDriverGetVersion)(int *driverVersion);
26 static CUresult CUDAAPI (*sym_cuGetProcAddress)(const char *symbol,
27 void **pfn, int cudaVersion, uint64_t flags);
29 /* CUDA Driver functions loaded with cuGetProcAddress for versioning */
30 static PFN_cuGetErrorString pfn_cuGetErrorString;
31 static PFN_cuGetErrorName pfn_cuGetErrorName;
32 static PFN_cuPointerSetAttribute pfn_cuPointerSetAttribute;
33 static PFN_cuDeviceGetAttribute pfn_cuDeviceGetAttribute;
34 static PFN_cuDeviceGetByPCIBusId pfn_cuDeviceGetByPCIBusId;
35 static PFN_cuDevicePrimaryCtxRetain pfn_cuDevicePrimaryCtxRetain;
36 static PFN_cuDevicePrimaryCtxRelease pfn_cuDevicePrimaryCtxRelease;
37 static PFN_cuDeviceTotalMem pfn_cuDeviceTotalMem;
38 static PFN_cuDeviceGetName pfn_cuDeviceGetName;
39 static PFN_cuCtxGetApiVersion pfn_cuCtxGetApiVersion;
40 static PFN_cuCtxSetCurrent pfn_cuCtxSetCurrent;
41 static PFN_cuCtxGetCurrent pfn_cuCtxGetCurrent;
42 static PFN_cuCtxGetDevice pfn_cuCtxGetDevice;
43 static PFN_cuCtxGetExecAffinity pfn_cuCtxGetExecAffinity;
44 static PFN_cuMemAlloc pfn_cuMemAlloc;
45 static PFN_cuMemFree pfn_cuMemFree;
46 static PFN_cuMemHostRegister pfn_cuMemHostRegister;
47 static PFN_cuMemHostUnregister pfn_cuMemHostUnregister;
48 static PFN_cuMemHostGetDevicePointer pfn_cuMemHostGetDevicePointer;
49 static PFN_cuFlushGPUDirectRDMAWrites pfn_cuFlushGPUDirectRDMAWrites;
52 static unsigned int cuda_api_version;
53 static int cuda_driver_version;
56 /* NVIDIA GPU vendor */
57 #define NVIDIA_GPU_VENDOR_ID (0x10de)
59 /* NVIDIA GPU device IDs */
60 #define NVIDIA_GPU_A100_40GB_DEVICE_ID (0x20f1)
61 #define NVIDIA_GPU_A100_80GB_DEVICE_ID (0x20b5)
62 #define NVIDIA_GPU_A100_80GB_DPU_DEVICE_ID (0x20b8)
64 #define NVIDIA_GPU_A30_24GB_DEVICE_ID (0x20b7)
65 #define NVIDIA_GPU_A30_24GB_DPU_DEVICE_ID (0x20b9)
66 #define NVIDIA_GPU_A10_24GB_DEVICE_ID (0x2236)
68 #define NVIDIA_GPU_V100_32GB_SXM_DEVICE_ID (0x1db5)
69 #define NVIDIA_GPU_V100_32GB_PCIE_DEVICE_ID (0x1db6)
70 #define NVIDIA_GPU_V100_16GB_DEVICE_ID (0x1db4)
72 #define NVIDIA_GPU_T4_16GB_DEVICE_ID (0x1eb8)
74 #define CUDA_MAX_ALLOCATION_NUM 512
76 #define GPU_PAGE_SHIFT 16
77 #define GPU_PAGE_SIZE (1UL << GPU_PAGE_SHIFT)
79 RTE_LOG_REGISTER_DEFAULT(cuda_logtype, NOTICE);
81 /* NVIDIA GPU address map */
82 static const struct rte_pci_id pci_id_cuda_map[] = {
84 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
85 NVIDIA_GPU_A100_40GB_DEVICE_ID)
88 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
89 NVIDIA_GPU_A100_80GB_DEVICE_ID)
92 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
93 NVIDIA_GPU_A100_80GB_DPU_DEVICE_ID)
96 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
97 NVIDIA_GPU_A30_24GB_DEVICE_ID)
100 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
101 NVIDIA_GPU_A30_24GB_DPU_DEVICE_ID)
104 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
105 NVIDIA_GPU_A10_24GB_DEVICE_ID)
108 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
109 NVIDIA_GPU_V100_32GB_SXM_DEVICE_ID)
112 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
113 NVIDIA_GPU_V100_32GB_PCIE_DEVICE_ID)
116 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
117 NVIDIA_GPU_V100_16GB_DEVICE_ID)
120 RTE_PCI_DEVICE(NVIDIA_GPU_VENDOR_ID,
121 NVIDIA_GPU_T4_16GB_DEVICE_ID)
128 /* Device private info */
130 char gpu_name[RTE_DEV_NAME_MAX_LEN];
133 int gdr_write_ordering;
137 /* Type of memory allocated by CUDA driver */
141 GPU_REGISTERED /* Not used yet */
144 /* key associated to a memory address */
145 typedef uintptr_t cuda_ptr_key;
147 /* Single entry of the memory list */
150 CUdeviceptr ptr_orig_d;
159 struct mem_entry *prev;
160 struct mem_entry *next;
163 static struct mem_entry *mem_alloc_list_head;
164 static struct mem_entry *mem_alloc_list_tail;
165 static uint32_t mem_alloc_list_last_elem;
167 /* Load the CUDA symbols */
172 char cuda_path[1024];
174 if (getenv("CUDA_PATH_L") == NULL)
175 snprintf(cuda_path, 1024, "%s", "libcuda.so");
177 snprintf(cuda_path, 1024, "%s/%s", getenv("CUDA_PATH_L"), "libcuda.so");
179 cudalib = dlopen(cuda_path, RTLD_LAZY);
180 if (cudalib == NULL) {
181 rte_cuda_log(ERR, "Failed to find CUDA library in %s (CUDA_PATH_L=%s)",
182 cuda_path, getenv("CUDA_PATH_L"));
190 cuda_sym_func_loader(void)
195 sym_cuInit = dlsym(cudalib, "cuInit");
196 if (sym_cuInit == NULL) {
197 rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuInit");
201 sym_cuDriverGetVersion = dlsym(cudalib, "cuDriverGetVersion");
202 if (sym_cuDriverGetVersion == NULL) {
203 rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuDriverGetVersion");
207 sym_cuGetProcAddress = dlsym(cudalib, "cuGetProcAddress");
208 if (sym_cuGetProcAddress == NULL) {
209 rte_cuda_log(ERR, "Failed to load CUDA missing symbol cuGetProcAddress");
217 cuda_pfn_func_loader(void)
221 res = sym_cuGetProcAddress("cuGetErrorString",
222 (void **) (&pfn_cuGetErrorString), cuda_driver_version, 0);
224 rte_cuda_log(ERR, "Retrieve pfn_cuGetErrorString failed with %d", res);
228 res = sym_cuGetProcAddress("cuGetErrorName",
229 (void **)(&pfn_cuGetErrorName), cuda_driver_version, 0);
231 rte_cuda_log(ERR, "Retrieve pfn_cuGetErrorName failed with %d", res);
235 res = sym_cuGetProcAddress("cuPointerSetAttribute",
236 (void **)(&pfn_cuPointerSetAttribute), cuda_driver_version, 0);
238 rte_cuda_log(ERR, "Retrieve pfn_cuPointerSetAttribute failed with %d", res);
242 res = sym_cuGetProcAddress("cuDeviceGetAttribute",
243 (void **)(&pfn_cuDeviceGetAttribute), cuda_driver_version, 0);
245 rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetAttribute failed with %d", res);
249 res = sym_cuGetProcAddress("cuDeviceGetByPCIBusId",
250 (void **)(&pfn_cuDeviceGetByPCIBusId), cuda_driver_version, 0);
252 rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetByPCIBusId failed with %d", res);
256 res = sym_cuGetProcAddress("cuDeviceGetName",
257 (void **)(&pfn_cuDeviceGetName), cuda_driver_version, 0);
259 rte_cuda_log(ERR, "Retrieve pfn_cuDeviceGetName failed with %d", res);
263 res = sym_cuGetProcAddress("cuDevicePrimaryCtxRetain",
264 (void **)(&pfn_cuDevicePrimaryCtxRetain), cuda_driver_version, 0);
266 rte_cuda_log(ERR, "Retrieve pfn_cuDevicePrimaryCtxRetain failed with %d", res);
270 res = sym_cuGetProcAddress("cuDevicePrimaryCtxRelease",
271 (void **)(&pfn_cuDevicePrimaryCtxRelease), cuda_driver_version, 0);
273 rte_cuda_log(ERR, "Retrieve pfn_cuDevicePrimaryCtxRelease failed with %d", res);
277 res = sym_cuGetProcAddress("cuDeviceTotalMem",
278 (void **)(&pfn_cuDeviceTotalMem), cuda_driver_version, 0);
280 rte_cuda_log(ERR, "Retrieve pfn_cuDeviceTotalMem failed with %d", res);
284 res = sym_cuGetProcAddress("cuCtxGetApiVersion",
285 (void **)(&pfn_cuCtxGetApiVersion), cuda_driver_version, 0);
287 rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetApiVersion failed with %d", res);
291 res = sym_cuGetProcAddress("cuCtxGetDevice",
292 (void **)(&pfn_cuCtxGetDevice), cuda_driver_version, 0);
294 rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetDevice failed with %d", res);
298 res = sym_cuGetProcAddress("cuCtxSetCurrent",
299 (void **)(&pfn_cuCtxSetCurrent), cuda_driver_version, 0);
301 rte_cuda_log(ERR, "Retrieve pfn_cuCtxSetCurrent failed with %d", res);
305 res = sym_cuGetProcAddress("cuCtxGetCurrent",
306 (void **)(&pfn_cuCtxGetCurrent), cuda_driver_version, 0);
308 rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetCurrent failed with %d", res);
312 res = sym_cuGetProcAddress("cuCtxGetExecAffinity",
313 (void **)(&pfn_cuCtxGetExecAffinity), cuda_driver_version, 0);
315 rte_cuda_log(ERR, "Retrieve pfn_cuCtxGetExecAffinity failed with %d", res);
319 res = sym_cuGetProcAddress("cuMemAlloc",
320 (void **)(&pfn_cuMemAlloc), cuda_driver_version, 0);
322 rte_cuda_log(ERR, "Retrieve pfn_cuMemAlloc failed with %d", res);
326 res = sym_cuGetProcAddress("cuMemFree",
327 (void **)(&pfn_cuMemFree), cuda_driver_version, 0);
329 rte_cuda_log(ERR, "Retrieve pfn_cuMemFree failed with %d", res);
333 res = sym_cuGetProcAddress("cuMemHostRegister",
334 (void **)(&pfn_cuMemHostRegister), cuda_driver_version, 0);
336 rte_cuda_log(ERR, "Retrieve pfn_cuMemHostRegister failed with %d", res);
340 res = sym_cuGetProcAddress("cuMemHostUnregister",
341 (void **)(&pfn_cuMemHostUnregister), cuda_driver_version, 0);
343 rte_cuda_log(ERR, "Retrieve pfn_cuMemHostUnregister failed with %d", res);
347 res = sym_cuGetProcAddress("cuMemHostGetDevicePointer",
348 (void **)(&pfn_cuMemHostGetDevicePointer), cuda_driver_version, 0);
350 rte_cuda_log(ERR, "Retrieve pfn_cuMemHostGetDevicePointer failed with %d", res);
354 res = sym_cuGetProcAddress("cuFlushGPUDirectRDMAWrites",
355 (void **)(&pfn_cuFlushGPUDirectRDMAWrites), cuda_driver_version, 0);
357 rte_cuda_log(ERR, "Retrieve cuFlushGPUDirectRDMAWrites failed with %d", res);
364 /* Generate a key from a memory pointer */
366 get_hash_from_ptr(void *ptr)
368 return (uintptr_t)ptr;
372 mem_list_count_item(void)
374 return mem_alloc_list_last_elem;
377 /* Initiate list of memory allocations if not done yet */
378 static struct mem_entry *
379 mem_list_add_item(void)
381 /* Initiate list of memory allocations if not done yet */
382 if (mem_alloc_list_head == NULL) {
383 mem_alloc_list_head = rte_zmalloc(NULL,
384 sizeof(struct mem_entry),
385 RTE_CACHE_LINE_SIZE);
386 if (mem_alloc_list_head == NULL) {
387 rte_cuda_log(ERR, "Failed to allocate memory for memory list");
391 mem_alloc_list_head->next = NULL;
392 mem_alloc_list_head->prev = NULL;
393 mem_alloc_list_tail = mem_alloc_list_head;
395 struct mem_entry *mem_alloc_list_cur = rte_zmalloc(NULL,
396 sizeof(struct mem_entry),
397 RTE_CACHE_LINE_SIZE);
399 if (mem_alloc_list_cur == NULL) {
400 rte_cuda_log(ERR, "Failed to allocate memory for memory list");
404 mem_alloc_list_tail->next = mem_alloc_list_cur;
405 mem_alloc_list_cur->prev = mem_alloc_list_tail;
406 mem_alloc_list_tail = mem_alloc_list_tail->next;
407 mem_alloc_list_tail->next = NULL;
410 mem_alloc_list_last_elem++;
412 return mem_alloc_list_tail;
415 static struct mem_entry *
416 mem_list_find_item(cuda_ptr_key pk)
418 struct mem_entry *mem_alloc_list_cur = NULL;
420 if (mem_alloc_list_head == NULL) {
421 rte_cuda_log(ERR, "Memory list doesn't exist");
425 if (mem_list_count_item() == 0) {
426 rte_cuda_log(ERR, "No items in memory list");
430 mem_alloc_list_cur = mem_alloc_list_head;
432 while (mem_alloc_list_cur != NULL) {
433 if (mem_alloc_list_cur->pkey == pk)
434 return mem_alloc_list_cur;
435 mem_alloc_list_cur = mem_alloc_list_cur->next;
438 return mem_alloc_list_cur;
442 mem_list_del_item(cuda_ptr_key pk)
444 struct mem_entry *mem_alloc_list_cur = NULL;
446 mem_alloc_list_cur = mem_list_find_item(pk);
447 if (mem_alloc_list_cur == NULL)
450 /* if key is in head */
451 if (mem_alloc_list_cur->prev == NULL) {
452 mem_alloc_list_head = mem_alloc_list_cur->next;
453 if (mem_alloc_list_head != NULL)
454 mem_alloc_list_head->prev = NULL;
456 mem_alloc_list_cur->prev->next = mem_alloc_list_cur->next;
457 if (mem_alloc_list_cur->next != NULL)
458 mem_alloc_list_cur->next->prev = mem_alloc_list_cur->prev;
461 rte_free(mem_alloc_list_cur);
463 mem_alloc_list_last_elem--;
469 cuda_dev_info_get(struct rte_gpu *dev, struct rte_gpu_info *info)
473 struct rte_gpu_info parent_info;
474 CUexecAffinityParam affinityPrm;
475 const char *err_string;
476 struct cuda_info *private;
477 CUcontext current_ctx;
485 /* Child initialization time probably called by rte_gpu_add_child() */
486 if (dev->mpshared->info.parent != RTE_GPU_ID_NONE &&
487 dev->mpshared->dev_private == NULL) {
488 /* Store current ctx */
489 res = pfn_cuCtxGetCurrent(¤t_ctx);
491 pfn_cuGetErrorString(res, &(err_string));
492 rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
498 /* Set child ctx as current ctx */
499 input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
500 res = pfn_cuCtxSetCurrent(input_ctx);
502 pfn_cuGetErrorString(res, &(err_string));
503 rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
514 res = pfn_cuCtxGetExecAffinity(&affinityPrm,
515 CU_EXEC_AFFINITY_TYPE_SM_COUNT);
517 pfn_cuGetErrorString(res, &(err_string));
518 rte_cuda_log(ERR, "cuCtxGetExecAffinity failed with %s",
521 dev->mpshared->info.processor_count =
522 (uint32_t)affinityPrm.param.smCount.val;
524 ret = rte_gpu_info_get(dev->mpshared->info.parent, &parent_info);
529 dev->mpshared->info.total_memory = parent_info.total_memory;
531 dev->mpshared->info.page_size = parent_info.page_size;
534 * GPU Device private info
536 dev->mpshared->dev_private = rte_zmalloc(NULL,
537 sizeof(struct cuda_info),
538 RTE_CACHE_LINE_SIZE);
539 if (dev->mpshared->dev_private == NULL) {
540 rte_cuda_log(ERR, "Failed to allocate memory for GPU process private");
545 private = (struct cuda_info *)dev->mpshared->dev_private;
547 res = pfn_cuCtxGetDevice(&(private->cu_dev));
549 pfn_cuGetErrorString(res, &(err_string));
550 rte_cuda_log(ERR, "cuCtxGetDevice failed with %s",
556 res = pfn_cuDeviceGetName(private->gpu_name,
557 RTE_DEV_NAME_MAX_LEN, private->cu_dev);
559 pfn_cuGetErrorString(res, &(err_string));
560 rte_cuda_log(ERR, "cuDeviceGetName failed with %s",
566 /* Restore original ctx as current ctx */
567 res = pfn_cuCtxSetCurrent(current_ctx);
569 pfn_cuGetErrorString(res, &(err_string));
570 rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
577 *info = dev->mpshared->info;
587 cuda_mem_alloc(struct rte_gpu *dev, size_t size, unsigned int align, void **ptr)
590 const char *err_string;
591 CUcontext current_ctx;
593 unsigned int flag = 1;
598 /* Store current ctx */
599 res = pfn_cuCtxGetCurrent(¤t_ctx);
601 pfn_cuGetErrorString(res, &(err_string));
602 rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
608 /* Set child ctx as current ctx */
609 input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
610 res = pfn_cuCtxSetCurrent(input_ctx);
612 pfn_cuGetErrorString(res, &(err_string));
613 rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
619 /* Get next memory list item */
620 mem_alloc_list_tail = mem_list_add_item();
621 if (mem_alloc_list_tail == NULL) {
626 /* Allocate memory */
627 mem_alloc_list_tail->size = size;
628 mem_alloc_list_tail->size_orig = size + align;
630 res = pfn_cuMemAlloc(&(mem_alloc_list_tail->ptr_orig_d),
631 mem_alloc_list_tail->size_orig);
633 pfn_cuGetErrorString(res, &(err_string));
634 rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
640 /* Align memory address */
641 mem_alloc_list_tail->ptr_d = mem_alloc_list_tail->ptr_orig_d;
642 if (align && ((uintptr_t)mem_alloc_list_tail->ptr_d) % align)
643 mem_alloc_list_tail->ptr_d += (align -
644 (((uintptr_t)mem_alloc_list_tail->ptr_d) % align));
646 /* GPUDirect RDMA attribute required */
647 res = pfn_cuPointerSetAttribute(&flag,
648 CU_POINTER_ATTRIBUTE_SYNC_MEMOPS,
649 mem_alloc_list_tail->ptr_d);
651 rte_cuda_log(ERR, "Could not set SYNC MEMOP attribute for "
652 "GPU memory at %"PRIu32", err %d",
653 (uint32_t)mem_alloc_list_tail->ptr_d, res);
658 mem_alloc_list_tail->pkey = get_hash_from_ptr((void *)mem_alloc_list_tail->ptr_d);
659 mem_alloc_list_tail->ptr_h = NULL;
660 mem_alloc_list_tail->dev = dev;
661 mem_alloc_list_tail->ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
662 mem_alloc_list_tail->mtype = GPU_MEM;
664 /* Restore original ctx as current ctx */
665 res = pfn_cuCtxSetCurrent(current_ctx);
667 pfn_cuGetErrorString(res, &(err_string));
668 rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
674 *ptr = (void *)mem_alloc_list_tail->ptr_d;
680 cuda_mem_register(struct rte_gpu *dev, size_t size, void *ptr)
683 const char *err_string;
684 CUcontext current_ctx;
686 unsigned int flag = 1;
692 /* Store current ctx */
693 res = pfn_cuCtxGetCurrent(¤t_ctx);
695 pfn_cuGetErrorString(res, &(err_string));
696 rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
702 /* Set child ctx as current ctx */
703 input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
704 res = pfn_cuCtxSetCurrent(input_ctx);
706 pfn_cuGetErrorString(res, &(err_string));
707 rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
713 /* Get next memory list item */
714 mem_alloc_list_tail = mem_list_add_item();
715 if (mem_alloc_list_tail == NULL) {
720 /* Allocate memory */
721 mem_alloc_list_tail->size = size;
722 mem_alloc_list_tail->ptr_h = ptr;
724 res = pfn_cuMemHostRegister(mem_alloc_list_tail->ptr_h,
725 mem_alloc_list_tail->size,
726 CU_MEMHOSTREGISTER_PORTABLE |
727 CU_MEMHOSTREGISTER_DEVICEMAP);
729 pfn_cuGetErrorString(res, &(err_string));
730 rte_cuda_log(ERR, "cuMemHostRegister failed with %s ptr %p size %zd",
732 mem_alloc_list_tail->ptr_h,
733 mem_alloc_list_tail->size);
738 res = pfn_cuDeviceGetAttribute(&(use_ptr_h),
739 CU_DEVICE_ATTRIBUTE_CAN_USE_HOST_POINTER_FOR_REGISTERED_MEM,
740 ((struct cuda_info *)(dev->mpshared->dev_private))->cu_dev);
742 pfn_cuGetErrorString(res, &(err_string));
743 rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
749 if (use_ptr_h == 0) {
750 res = pfn_cuMemHostGetDevicePointer(&(mem_alloc_list_tail->ptr_d),
751 mem_alloc_list_tail->ptr_h, 0);
753 pfn_cuGetErrorString(res, &(err_string));
754 rte_cuda_log(ERR, "cuMemHostGetDevicePointer failed with %s",
760 if ((uintptr_t)mem_alloc_list_tail->ptr_d !=
761 (uintptr_t)mem_alloc_list_tail->ptr_h) {
762 rte_cuda_log(ERR, "Host input pointer is different wrt GPU registered pointer");
767 mem_alloc_list_tail->ptr_d = (CUdeviceptr)mem_alloc_list_tail->ptr_h;
770 /* GPUDirect RDMA attribute required */
771 res = pfn_cuPointerSetAttribute(&flag,
772 CU_POINTER_ATTRIBUTE_SYNC_MEMOPS,
773 mem_alloc_list_tail->ptr_d);
775 rte_cuda_log(ERR, "Could not set SYNC MEMOP attribute for GPU memory at %"PRIu32
776 ", err %d", (uint32_t)mem_alloc_list_tail->ptr_d, res);
781 mem_alloc_list_tail->pkey = get_hash_from_ptr((void *)mem_alloc_list_tail->ptr_h);
782 mem_alloc_list_tail->size = size;
783 mem_alloc_list_tail->dev = dev;
784 mem_alloc_list_tail->ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
785 mem_alloc_list_tail->mtype = CPU_REGISTERED;
786 mem_alloc_list_tail->ptr_orig_d = mem_alloc_list_tail->ptr_d;
788 /* Restore original ctx as current ctx */
789 res = pfn_cuCtxSetCurrent(current_ctx);
791 pfn_cuGetErrorString(res, &(err_string));
792 rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
802 cuda_mem_cpu_map(struct rte_gpu *dev, __rte_unused size_t size, void *ptr_in, void **ptr_out)
804 struct mem_entry *mem_item;
810 hk = get_hash_from_ptr((void *)ptr_in);
812 mem_item = mem_list_find_item(hk);
813 if (mem_item == NULL) {
814 rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory.", ptr_in);
819 if (mem_item->mtype != GPU_MEM) {
820 rte_cuda_log(ERR, "Memory address 0x%p is not GPU memory type.", ptr_in);
825 if (mem_item->size != size)
826 rte_cuda_log(WARNING,
827 "Can't expose memory area with size (%zd) different from original size (%zd).",
828 size, mem_item->size);
830 if (gdrcopy_pin(&gdrc_h, &(mem_item->mh), (uint64_t)mem_item->ptr_d,
831 mem_item->size, &(mem_item->ptr_h))) {
832 rte_cuda_log(ERR, "Error exposing GPU memory address 0x%p.", ptr_in);
837 *ptr_out = mem_item->ptr_h;
843 cuda_mem_free(struct rte_gpu *dev, void *ptr)
846 struct mem_entry *mem_item;
847 const char *err_string;
853 hk = get_hash_from_ptr((void *)ptr);
855 mem_item = mem_list_find_item(hk);
856 if (mem_item == NULL) {
857 rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory", ptr);
862 if (mem_item->mtype == GPU_MEM) {
863 res = pfn_cuMemFree(mem_item->ptr_orig_d);
865 pfn_cuGetErrorString(res, &(err_string));
866 rte_cuda_log(ERR, "cuMemFree current failed with %s",
872 return mem_list_del_item(hk);
875 rte_cuda_log(ERR, "Memory type %d not supported", mem_item->mtype);
881 cuda_mem_unregister(struct rte_gpu *dev, void *ptr)
884 struct mem_entry *mem_item;
885 const char *err_string;
891 hk = get_hash_from_ptr((void *)ptr);
893 mem_item = mem_list_find_item(hk);
894 if (mem_item == NULL) {
895 rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory", ptr);
900 if (mem_item->mtype == CPU_REGISTERED) {
901 res = pfn_cuMemHostUnregister(ptr);
903 pfn_cuGetErrorString(res, &(err_string));
904 rte_cuda_log(ERR, "cuMemHostUnregister current failed with %s",
910 return mem_list_del_item(hk);
913 rte_cuda_log(ERR, "Memory type %d not supported", mem_item->mtype);
920 cuda_mem_cpu_unmap(struct rte_gpu *dev, void *ptr_in)
922 struct mem_entry *mem_item;
928 hk = get_hash_from_ptr((void *)ptr_in);
930 mem_item = mem_list_find_item(hk);
931 if (mem_item == NULL) {
932 rte_cuda_log(ERR, "Memory address 0x%p not found in driver memory.", ptr_in);
937 if (gdrcopy_unpin(gdrc_h, mem_item->mh, (void *)mem_item->ptr_d,
939 rte_cuda_log(ERR, "Error unexposing GPU memory address 0x%p.", ptr_in);
948 cuda_dev_close(struct rte_gpu *dev)
953 rte_free(dev->mpshared->dev_private);
959 cuda_wmb(struct rte_gpu *dev)
962 const char *err_string;
963 CUcontext current_ctx;
965 struct cuda_info *private;
972 private = (struct cuda_info *)dev->mpshared->dev_private;
974 if (private->gdr_write_ordering != CU_GPU_DIRECT_RDMA_WRITES_ORDERING_NONE) {
976 * No need to explicitly force the write ordering because
977 * the device natively supports it
982 if (private->gdr_flush_type != CU_FLUSH_GPU_DIRECT_RDMA_WRITES_OPTION_HOST) {
984 * Can't flush GDR writes with cuFlushGPUDirectRDMAWrites CUDA function.
985 * Application needs to use alternative methods.
987 rte_cuda_log(WARNING, "Can't flush GDR writes with cuFlushGPUDirectRDMAWrites CUDA function."
988 "Application needs to use alternative methods.");
994 /* Store current ctx */
995 res = pfn_cuCtxGetCurrent(¤t_ctx);
997 pfn_cuGetErrorString(res, &(err_string));
998 rte_cuda_log(ERR, "cuCtxGetCurrent failed with %s",
1004 /* Set child ctx as current ctx */
1005 input_ctx = (CUcontext)((uintptr_t)dev->mpshared->info.context);
1006 res = pfn_cuCtxSetCurrent(input_ctx);
1008 pfn_cuGetErrorString(res, &(err_string));
1009 rte_cuda_log(ERR, "cuCtxSetCurrent input failed with %s",
1015 res = pfn_cuFlushGPUDirectRDMAWrites(CU_FLUSH_GPU_DIRECT_RDMA_WRITES_TARGET_CURRENT_CTX,
1016 CU_FLUSH_GPU_DIRECT_RDMA_WRITES_TO_ALL_DEVICES);
1018 pfn_cuGetErrorString(res, &(err_string));
1019 rte_cuda_log(ERR, "cuFlushGPUDirectRDMAWrites current failed with %s",
1025 /* Restore original ctx as current ctx */
1026 res = pfn_cuCtxSetCurrent(current_ctx);
1028 pfn_cuGetErrorString(res, &(err_string));
1029 rte_cuda_log(ERR, "cuCtxSetCurrent current failed with %s",
1039 cuda_gpu_probe(__rte_unused struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
1041 struct rte_gpu *dev = NULL;
1045 char dev_name[RTE_DEV_NAME_MAX_LEN];
1046 const char *err_string;
1047 int processor_count = 0;
1048 struct cuda_info *private;
1050 if (pci_dev == NULL) {
1051 rte_cuda_log(ERR, "NULL PCI device");
1056 rte_pci_device_name(&pci_dev->addr, dev_name, sizeof(dev_name));
1058 /* Allocate memory to be used privately by drivers */
1059 dev = rte_gpu_allocate(pci_dev->device.name);
1065 /* Initialize values only for the first CUDA driver call */
1066 if (dev->mpshared->info.dev_id == 0) {
1067 mem_alloc_list_head = NULL;
1068 mem_alloc_list_tail = NULL;
1069 mem_alloc_list_last_elem = 0;
1071 /* Load libcuda.so library */
1072 if (cuda_loader()) {
1073 rte_cuda_log(ERR, "CUDA Driver library not found");
1074 rte_errno = ENOTSUP;
1078 /* Load initial CUDA functions */
1079 if (cuda_sym_func_loader()) {
1080 rte_cuda_log(ERR, "CUDA functions not found in library");
1081 rte_errno = ENOTSUP;
1086 * Required to initialize the CUDA Driver.
1087 * Multiple calls of cuInit() will return immediately
1088 * without making any relevant change
1092 res = sym_cuDriverGetVersion(&cuda_driver_version);
1094 rte_cuda_log(ERR, "cuDriverGetVersion failed with %d", res);
1095 rte_errno = ENOTSUP;
1099 if (cuda_driver_version < CUDA_DRIVER_MIN_VERSION) {
1100 rte_cuda_log(ERR, "CUDA Driver version found is %d. "
1101 "Minimum requirement is %d",
1102 cuda_driver_version,
1103 CUDA_DRIVER_MIN_VERSION);
1104 rte_errno = ENOTSUP;
1108 if (cuda_pfn_func_loader()) {
1109 rte_cuda_log(ERR, "CUDA PFN functions not found in library");
1110 rte_errno = ENOTSUP;
1117 /* Fill HW specific part of device structure */
1118 dev->device = &pci_dev->device;
1119 dev->mpshared->info.numa_node = pci_dev->device.numa_node;
1121 /* Get NVIDIA GPU Device descriptor */
1122 res = pfn_cuDeviceGetByPCIBusId(&cu_dev_id, dev->device->name);
1124 pfn_cuGetErrorString(res, &(err_string));
1125 rte_cuda_log(ERR, "cuDeviceGetByPCIBusId name %s failed with %d: %s",
1126 dev->device->name, res, err_string);
1131 res = pfn_cuDevicePrimaryCtxRetain(&pctx, cu_dev_id);
1133 pfn_cuGetErrorString(res, &(err_string));
1134 rte_cuda_log(ERR, "cuDevicePrimaryCtxRetain name %s failed with %d: %s",
1135 dev->device->name, res, err_string);
1140 res = pfn_cuCtxGetApiVersion(pctx, &cuda_api_version);
1142 rte_cuda_log(ERR, "cuCtxGetApiVersion failed with %d", res);
1143 rte_errno = ENOTSUP;
1147 if (cuda_api_version < CUDA_API_MIN_VERSION) {
1148 rte_cuda_log(ERR, "CUDA API version found is %d Minimum requirement is %d",
1149 cuda_api_version, CUDA_API_MIN_VERSION);
1150 rte_errno = ENOTSUP;
1154 dev->mpshared->info.context = (uint64_t)pctx;
1157 * GPU Device generic info
1160 /* Processor count */
1161 res = pfn_cuDeviceGetAttribute(&(processor_count),
1162 CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
1165 pfn_cuGetErrorString(res, &(err_string));
1166 rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
1171 dev->mpshared->info.processor_count = (uint32_t)processor_count;
1174 res = pfn_cuDeviceTotalMem(&dev->mpshared->info.total_memory, cu_dev_id);
1176 pfn_cuGetErrorString(res, &(err_string));
1177 rte_cuda_log(ERR, "cuDeviceTotalMem failed with %s",
1183 dev->mpshared->info.page_size = (size_t)GPU_PAGE_SIZE;
1186 * GPU Device private info
1188 dev->mpshared->dev_private = rte_zmalloc(NULL,
1189 sizeof(struct cuda_info),
1190 RTE_CACHE_LINE_SIZE);
1191 if (dev->mpshared->dev_private == NULL) {
1192 rte_cuda_log(ERR, "Failed to allocate memory for GPU process private");
1197 private = (struct cuda_info *)dev->mpshared->dev_private;
1198 private->cu_dev = cu_dev_id;
1199 res = pfn_cuDeviceGetName(private->gpu_name,
1200 RTE_DEV_NAME_MAX_LEN,
1203 pfn_cuGetErrorString(res, &(err_string));
1204 rte_cuda_log(ERR, "cuDeviceGetName failed with %s",
1210 res = pfn_cuDeviceGetAttribute(&(private->gdr_supported),
1211 CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_SUPPORTED,
1214 pfn_cuGetErrorString(res, &(err_string));
1215 rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
1221 if (private->gdr_supported == 0)
1222 rte_cuda_log(WARNING, "GPU %s doesn't support GPUDirect RDMA",
1223 pci_dev->device.name);
1225 res = pfn_cuDeviceGetAttribute(&(private->gdr_write_ordering),
1226 CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_WRITES_ORDERING,
1229 pfn_cuGetErrorString(res, &(err_string));
1231 "cuDeviceGetAttribute failed with %s",
1237 if (private->gdr_write_ordering == CU_GPU_DIRECT_RDMA_WRITES_ORDERING_NONE) {
1238 res = pfn_cuDeviceGetAttribute(&(private->gdr_flush_type),
1239 CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_FLUSH_WRITES_OPTIONS,
1242 pfn_cuGetErrorString(res, &(err_string));
1243 rte_cuda_log(ERR, "cuDeviceGetAttribute failed with %s",
1249 if (private->gdr_flush_type != CU_FLUSH_GPU_DIRECT_RDMA_WRITES_OPTION_HOST)
1250 rte_cuda_log(ERR, "GPUDirect RDMA flush writes API is not supported");
1253 dev->ops.dev_info_get = cuda_dev_info_get;
1254 dev->ops.dev_close = cuda_dev_close;
1255 dev->ops.mem_alloc = cuda_mem_alloc;
1256 dev->ops.mem_free = cuda_mem_free;
1257 dev->ops.mem_register = cuda_mem_register;
1258 dev->ops.mem_unregister = cuda_mem_unregister;
1259 dev->ops.mem_cpu_map = cuda_mem_cpu_map;
1260 dev->ops.mem_cpu_unmap = cuda_mem_cpu_unmap;
1261 dev->ops.wmb = cuda_wmb;
1263 rte_gpu_complete_new(dev);
1265 rte_cuda_debug("dev id = %u name = %s",
1266 dev->mpshared->info.dev_id, private->gpu_name);
1272 cuda_gpu_remove(struct rte_pci_device *pci_dev)
1274 struct rte_gpu *dev;
1278 if (pci_dev == NULL) {
1283 dev = rte_gpu_get_by_name(pci_dev->device.name);
1285 rte_cuda_log(ERR, "Couldn't find HW dev \"%s\" to uninitialise it",
1286 pci_dev->device.name);
1290 gpu_id = dev->mpshared->info.dev_id;
1292 /* release dev from library */
1293 ret = rte_gpu_release(dev);
1295 rte_cuda_log(ERR, "Device %i failed to uninit: %i", gpu_id, ret);
1297 rte_cuda_debug("Destroyed dev = %u", gpu_id);
1302 static struct rte_pci_driver rte_cuda_driver = {
1303 .id_table = pci_id_cuda_map,
1304 .drv_flags = RTE_PCI_DRV_WC_ACTIVATE,
1305 .probe = cuda_gpu_probe,
1306 .remove = cuda_gpu_remove,
1309 RTE_PMD_REGISTER_PCI(gpu_cuda, rte_cuda_driver);
1310 RTE_PMD_REGISTER_PCI_TABLE(gpu_cuda, pci_id_cuda_map);
1311 RTE_PMD_REGISTER_KMOD_DEP(gpu_cuda, "* nvidia & (nv_peer_mem | nvpeer_mem)");