From 9f808859df2159a877b0c47822248b4b17d513aa Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Tue, 22 Jul 2025 16:31:59 +0530 Subject: [PATCH 1/4] libdfx: Add optional CMA file support to dma allocation and init APIs Introduces optional support for specifying a custom CMA file path for DMA buffer allocation. The following changes are made: - Updated `dfx_cfg_init()` and `dfx_cfg_init_file()` to accept an optional `cma_file` parameter using variadic arguments (`va_list`), maintaining backward compatibility with existing calls. - Modified `dfx_cfg_init_common()` and `dfx_package_load_dmabuf()` to accept and pass through the `cma_file` pointer. - Refactored `open_device()` to try opening the provided `cma_file`, and fall back to default `/dev/dma_heap/*` paths if not provided. - Extended `dma_buffer_info` struct to include `cma_file` as a member. - Updated `export_dma_buffer()` to pass `cma_file` from `dma_data`. These changes allow users to override the default DMA heap path during runtime configuration, offering greater flexibility across different platforms or reserved memory configurations. Signed-off-by: Nava kishore Manne --- src/dmabuf_alloc.c | 39 +++++++++++++++++------ src/include/dmabuf_alloc.h | 1 + src/include/libdfx.h | 5 +-- src/libdfx.c | 63 ++++++++++++++++++++++++++++++-------- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/dmabuf_alloc.c b/src/dmabuf_alloc.c index 9b4175b..25fea77 100644 --- a/src/dmabuf_alloc.c +++ b/src/dmabuf_alloc.c @@ -17,21 +17,42 @@ #include "dmabuf_alloc.h" #include "dma-heap.h" -static int open_device (int *devfd) +#include +#include +#include + +static int open_device(const char *cma_file, int *devfd) { - *devfd = open("/dev/dma_heap/reserved", O_RDWR); - if (*devfd >= 0) { - return 0; - } else { - *devfd = open("/dev/dma_heap/cma_reserved@800000000", O_RDWR); - if (*devfd >= 0) { + if (!devfd) { + printf("%s: Invalid devfd pointer\n", __func__); + return -1; + } + + // Try user-provided file if available + if (cma_file != NULL) { + *devfd = open(cma_file, O_RDWR); + if (*devfd >= 0) return 0; - } } + // Try default device paths + const char *fallback_paths[] = { + "/dev/dma_heap/reserved", + "/dev/dma_heap/cma_reserved@800000000" + }; + + for (int i = 0; i < sizeof(fallback_paths)/sizeof(fallback_paths[0]); ++i) { + *devfd = open(fallback_paths[i], O_RDWR); + if (*devfd >= 0) + return 0; + } + + printf("%s: Failed to open any device\n", __func__); + return -1; } + static int alloc_dma_buffer(struct dma_buffer_info *dma_data) { struct dma_heap_allocation_data alloc_data_info = { @@ -84,7 +105,7 @@ int export_dma_buffer(struct dma_buffer_info *dma_data) return -1; } - ret = open_device(&devfd); + ret = open_device(dma_data->cma_file, &devfd); if (ret) return ret; diff --git a/src/include/dmabuf_alloc.h b/src/include/dmabuf_alloc.h index 64bce26..16ce2dd 100644 --- a/src/include/dmabuf_alloc.h +++ b/src/include/dmabuf_alloc.h @@ -14,6 +14,7 @@ struct dma_buffer_info { int devfd; int dma_buffd; + const char *cma_file; unsigned char *dma_buffer; unsigned long dma_buflen; }; diff --git a/src/include/libdfx.h b/src/include/libdfx.h index 78065d7..0eb7238 100644 --- a/src/include/libdfx.h +++ b/src/include/libdfx.h @@ -73,7 +73,8 @@ int dfx_cfg_init(const char *dfx_package_path, - const char *devpath, unsigned long flags); + const char *devpath, unsigned long flags, + ...); int dfx_cfg_load(int package_id); int dfx_cfg_drivers_load(int package_id); int dfx_cfg_remove(int package_id); @@ -82,5 +83,5 @@ int dfx_get_active_uid_list(int *buffer); int dfx_get_meta_header(char *binfile, int *buffer, int buf_size); int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, - const char *devpath, unsigned long flags); + const char *devpath, unsigned long flags, ...); #endif diff --git a/src/libdfx.c b/src/libdfx.c index 7d44bfb..8e4cf56 100644 --- a/src/libdfx.c +++ b/src/libdfx.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -111,15 +112,17 @@ static struct dfx_package_node *get_package(int package_id); static int destroy_package(int package_id); static int read_package_folder(struct dfx_package_node *package_node); static int dfx_state(char *cmd, char *state); -static int dfx_package_load_dmabuf(struct dfx_package_node *package_node); +static int dfx_package_load_dmabuf(struct dfx_package_node *package_node, + const char *cma_file); static int dfx_getplatform(void); static int find_key(struct dfx_package_node *package_node); static int lengthOfLastWord2(const char *input); static void strlwr(char *destination, const char *source); static int dfx_get_error(char *cmd); static void zynqmp_print_err_msg(int err); -static int dfx_cfg_init_common(const char *dfx_package_path, const char *dfx_bin_file, - const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, +static int dfx_cfg_init_common(const char *dfx_package_path, const char *cma_file, + const char *dfx_bin_file, const char *dfx_dtbo_file, + const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, const char *devpath, unsigned long flags); static int read_package_byname(struct dfx_package_node *package_node, @@ -149,13 +152,21 @@ static inline double gettime(struct timeval t0, struct timeval t1); * where N is the interface-device number. * unsigned long flags: Flags to specify any special instructions for library * to perform. + * Optional parameters (using variadic arguments): + * char *cma_file: (Optional) Custom CMA file path for DMA buffer allocation. + * If NULL or not provided, defaults to standard paths: + * "/dev/dma_heap/reserved" or "/dev/dma_heap/cma_reserved@800000000" * * Return: returns unique package_Id, or Error code on failure. */ int dfx_cfg_init(const char *dfx_package_path, - const char *devpath, unsigned long flags) + const char *devpath, unsigned long flags, + ...) { int ret = 0; + va_list args; + const char *cma_file = NULL; + #ifdef ENABLE_LIBDFX_TIME struct timeval t1, t0; double time; @@ -168,8 +179,15 @@ int dfx_cfg_init(const char *dfx_package_path, return -DFX_INVALID_PARAM; } - ret = dfx_cfg_init_common(dfx_package_path, NULL, NULL, NULL, NULL, - devpath, flags); + va_start(args, flags); + + // Attempt to fetch next arg (optional cma_file) + cma_file = va_arg(args, const char *); + + va_end(args); + + ret = dfx_cfg_init_common(dfx_package_path, cma_file, NULL, NULL, + NULL, NULL, devpath, flags); #ifdef ENABLE_LIBDFX_TIME gettimeofday(&t1, NULL); @@ -203,6 +221,11 @@ int dfx_cfg_init(const char *dfx_package_path, * char *devpath: The dev interface is exposed at /dev/fpga-deviceN. * Where N is the interface-device number. * + * Optional parameters (using variadic arguments): + * char *cma_file: (Optional) Custom CMA file path for DMA buffer allocation. + * If NULL or not provided, defaults to standard paths: + * "/dev/dma_heap/reserved" or "/dev/dma_heap/cma_reserved@800000000" + * * unsigned long flags: Flags to specify any special instructions for the * library to perform. * @@ -210,9 +233,11 @@ int dfx_cfg_init(const char *dfx_package_path, */ int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, - const char *devpath, unsigned long flags) + const char *devpath, unsigned long flags, ...) { + va_list args; int len, ret = 0; + const char *cma_file = NULL; #ifdef ENABLE_LIBDFX_TIME struct timeval t1, t0; double time; @@ -228,7 +253,14 @@ int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, return ret; } - ret = dfx_cfg_init_common(NULL, dfx_bin_file, dfx_dtbo_file, + va_start(args, flags); + + // Attempt to fetch next arg (optional cma_file) + cma_file = va_arg(args, const char *); + + va_end(args); + + ret = dfx_cfg_init_common(NULL, cma_file, dfx_bin_file, dfx_dtbo_file, dfx_driver_dtbo_file, dfx_aes_key_file, devpath, flags); #ifdef ENABLE_LIBDFX_TIME @@ -1013,7 +1045,8 @@ static int dfx_get_error(char *cmd) return (int)strtol(string, NULL, 0); } -static int dfx_package_load_dmabuf(struct dfx_package_node *package_node) +static int dfx_package_load_dmabuf(struct dfx_package_node *package_node, + const char *cma_file) { int word_align = 0, index, fd, ret; struct dma_buf_sync sync = { 0 }; @@ -1044,6 +1077,7 @@ static int dfx_package_load_dmabuf(struct dfx_package_node *package_node) package_node->dmabuf_info = (struct dma_buffer_info *) calloc(1, sizeof(struct dma_buffer_info)); package_node->dmabuf_info->dma_buflen = fileLen; + package_node->dmabuf_info->cma_file = cma_file; /* This call will do the following things * 1. Allocate memory from the DMA pool and return a valid buffer fd @@ -1207,9 +1241,12 @@ static void zynqmp_print_err_msg(int err) printf("\r\n"); } -static int dfx_cfg_init_common(const char *dfx_package_path, const char *dfx_bin_file, - const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, - const char *dfx_aes_key_file, const char *devpath, +static int dfx_cfg_init_common(const char *dfx_package_path, + const char *cma_file, const char *dfx_bin_file, + const char *dfx_dtbo_file, + const char *dfx_driver_dtbo_file, + const char *dfx_aes_key_file, + const char *devpath, unsigned long flags) { FPGA_NODE *package_node; @@ -1272,7 +1309,7 @@ static int dfx_cfg_init_common(const char *dfx_package_path, const char *dfx_bin } if (!(flags & DFX_EXTERNAL_CONFIG_EN)) { - ret = dfx_package_load_dmabuf(package_node); + ret = dfx_package_load_dmabuf(package_node, cma_file); if (ret) { printf("%s: load dmabuf failed\r\n", __func__); goto destroy_package; From 10df4cf5b1d604a02f3c06859987ed77110b5d3a Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Thu, 31 Jul 2025 13:07:12 +0530 Subject: [PATCH 2/4] doc: update README to document optional custom CMA file support in libdfx The README has been updated to explain how you can optionally use a custom CMA (Contiguous Memory Allocator) file in libdfx. By default, the library uses standard DMA heap paths like /dev/dma_heap/reserved or /dev/dma_heap/cma_reserved@800000000. If a custom CMA file path is provided and fails to open, it will fall back to the default. The update includes simple examples showing how to use this feature with dfx_cfg_init() and dfx_cfg_init_file(). This option is useful for platforms with specific DMA buffer setup needs. Signed-off-by: Nava kishore Manne --- doc/README.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/doc/README.txt b/doc/README.txt index f0501f1..0ea1800 100755 --- a/doc/README.txt +++ b/doc/README.txt @@ -178,10 +178,31 @@ removed at run-time. API Details: ============ -============================================================== +================= +CMA File Support: +================= + libdfx now supports optional custom CMA (Contiguous Memory Allocator) file +specification for DMA buffer allocation. This feature provides flexibility for +different platform configurations and reserved memory setups. + +Default DMA Heap Paths: + - /dev/dma_heap/reserved + - /dev/dma_heap/cma_reserved@800000000 + +Custom CMA File Usage: + - Users can specify a custom CMA file path as an optional parameter + - If provided, libdfx will attempt to use the custom path first + - If the custom path fails, it falls back to default paths + - This allows for platform-specific memory configurations + +Examples of custom CMA paths: + - /dev/dma_heap/custom_cma + - /dev/dma_heap/cma_reserved@specific_address + - /dev/dma_heap/platform_specific_heap +=================================================================  -pre-fetch:  dfx_cfg_init (const char *dfx_package_path, - const char *devpath, u32 flags); -============================================================== + const char *devpath, u32 flags, ...); +================================================================= /* Provide a generic interface to the user to specify the required parameters * for PR programming. @@ -199,6 +220,11 @@ API Details: * unsigned long flags: Flags to specify any special instructions for library * to perform. * + * Optional parameters (using variadic arguments): + * char *cma_file: (Optional) Custom CMA file path for DMA buffer allocation. + * If NULL or not provided, defaults to standard paths: + * "/dev/dma_heap/reserved" or "/dev/dma_heap/cma_reserved@800000000" + * * Return: returns unique package_Id or Error code on failure. */ @@ -219,12 +245,19 @@ package_id2 = dfx_cfg_init ("/path/package2/", "/dev/fpga0", flags); /* More code */ +/* -store /Pre-fetch data - For custom CMA file use case*/ +package_id3 = dfx_cfg_init ("/path/package3/", "/dev/fpga0", flags, + "/dev/dma_heap/custom_cma"); + +/* More code */ + ============================================================================= -pre-fetch int dfx_cfg_init_file(const char *dfx_bin_file, const char *dfx_dtbo_file, const char *dfx_driver_dtbo_file, const char *dfx_aes_key_file, - const char *devpath, unsigned long flags); + const char *devpath, + unsigned long flags, ...); ============================================================================= /* Provide a generic interface to the user to specify the required parameters @@ -255,6 +288,11 @@ package_id2 = dfx_cfg_init ("/path/package2/", "/dev/fpga0", flags); * unsigned long flags: Flags to specify any special instructions for the * library to perform. * + * Optional parameters (using variadic arguments): + * char *cma_file: (Optional) Custom CMA file path for DMA buffer allocation. + * If NULL or not provided, defaults to standard paths: + * "/dev/dma_heap/reserved" or "/dev/dma_heap/cma_reserved@800000000" + * * Return: returns unique package_Id or Error code on failure. */ @@ -287,6 +325,13 @@ package_id3 = dfx_cfg_init_file("/lib/firmware/xilinx/example/example.bin ", /dev/fpga0", flags); /* More code */ +/* -store /Pre-fetch data - For custom CMA file use case*/ +package_id4 = dfx_cfg_init_file("/lib/firmware/xilinx/example/example.bin ", + "/lib/firmware/xilinx/example/example.dtbo", + NULL, NULL, "/dev/fpga0", flags, + "/dev/dma_heap/custom_cma"); +/* More code */ + ================================================================ -fpga-load:  int dfx_cfg_load(struct dfx_package_Id package_Id) ================================================================ From 0d5a8cab8b60fd942ece54c3df9d137814575693 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Fri, 12 Sep 2025 16:37:09 +0530 Subject: [PATCH 3/4] cmake: add proper library versioning and SONAME support - Introduce semantic versioning (MAJOR.MINOR.PATCH) for libdfx. - Use VERSION and SOVERSION properties for shared library to set SONAME. - Cleaned up target properties with modern `set_target_properties`. - Added explicit install rules for headers, shared, and static libraries. - Copy `libdfx.h` to build directory for IDE support. - Ensure install of runtime targets into ${CMAKE_INSTALL_BINDIR}. Signed-off-by: Nava kishore Manne --- src/CMakeLists.txt | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a489bfb..fc64ac6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,14 @@ -#*************************************************************** +#****************************************************************************** #* Copyright (c) 2020 Xilinx, Inc. All rights reserved. -#* Copyright (C) 2023, Advanced Micro Devices, Inc. All Rights Reserved +#* Copyright (C) 2023 - 2025, Advanced Micro Devices, Inc. All Rights Reserved #* SPDX-License-Identifier: MIT -#*************************************************************** +#****************************************************************************** include(GNUInstallDirs) + # Specify the minimum version for CMake -cmake_minimum_required(VERSION 2.8.9) +cmake_minimum_required(VERSION 2.8.9) + # Project's name project(dfx) enable_language(C ASM) @@ -20,21 +22,39 @@ set(LIBDFX_INCLUDE_DIRS "include/" ) -SET(LIBDFX_VERSION 1.0) +# ---- Library versioning ---- +set(LIBDFX_VERSION_MAJOR 1) +set(LIBDFX_VERSION_MINOR 0) +set(LIBDFX_VERSION_PATCH 1) +set(LIBDFX_VERSION ${LIBDFX_VERSION_MAJOR}.${LIBDFX_VERSION_MINOR}.${LIBDFX_VERSION_PATCH}) +# Copy header to build directory for IDE support file(COPY include/libdfx.h DESTINATION ${CMAKE_BINARY_DIR}/include) +# ---- Shared library (with SONAME) ---- add_library(dfx_shared SHARED ${libdfx_sources}) -SET_TARGET_PROPERTIES(dfx_shared PROPERTIES SOVERSION ${LIBDFX_VERSION} OUTPUT_NAME "dfx") -SET_TARGET_PROPERTIES(dfx_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) +set_target_properties(dfx_shared PROPERTIES + VERSION ${LIBDFX_VERSION} + SOVERSION ${LIBDFX_VERSION_MAJOR} + OUTPUT_NAME "dfx" + CLEAN_DIRECT_OUTPUT 1 +) +# ---- Static library ---- add_library(dfx_static STATIC ${libdfx_sources}) -SET_TARGET_PROPERTIES(dfx_static PROPERTIES OUTPUT_NAME "dfx") -SET_TARGET_PROPERTIES(dfx_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) +set_target_properties(dfx_static PROPERTIES + OUTPUT_NAME "dfx" + CLEAN_DIRECT_OUTPUT 1 +) +# ---- Include directories ---- target_include_directories(dfx_shared PUBLIC ${LIBDFX_INCLUDE_DIRS}) target_include_directories(dfx_static PUBLIC ${LIBDFX_INCLUDE_DIRS}) + +# ---- Install rules ---- install(FILES "include/libdfx.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -install(TARGETS dfx_shared; dfx_static - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install(TARGETS dfx_shared dfx_static + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) From 6356fdea7bf3c293edaa813b6c61427139a4ca22 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Wed, 29 Oct 2025 13:10:49 +0530 Subject: [PATCH 4/4] libdfx: Add support to dynamically detect and open CMA heap files Updates open_device() to provide dynamic and reliable handling of CMA heaps under /dev/dma_heap. It now scans for any cma_reserved@* node and opens it only if the corresponding device tree node has the linux,cma-default property, verified via the new helper function is_cma_default_node(). This ensures that only valid, default CMA heaps are used. Signed-off-by: Nava kishore Manne --- src/dmabuf_alloc.c | 58 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/dmabuf_alloc.c b/src/dmabuf_alloc.c index 25fea77..f2069e3 100644 --- a/src/dmabuf_alloc.c +++ b/src/dmabuf_alloc.c @@ -17,10 +17,24 @@ #include "dmabuf_alloc.h" #include "dma-heap.h" +#include +#include #include #include #include +static int is_cma_default_node(const char *node_name) +{ + char path[512]; + + snprintf(path, sizeof(path), + "/sys/firmware/devicetree/base/reserved-memory/%s/linux,cma-default", + node_name); + + /* returns 1 if property exists, 0 if not */ + return (access(path, F_OK) == 0); +} + static int open_device(const char *cma_file, int *devfd) { if (!devfd) { @@ -28,31 +42,49 @@ static int open_device(const char *cma_file, int *devfd) return -1; } - // Try user-provided file if available + // Try user-provided heap path first if (cma_file != NULL) { *devfd = open(cma_file, O_RDWR); if (*devfd >= 0) return 0; } - // Try default device paths - const char *fallback_paths[] = { - "/dev/dma_heap/reserved", - "/dev/dma_heap/cma_reserved@800000000" - }; - - for (int i = 0; i < sizeof(fallback_paths)/sizeof(fallback_paths[0]); ++i) { - *devfd = open(fallback_paths[i], O_RDWR); - if (*devfd >= 0) - return 0; + // Try default kernel reserved CMA heap + *devfd = open("/dev/dma_heap/reserved", O_RDWR); + if (*devfd >= 0) + return 0; + + // Dynamic scan for cma_reserved@* that also has linux,cma-default + DIR *dir = opendir("/dev/dma_heap"); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (strncmp(entry->d_name, "cma_reserved@", 13) == 0) { + + // Check if the DT node has the linux,cma-default flag + if (!is_cma_default_node(entry->d_name)) + continue; + + char path[256]; + snprintf(path, sizeof(path), + "/dev/dma_heap/%s", entry->d_name); + + *devfd = open(path, O_RDWR); + + if (*devfd >= 0) { + closedir(dir); + return 0; + } + } + } + closedir(dir); } - printf("%s: Failed to open any device\n", __func__); + printf("%s: No valid CMA heap found\n", __func__); return -1; } - static int alloc_dma_buffer(struct dma_buffer_info *dma_data) { struct dma_heap_allocation_data alloc_data_info = {