diff options
| author | Eric Dao <eric@erickhangdao.com> | 2025-03-10 17:54:31 -0400 |
|---|---|---|
| committer | Eric Dao <eric@erickhangdao.com> | 2025-03-10 17:54:31 -0400 |
| commit | ab224e2e6ba65f5a369ec392f99cd8845ad06c98 (patch) | |
| tree | a1e757e9341863ed52b8ad4c5a1c45933aab9da4 /python/openvino/runtime/coredla_device/mmd/hps_platform | |
| parent | 40da1752f2c8639186b72f6838aa415e854d0b1d (diff) | |
| download | thesis-master.tar.gz thesis-master.tar.bz2 thesis-master.zip | |
Diffstat (limited to 'python/openvino/runtime/coredla_device/mmd/hps_platform')
12 files changed, 2363 insertions, 0 deletions
diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/.gitignore b/python/openvino/runtime/coredla_device/mmd/hps_platform/.gitignore new file mode 100644 index 0000000..0948b39 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/.gitignore @@ -0,0 +1,20 @@ +*~ +*# +*.marks +release_build/ +build/ +example_designs/mem_bandwidth/bin/ +example_designs/mem_bandwidth/simulation.tar.gz +example_designs/mem_bandwidth/temp_simulation/ +linux64/lib/ +linux64/libexec/diagnose +linux64/libexec/program +ase/mpf_src +*.pyc +*.swp +*.kwlp +*.kwps +temp_simulation/ +simulation.tar.gz + +backup diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/CMakeLists.txt b/python/openvino/runtime/coredla_device/mmd/hps_platform/CMakeLists.txt new file mode 100644 index 0000000..d8bf50d --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/CMakeLists.txt @@ -0,0 +1,59 @@ +# (C) 2017 Intel Corporation. All rights reserved. +# Your use of Intel Corporation's design tools, logic functions and other +# software and tools, and its AMPP partner logic functions, and any output +# files any of the foregoing (including device programming or simulation +# files), and any associated documentation or information are expressly subject +# to the terms and conditions of the Intel Program License Subscription +# Agreement, Intel MegaCore Function License Agreement, or other applicable +# license agreement, including, without limitation, that your use is for the +# sole purpose of programming logic devices manufactured by Intel and sold by +# Intel or its authorized distributors. Please refer to the applicable +# agreement for further details. + +cmake_minimum_required(VERSION 2.8.12) +project(mmd) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") + +# DLA specific modifications made to the MMD +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDLA_MMD") + +# Select PCIE Gen3 x8 +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGEN3_x8") + +# from the opencl makefile +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL_64BIT -DOPTION3=1 -DACL_USE_DMA=1 -DACL_COMPILER_IS_MSVC=0 -Wall -Wno-unknown-pragmas -DACL_HAS_STDLIB_STDIO") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector -Wformat -Wformat-security -D_GLIBCXX_USE_CXX11_ABI=0 -fPIC -DACL_HOST_RUNTIME_IS_STATIC=0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DACL_OPENCL_HOST_SYS=linux -DACL_OPENCL_HOST_BIT=64 -DACL_TARGET_SYS=linux -DACL_TARGET_BIT=64 -DLINUX -DACL_MAX_DEVICE=128") + +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2 -O3") +enable_language(C ASM) + +set(ASM_OPTIONS "-x assembler-with-cpp") +if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") + set(ASM_OPTIONS "${ASM_OPTIONS} -no-integrated-as") +endif() + +set(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS}") + +if(RUNTIME_POLLING) + add_definitions(-DRUNTIME_POLLING) +endif(RUNTIME_POLLING) + +set(MMD_SRC + ./host/acl_hps.cpp + ./host/mmd_device.cpp + ./host/dma_device.cpp + ./host/uio_device.cpp +) + +add_library(hps_platform_mmd SHARED ${MMD_SRC}) + +target_include_directories(hps_platform_mmd PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +target_link_libraries(hps_platform_mmd) + +install(TARGETS hps_platform_mmd + LIBRARY DESTINATION lib + COMPONENT hps_platform_mmd +) diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.cpp b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.cpp new file mode 100644 index 0000000..53055ef --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.cpp @@ -0,0 +1,473 @@ +// (c) 1992-2021 Intel Corporation. +// Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words +// and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. +// and/or other countries. Other marks and brands may be claimed as the property +// of others. See Trademarks on intel.com for full list of Intel trademarks or +// the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) +// Your use of Intel Corporation's design tools, logic functions and other +// software and tools, and its AMPP partner logic functions, and any output +// files any of the foregoing (including device programming or simulation +// files), and any associated documentation or information are expressly subject +// to the terms and conditions of the Altera Program License Subscription +// Agreement, Intel MegaCore Function License Agreement, or other applicable +// license agreement, including, without limitation, that your use is for the +// sole purpose of programming logic devices manufactured by Intel and sold by +// Intel or its authorized distributors. Please refer to the applicable +// agreement for further details. + +/* ===- HPS.cpp ------------------------------------------------- C++ -*-=== */ +/* */ +/* Intel(R) HPS MMD Driver */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions that are defined in aocl_mmd.h */ +/* */ +/* ===-------------------------------------------------------------------------=== */ + +// common and its own header files +#include "acl_hps.h" + +// other standard header files +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <memory> +#include <map> +#include <sstream> +#include <string> +#include <utility> + +#include "mmd_device.h" + +#ifdef DLA_MMD +#include <chrono> +#include <thread> +#endif + +#if defined(LINUX) +#include <fcntl.h> +#include <semaphore.h> +#include <signal.h> +#include <unistd.h> +#endif // LINUX + +#define MAX_HPS_FPGA_DEVICES (1) + +// MAX size of line read from pipe-ing the output of system call to MMD +#define BUF_SIZE 1024 +// MAX size of command passed to system for invoking system call from MMD +#define SYSTEM_CMD_SIZE 4 * 1024 + +#ifndef DLA_MMD +// static helper functions +static bool blob_has_elf_signature(void *data, size_t data_size); +#endif + + +// Function to return the number of boards installed in the system +unsigned int get_offline_num_boards() { + board_names names = mmd_get_devices(MAX_HPS_FPGA_DEVICES); + return (unsigned int)names.size(); +} + +// Get information about the board using the enum aocl_mmd_offline_info_t for +// offline info (called without a handle), and the enum aocl_mmd_info_t for +// info specific to a certain board. +#define RESULT_INT(X) \ + { \ + *((int *)param_value) = X; \ + if (param_size_ret) *param_size_ret = sizeof(int); \ + } +#define RESULT_UNSIGNED(X) \ + { \ + *((unsigned *)param_value) = X; \ + if (param_size_ret) *param_size_ret = sizeof(unsigned); \ + } +#define RESULT_SIZE_T(X) \ + { \ + *((size_t *)param_value) = X; \ + if (param_size_ret) *param_size_ret = sizeof(size_t); \ + } +#if defined(WINDOWS) +#define RESULT_STR(X) \ + do { \ + size_t Xlen = strnlen(X, MAX_NAME_SIZE) + 1; \ + memcpy_s((void *)param_value, param_value_size, X, (param_value_size <= Xlen) ? param_value_size : Xlen); \ + if (param_size_ret) *param_size_ret = Xlen; \ + } while (0) +#else +#define RESULT_STR(X) \ + do { \ + size_t Xlen = strnlen(X, MAX_NAME_SIZE) + 1; \ + memcpy((void *)param_value, X, (param_value_size <= Xlen) ? param_value_size : Xlen); \ + if (param_size_ret) *param_size_ret = Xlen; \ + } while (0) +#endif +#define ACL_VENDOR_NAME "Intel" +int aocl_mmd_get_offline_info(aocl_mmd_offline_info_t requested_info_id, + size_t param_value_size, + void *param_value, + size_t *param_size_ret) { + unsigned int num_boards; + switch (requested_info_id) { + case AOCL_MMD_VERSION: + RESULT_STR(MMD_VERSION); + break; + case AOCL_MMD_NUM_BOARDS: { + num_boards = MAX_HPS_FPGA_DEVICES; + RESULT_INT((int)num_boards); + break; + } + case AOCL_MMD_BOARD_NAMES: { + // Retrieve all the CoreDLA cores in the system + board_names names = mmd_get_devices(MAX_HPS_FPGA_DEVICES); + // Construct a list of all possible devices supported by this MMD layer + std::ostringstream board; + auto name = names.begin(); + while(name != names.end() ) + { + board << *name; + name++; + if( name != names.end() ) + { + board << ";"; + } + } + + RESULT_STR(board.str().c_str()); + break; + } + case AOCL_MMD_VENDOR_NAME: { + RESULT_STR(ACL_VENDOR_NAME); + break; + } + case AOCL_MMD_VENDOR_ID: + RESULT_INT(0); + break; + case AOCL_MMD_USES_YIELD: + RESULT_INT(0); /* TODO: Can we yield? */ + break; + case AOCL_MMD_MEM_TYPES_SUPPORTED: + RESULT_INT(AOCL_MMD_PHYSICAL_MEMORY); /* TODO: Confirm this is the right memory type */ + break; + } + return 0; +} + +// If the MMD is loaded dynamically, destructors in the MMD will execute before the destructors in the runtime +// upon program termination. The DeviceMapManager guards accesses to the device/handle maps to make sure +// the runtime doesn't get to reference them after MMD destructors have been called. +// Destructor makes sure that all devices are closed at program termination regardless of what the runtime does. +// Implemented as a singleton. +class DeviceMapManager final { +public: + typedef std::map<int, mmd_device_ptr> map_handle_to_dev_t; + ~DeviceMapManager() + { + } + + int add_device(const char *name) + { + int handle = idx++; + + mmd_device_ptr spDevice = std::make_shared<mmd_device>(name, handle); + if( spDevice->bValid() ) + { + auto it = handle_to_dev.find(handle); + HPS_ERROR_IF( it != handle_to_dev.end(), return FAILURE, "Error: Handle already used.\n" ); + handle_to_dev.insert({handle, spDevice}); + return handle; + } + return FAILURE; + } + + mmd_device_ptr get_device(const int handle) + { + auto it = handle_to_dev.find(handle); + HPS_ERROR_IF( it == handle_to_dev.end(), return nullptr, "Error: Invalid handle.\n" ); + return it->second; + } + + bool remove_device(const int handle) + { + auto it = handle_to_dev.find(handle); + HPS_ERROR_IF( it == handle_to_dev.end(), return false, "Error: Handle does not exist.\n" ); + handle_to_dev.erase(it); + return true; + } + + DeviceMapManager() + { + } +private: + map_handle_to_dev_t handle_to_dev = {}; + int idx = {0}; +}; +static DeviceMapManager _gDeviceMapManager; + +int aocl_mmd_get_info( + int handle, aocl_mmd_info_t requested_info_id, size_t param_value_size, void *param_value, size_t *param_size_ret) { + HPS_ERROR_IF(true, + return FAILURE, + "aocl_mmd_get_info not supported on platform. \n"); +} + +#undef RESULT_INT +#undef RESULT_STR + + +// Open and initialize the named device. +int AOCL_MMD_CALL aocl_mmd_open(const char *name) { + return _gDeviceMapManager.add_device(name); +} + +// Close an opened device, by its handle. +int AOCL_MMD_CALL aocl_mmd_close(int handle) { + if ( _gDeviceMapManager.remove_device(handle) ) + return SUCCESS; + return FAILURE; +} + +// Set the interrupt handler for the opened device. +int AOCL_MMD_CALL aocl_mmd_set_interrupt_handler(int handle, aocl_mmd_interrupt_handler_fn fn, void *user_data) { + mmd_device_ptr spDevice = _gDeviceMapManager.get_device(handle); + if( nullptr == spDevice ) { + return FAILURE; + } + return spDevice->set_interrupt_handler(fn, user_data); +} + +// Set the device interrupt handler for the opened device. +int AOCL_MMD_CALL aocl_mmd_set_device_interrupt_handler(int handle, + aocl_mmd_device_interrupt_handler_fn fn, + void *user_data) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + return -1; +} + +// Set the operation status handler for the opened device. +int AOCL_MMD_CALL aocl_mmd_set_status_handler(int handle, aocl_mmd_status_handler_fn fn, void *user_data) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + return -1; +} + +// Called when the host is idle and hence possibly waiting for events to be +// processed by the device +int AOCL_MMD_CALL aocl_mmd_yield(int handle) +{ + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + return -1; +} + +// Read, write and copy operations on a single interface. +int AOCL_MMD_CALL aocl_mmd_read(int handle, aocl_mmd_op_t op, size_t len, void *dst, int mmd_interface, size_t offset) { + mmd_device_ptr spDevice = _gDeviceMapManager.get_device(handle); + if( nullptr == spDevice ) { + return FAILURE; + } + return spDevice->read_block(op, mmd_interface, dst, offset, len); +} + +int AOCL_MMD_CALL +aocl_mmd_write(int handle, aocl_mmd_op_t op, size_t len, const void *src, int mmd_interface, size_t offset) { + mmd_device_ptr spDevice = _gDeviceMapManager.get_device(handle); + if( nullptr == spDevice ) { + return FAILURE; + } + return spDevice->write_block(op, mmd_interface, src, offset, len); +} + +int AOCL_MMD_CALL +aocl_mmd_copy(int handle, aocl_mmd_op_t op, size_t len, int mmd_interface, size_t src_offset, size_t dst_offset) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return -1; +} + +// Initialize host channel specified in channel_name +int AOCL_MMD_CALL aocl_mmd_hostchannel_create(int handle, char *channel_name, size_t queue_depth, int direction) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return -1; +} + +// reset the host channel specified with channel handle +int AOCL_MMD_CALL aocl_mmd_hostchannel_destroy(int handle, int channel) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return -1; +} + +// Get the pointer to buffer the user can write/read from the kernel with +AOCL_MMD_CALL void *aocl_mmd_hostchannel_get_buffer(int handle, int channel, size_t *buffer_size, int *status) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return NULL; +} + +// Acknolwedge from the user that they have written/read send_size amount of buffer obtained from get_buffer +size_t AOCL_MMD_CALL aocl_mmd_hostchannel_ack_buffer(int handle, int channel, size_t send_size, int *status) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return -1; +} + +#ifdef DLA_MMD +// Reprogram the device given the sof file name +int AOCL_MMD_CALL aocl_mmd_program_sof(int handle, const char *sof_filename) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* We don't support reprogramming the SOF on a HPS device */ + return -1; +} +#else +// Reprogram the device based on the program mode +int AOCL_MMD_CALL aocl_mmd_program(int handle, void *data, size_t data_size, aocl_mmd_program_mode_t program_mode) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* We don't support reprogramming the SOF on a HPS device */ + return -1; +} +#endif +// Shared memory allocator +AOCL_MMD_CALL void *aocl_mmd_shared_mem_alloc(int handle, size_t size, unsigned long long *device_ptr_out) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return NULL; +} + +// Shared memory de-allocator +AOCL_MMD_CALL void aocl_mmd_shared_mem_free(int handle, void *host_ptr, size_t size) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + /* Not called by CoreDLA, so not implementing */ + return; +} + +#ifndef DLA_MMD +// This function checks if the input data has an ELF-formatted blob. +// Return true when it does. +static bool blob_has_elf_signature(void *data, size_t data_size) { + bool result = false; + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + if (data && data_size > 4) { + unsigned char *cdata = (unsigned char *)data; + const unsigned char elf_signature[4] = {0177, 'E', 'L', 'F'}; // Little endian + result = (cdata[0] == elf_signature[0]) && (cdata[1] == elf_signature[1]) && (cdata[2] == elf_signature[2]) && + (cdata[3] == elf_signature[3]); + } + return result; +} +#endif + +// Return a positive number when single device open. Otherwise, return -1 +AOCL_MMD_CALL int get_open_handle() { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + return -1; +} + +AOCL_MMD_CALL void *aocl_mmd_host_alloc(int *handles, + size_t num_devices, + size_t size, + size_t alignment, + aocl_mmd_mem_properties_t *properties, + int *error) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + // Not supported on this BSP + return NULL; +} + +AOCL_MMD_CALL int aocl_mmd_free(void *mem) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + // Not supported on this BSP + return 0; +} + +AOCL_MMD_CALL void *aocl_mmd_device_alloc( + int handle, size_t size, size_t alignment, aocl_mmd_mem_properties_t *properties, int *error) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + // Not supported on this BSP + return NULL; +} + +AOCL_MMD_CALL void *aocl_mmd_shared_alloc( + int handle, size_t size, size_t alignment, aocl_mmd_mem_properties_t *properties, int *error) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + // Not supported on this BSP + return NULL; +} + +AOCL_MMD_CALL int aocl_mmd_shared_migrate(int handle, void *shared_ptr, size_t size, aocl_mmd_migrate_t destination) { + printf("%s:%s:%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__); + // Not supported on this BSP + return 0; +} + +#ifdef DLA_MMD +// Query functions to get board-specific values +AOCL_MMD_CALL int dla_mmd_get_max_num_instances() +{ + return 1; +} + +AOCL_MMD_CALL uint64_t dla_mmd_get_ddr_size_per_instance() { + return 1ULL << 29; +} + +// AGX7 HPS board uses 333.3325 MHz (1333.33/4) for the DLA DDR Clock +// All other boards use 266.666666 MHz (1066.66666/4) +AOCL_MMD_CALL double dla_mmd_get_ddr_clock_freq() { +#ifdef HPS_AGX7 + return 333.332500; +#else + return 266.666666; +#endif +} // MHz + +// Helper functions for the wrapper functions around CSR and DDR +uint64_t dla_get_raw_csr_address(int instance, uint64_t addr) { + return (0x1000 * instance) + addr; +} +uint64_t dla_get_raw_ddr_address(int instance, uint64_t addr) { + return addr; +} + +// Wrappers around CSR and DDR reads and writes to abstract away board-specific offsets +AOCL_MMD_CALL int dla_mmd_csr_write(int handle, int instance, uint64_t addr, const uint32_t *data) { + return aocl_mmd_write( + handle, NULL, sizeof(uint32_t), data, HPS_MMD_COREDLA_CSR_HANDLE, dla_get_raw_csr_address(instance, addr)); +} +AOCL_MMD_CALL int dla_mmd_csr_read(int handle, int instance, uint64_t addr, uint32_t *data) { + return aocl_mmd_read( + handle, NULL, sizeof(uint32_t), data, HPS_MMD_COREDLA_CSR_HANDLE, dla_get_raw_csr_address(instance, addr)); +} +AOCL_MMD_CALL int dla_mmd_ddr_write(int handle, int instance, uint64_t addr, uint64_t length, const void *data) { + return aocl_mmd_write(handle, NULL, length, data, HPS_MMD_MEMORY_HANDLE, dla_get_raw_ddr_address(instance, addr)); +} +AOCL_MMD_CALL int dla_mmd_ddr_read(int handle, int instance, uint64_t addr, uint64_t length, void *data) { + return aocl_mmd_read(handle, NULL, length, data, HPS_MMD_MEMORY_HANDLE, dla_get_raw_ddr_address(instance, addr)); +} + +#ifdef STREAM_CONTROLLER_ACCESS +AOCL_MMD_CALL bool dla_is_stream_controller_valid(int handle, int instance) { + mmd_device_ptr spDevice = _gDeviceMapManager.get_device(handle); + if( nullptr == spDevice ) { + return FAILURE; + } + return spDevice->bStreamControllerValid(); +} + +AOCL_MMD_CALL int dla_mmd_stream_controller_write(int handle, int instance, uint64_t addr, uint64_t length, const void *data) { + return aocl_mmd_write(handle, NULL, length, data, HPS_MMD_STREAM_CONTROLLER_HANDLE, addr); +} + +AOCL_MMD_CALL int dla_mmd_stream_controller_read(int handle, int instance, uint64_t addr, uint64_t length, void* data) { + return aocl_mmd_read( + handle, NULL, length, data, HPS_MMD_STREAM_CONTROLLER_HANDLE, addr); +} +#endif + +AOCL_MMD_CALL double dla_mmd_get_coredla_clock_freq(int handle) { + return 200; +} + +#endif diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.h new file mode 100644 index 0000000..7c85a24 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/acl_hps.h @@ -0,0 +1,111 @@ +#ifndef ACL_HPS_H +#define ACL_HPS_H + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- acl_hps.h --------------------------------------------------- C++ -*-=== */ +/* */ +/* Intel(R) HPS MMD Driver */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file defines macros and types that are used inside the MMD driver */ +/* */ +/* ===-------------------------------------------------------------------------=== */ + +#ifndef ACL_HPS_EXPORT +#define ACL_HPS_EXPORT __declspec(dllimport) +#endif + +#define MMD_VERSION AOCL_MMD_VERSION_STRING + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#ifdef DLA_MMD +#include <cstdint> +#endif +#include "aocl_mmd.h" + +#include "hps_types.h" + +#if defined(WINDOWS) +#error Currently not available for windows +#endif + +#if defined(LINUX) +typedef uintptr_t KPTR; +typedef int fpga_handle; +typedef unsigned int fpga_result; +#define FPGA_OK 0 + +typedef unsigned int DWORD; +typedef unsigned long long QWORD; +typedef char INT8; +typedef unsigned char UINT8; +typedef int16_t INT16; +typedef uint16_t UINT16; +typedef int INT32; +typedef unsigned int UINT32; +typedef long long INT64; +typedef unsigned long long UINT64; + +#define INVALID_HANDLE_VALUE ((int)(-1)) + +#define INVALID_DEVICE (-1) +#define WD_STATUS_SUCCESS 0 + +// define for the format string for DWORD type +#define DWORD_FMT_U "%u" +#define DWORD_FMT_X "%x" +#define DWORD_FMT_4X "%04X" + +// define for the format string for size_t type +#define SIZE_FMT_U "%zu" +#define SIZE_FMT_X "%zx" + +#endif // LINUX + +#define MAX_NAME_SIZE (1204) + +#define HPS_ASSERT(COND, ...) \ + do { \ + if (!(COND)) { \ + printf("\nMMD FATAL: %s:%d: ", __FILE__, __LINE__); \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + assert(0); \ + } \ + } while (0) + +#define HPS_ERROR_IF(COND, NEXT, ...) \ + do { \ + if (COND) { \ + printf("\nMMD ERROR: " __VA_ARGS__); \ + fflush(stdout); \ + NEXT; \ + } \ + } while (0) + +#define HPS_INFO(...) \ + do { \ + printf("MMD INFO : " __VA_ARGS__); \ + fflush(stdout); \ + } while (0) + +#endif // ACL_HPS_H diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.cpp b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.cpp new file mode 100644 index 0000000..e403823 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.cpp @@ -0,0 +1,120 @@ +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- dma_device.h ------------------------------------------------- C++ -*-=== */ +/* */ +/* dma device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the dma device objects */ +/* */ +/* ===-------------------------------------------------------------------------=== */ + +// common and its own header files +#include "dma_device.h" +#include <unistd.h> +#include <glob.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> + +#include <memory.h> + +// Copied from Linux driver: /drivers/dma/altera-msgdma.c +#define MSGDMA_DESC_NUM 1024 + +// Same page size as used in /meta-intel-fpga-coredla/recipes-drivers/msgdma-userio/files/msgdma_userio_chr.c +#define PAGE_SIZE 4096 + +////////////////////////////////////////////////////// + +#define ERR(format, ...) \ +printf("%s:%u() **ERROR** : " format, \ + __func__, __LINE__, ##__VA_ARGS__) + +////////////////////////////////////////////////////// +dma_device::dma_device(std::string &name) +{ + _pFile = fopen(name.c_str(), "r+"); + if( _pFile == nullptr ) + { + ERR("dma_device::dma_device failed to open %s\n", name.c_str()); + return; + } + + // Turn off buffering + setvbuf(_pFile, NULL, _IONBF, 0); +} + +dma_device::~dma_device() +{ + if( _pFile ) + { + fclose(_pFile); + _pFile = NULL; + } +} + +int dma_device::read_block(void *host_addr, size_t offset, size_t size) +{ + // Use 32bit seek as DDR memory current < 32bits + if( fseek(_pFile, (uint32_t)offset, SEEK_SET) != 0 ) { + return FAILURE; + } + + size_t read_size = fread(host_addr, 1, size, _pFile); + return (read_size == size) ? SUCCESS : FAILURE; +} + +int dma_device::write_block(const void *host_addr, size_t offset, size_t size) +{ + // The MSGDMA driver only supports a maximum of 1024 x 4096 = 4MBytes in the worst case scenario, + // in the event that the virtual buffer is fully fragmented. As the buffer gets more fragmented it's + // possible to run out of DMA descriptors. To prevent this, slice the data into 4MB chunks. + + // chunk_size is chosen based on the size of a page (12 bits) and default number of descriptors (1024). + // The descriptor count is reduced by 1 since if the host_addr is not aligned to a page then an extra page + // will be added at the end. This would then increase the descriptor count by 1. + size_t chunk_size = PAGE_SIZE * (MSGDMA_DESC_NUM - 1); + size_t write_size = 0; + + // Use 32bit seek as DDR memory current < 32bits + if( fseek(_pFile, (uint32_t)offset, SEEK_SET) != 0 ) { + return FAILURE; + } + + for (size_t host_addr_offset = 0; host_addr_offset < size; host_addr_offset += chunk_size) { + size_t current_size = chunk_size; + + // If the current address is within one chunk_size from the end of the data, set current_size + // to the bytes left to send + if (size - host_addr_offset < chunk_size) { + current_size = size - host_addr_offset; + } + + size_t current_write_size = fwrite((uint8_t *)host_addr + host_addr_offset, 1, current_size, _pFile); + + if (current_write_size != current_size) { + return FAILURE; + } + + write_size += current_write_size; + } + + return (write_size == size) ? SUCCESS : FAILURE; +} diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.h new file mode 100644 index 0000000..24f89e4 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/dma_device.h @@ -0,0 +1,56 @@ +#ifndef DMA_DEVICE_H_ +#define DMA_DEVICE_H_ + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- dma_device.h ------------------------------------------------- C++ -*-=== */ +/* */ +/* dma device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the dma device objects */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +#include <vector> +#include <string> +#include <memory> + +#include "hps_types.h" + +class dma_device +{ +public: + dma_device(std::string &name); + ~dma_device(); + + int read_block(void *host_addr, size_t offset, size_t size); + int write_block(const void *host_addr, size_t offset, size_t size); + + bool bValid() { return _pFile != nullptr; }; +private: + + dma_device() = delete; + dma_device(dma_device const&) = delete; + void operator=(dma_device const &) = delete; + + FILE *_pFile = {nullptr}; // File pointer to UIO - Used to indicate the the uio_device is valid +}; +typedef std::shared_ptr<dma_device> dma_device_ptr; + +#endif // DMA_DEVICE_H_ diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/hps_types.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/hps_types.h new file mode 100644 index 0000000..3f11c4a --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/hps_types.h @@ -0,0 +1,44 @@ +#ifndef HPS_TYPES_H_ +#define HPS_TYPES_H_ + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- hps_types.h -------------------------------------------------- C++ -*-=== */ +/* */ +/* Useful HPS Types */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file contains useful type definition */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +#include <vector> +#include <string> + +#define SUCCESS (0) +#define FAILURE (1) + +typedef std::vector<std::string> board_names; + +typedef enum { + HPS_MMD_COREDLA_CSR_HANDLE = 1, // COREDLA CSR Interface + HPS_MMD_MEMORY_HANDLE = 2, // Device Memory transfers + HPS_MMD_STREAM_CONTROLLER_HANDLE = 3 // Stream Controller Interface +} hps_mmd_interface_t; + +#endif // HPS_TYPES_H_ diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.cpp b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.cpp new file mode 100644 index 0000000..b52c1d8 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.cpp @@ -0,0 +1,129 @@ +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- mmd_device.h ------------------------------------------------- C++ -*-=== */ +/* */ +/* mmd device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the mmd device object */ +/* */ +/* ===-------------------------------------------------------------------------=== */ + +#include "mmd_device.h" + +// Defined names of the UIO Nodes +#define UIO_COREDLA_PREFIX "coredla" +#define STREAM_CONTROLLER_PREFIX "stream_controller" + +// Defined name of the msgdma device +#define DMA_DEVICE_PREFIX "/dev/msgdma_coredla" +#define UIO_DEVICE_PREFIX "uio" + +board_names mmd_get_devices(const int max_fpga_devices) +{ + return uio_get_devices(UIO_COREDLA_PREFIX, max_fpga_devices); +} + + +///////////////////////////////////////////////////////// +mmd_device::mmd_device(std::string name, const int mmd_handle) +: _name(name), _mmd_handle(mmd_handle) { + _spCoredlaDevice = std::make_shared<uio_device>(name, _mmd_handle, true); + int32_t index = extract_index(_name); + if( (index >= 0) && _spCoredlaDevice && _spCoredlaDevice->bValid() ) + { + std::string dma_name(DMA_DEVICE_PREFIX); + dma_name += std::to_string(index); + _spDmaDevice = std::make_shared<dma_device>(dma_name); + + if( (_spDmaDevice==nullptr) || (!_spDmaDevice->bValid()) ) { + _spDmaDevice = nullptr; + return; + } + std::string stream_controller_name = uio_get_device(STREAM_CONTROLLER_PREFIX, index); + if( !stream_controller_name.empty() ) { + // Create a uio_device but don't attach any interrupt support as the stream controller + // does not require interrupts + _spStreamControllerDevice = std::make_shared<uio_device>(stream_controller_name, _mmd_handle, false); + if( _spStreamControllerDevice && !_spStreamControllerDevice->bValid() ) { + // The stream controller does not exist + _spStreamControllerDevice = nullptr; + } + } + } +} + +int mmd_device::read_block(aocl_mmd_op_t op, int mmd_interface, void *host_addr, size_t offset, size_t size) +{ + if( op ) { + LOG_ERR("op not support : %s\n", __func__ ); + return FAILURE; + } + if( mmd_interface == HPS_MMD_MEMORY_HANDLE ) { + return _spDmaDevice->read_block(host_addr, offset, size); + } else if( mmd_interface == HPS_MMD_COREDLA_CSR_HANDLE ) { + return _spCoredlaDevice->read_block(host_addr, offset, size); + } else if( mmd_interface == HPS_MMD_STREAM_CONTROLLER_HANDLE ) { + if ( _spStreamControllerDevice ) { + return _spStreamControllerDevice->read_block(host_addr, offset, size); + } + } + + return FAILURE; +} + +int mmd_device::write_block(aocl_mmd_op_t op, int mmd_interface, const void *host_addr, size_t offset, size_t size) +{ + if( op ) { + LOG_ERR("op not support : %s\n", __func__ ); + return FAILURE; + } + if( mmd_interface == HPS_MMD_MEMORY_HANDLE ) { + return _spDmaDevice->write_block(host_addr, offset, size); + } else if ( mmd_interface == HPS_MMD_COREDLA_CSR_HANDLE ) { + return _spCoredlaDevice->write_block(host_addr, offset, size); + } else if ( mmd_interface == HPS_MMD_STREAM_CONTROLLER_HANDLE ) { + if( _spStreamControllerDevice ) { + return _spStreamControllerDevice->write_block(host_addr, offset, size); + } + } + return FAILURE; +} + +int mmd_device::set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void *user_data) { + if( _spCoredlaDevice ) { + return _spCoredlaDevice->set_interrupt_handler(fn, user_data); + } + return FAILURE; +} + +// Returns the index of a uio device +// If index cannot be found then returns -1 +int mmd_device::extract_index(const std::string name) { + std::string prefix(UIO_DEVICE_PREFIX); + + if (name.length() <= prefix.length() && name.compare(0, prefix.length(), prefix)) { + LOG_ERR("Error parsing device name '%s'\n", name.c_str()); + return -1; + } + + std::string device_num_str = name.substr(prefix.length()); + int32_t index = std::stoi(device_num_str, 0, 10); + return index; +} diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.h new file mode 100644 index 0000000..9cb0c71 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/mmd_device.h @@ -0,0 +1,75 @@ +#ifndef MMD_DEVICE_H_ +#define MMD_DEVICE_H_ + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- mmd_device.h ------------------------------------------------- C++ -*-=== */ +/* */ +/* mmd device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the mmd device object */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +#include <memory> +#include <string> + +#include "hps_types.h" +#include "dma_device.h" +#include "uio_device.h" + +#include "aocl_mmd.h" + +// LOG ERRORS +#define MMD_ERR_LOGGING 1 +#ifdef MMD_ERR_LOGGING +#define LOG_ERR(...) fprintf(stderr, __VA_ARGS__) +#else +#define LOG_ERR(...) +#endif + +class mmd_device { +public: + mmd_device(std::string name, const int mmd_handle); + + bool bValid() { return _spCoredlaDevice && _spCoredlaDevice->bValid() && _spDmaDevice && _spDmaDevice->bValid(); }; + bool bStreamControllerValid() { return _spCoredlaDevice && _spStreamControllerDevice && _spStreamControllerDevice->bValid(); }; + int write_block(aocl_mmd_op_t op, int mmd_interface, const void *host_addr, size_t offset, size_t size); + int read_block(aocl_mmd_op_t op, int mmd_interface, void *host_addr, size_t offset, size_t size); + + int set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void *user_data); +private: + int32_t extract_index(const std::string name); + + mmd_device() = delete; + mmd_device(mmd_device const&) = delete; + void operator=(mmd_device const &) = delete; + std::string _name; + + uio_device_ptr _spCoredlaDevice; + uio_device_ptr _spStreamControllerDevice; + dma_device_ptr _spDmaDevice; + int _mmd_handle; +}; + +typedef std::shared_ptr<mmd_device> mmd_device_ptr; + +extern board_names mmd_get_devices(const int max_fpga_devices); + +#endif // MMD_DEVICE_H_ diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.cpp b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.cpp new file mode 100644 index 0000000..95a9567 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.cpp @@ -0,0 +1,469 @@ +// (c) 1992-2021 Intel Corporation. +// Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words +// and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. +// and/or other countries. Other marks and brands may be claimed as the property +// of others. See Trademarks on intel.com for full list of Intel trademarks or +// the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) +// Your use of Intel Corporation's design tools, logic functions and other +// software and tools, and its AMPP partner logic functions, and any output +// files any of the foregoing (including device programming or simulation +// files), and any associated documentation or information are expressly subject +// to the terms and conditions of the Altera Program License Subscription +// Agreement, Intel MegaCore Function License Agreement, or other applicable +// license agreement, including, without limitation, that your use is for the +// sole purpose of programming logic devices manufactured by Intel and sold by +// Intel or its authorized distributors. Please refer to the applicable +// agreement for further details. + +/* ===- uio_device.cpp ----------------------------------------------- C++ -*-=== */ +/* */ +/* uio device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the uio device objects */ +/* */ +/* ===-------------------------------------------------------------------------=== */ + +// common and its own header files +#include "uio_device.h" +#include <unistd.h> +#include <glob.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> +#include <poll.h> + +#include <cinttypes> +#include <memory.h> + +////////////////////////////////////////////////////// +#define UIO_BASE_NAME "uio*" +#define UIO_BASE_PATH "/sys/class/uio/" +#define UIO_BASE_SEARCH UIO_BASE_PATH UIO_BASE_NAME +#define UIO_MAX_PATH (256) + +#define ERR(format, ...) \ +fprintf(stderr, "%s:%u **ERROR** : " format, \ + __FILE__, __LINE__, ##__VA_ARGS__) + +////////////////////////////////////////////////////// +#define MAX_NAME (20) +bool uio_read_sysfs_uint64(const char *device_name, const char *sysfs_name, uint64_t &value) +{ + FILE *fp; + char param_path[UIO_MAX_PATH]; + + if( snprintf(param_path, sizeof(param_path), "%s/%s", device_name, sysfs_name) < 0 ) + { + ERR("Path too long. %s, %s\n", device_name, sysfs_name); + return false; + } + + fp = fopen(param_path, "r"); + if( !fp ) + { + ERR("Failed to fopen - %s\n", param_path); + return false; + } + + if( fscanf(fp, "%" PRIx64, &value) != 1 ) + { + ERR("Failed fscanf - %s\n", param_path); + fclose(fp); + return false; + } + + fclose(fp); + return true; +} + +bool uio_read_sysfs_string(const char *uio_path, const char *sysfs_name, std::string &result) +{ + char uio_name[MAX_NAME]; + FILE *fp; + char param_path[UIO_MAX_PATH]; + + if( snprintf(param_path, sizeof(param_path), "%s/%s", uio_path, sysfs_name) < 0 ) + { + ERR("Path too long. %s, %s\n", uio_path, sysfs_name); + return false; + } + + fp = fopen(param_path, "r"); + if( !fp ) + { + ERR("Failed to fopen - %s\n", param_path); + return false; + } + + int num_read = fread(uio_name, 1, MAX_NAME, fp); + if( num_read <= 0 ) + { + ERR("Failed to read name - %s\n", param_path); + fclose(fp); + return false; + } + + uio_name[num_read-1] = '\0'; // Terminate + result = std::string(uio_name); + fclose(fp); + + return true; +} + +std::string uio_get_device(const std::string prefix, const int32_t index) +{ + glob_t globbuf = {0}; + std::string uio_name; + + int glob_res = glob(UIO_BASE_SEARCH, GLOB_NOSORT, NULL, &globbuf); + if( (glob_res == 0) && (globbuf.gl_pathc) ) + { + std::string device_name; + device_name = prefix + std::to_string(index); + + for( size_t i=0; i<globbuf.gl_pathc; i++ ) + { + std::string name; + uio_read_sysfs_string(globbuf.gl_pathv[i], "name", name); + + if( name.find(device_name) != std::string::npos ) + { + // We will return just the device name without the UIO_BASE_PATH + std::string name = std::string(globbuf.gl_pathv[i]); + uio_name = name.substr(sizeof(UIO_BASE_PATH)-1); + } + } + } + return uio_name; +} + +board_names uio_get_devices(const std::string device_name, const int max_devices) +{ + board_names names; + int device = 0; + + glob_t globbuf = {0}; + + int glob_res = glob(UIO_BASE_SEARCH, GLOB_NOSORT, NULL, &globbuf); + if( (glob_res == 0) && (globbuf.gl_pathc) ) + { + for( size_t i=0; (i<globbuf.gl_pathc) && (device < max_devices); i++ ) + { + std::string name; + uio_read_sysfs_string(globbuf.gl_pathv[i], "name", name); + + if( name.find(device_name) != std::string::npos ) + { + // We will return just the device name without the UIO_BASE_PATH + std::string name = std::string(globbuf.gl_pathv[i]); + name = name.substr(sizeof(UIO_BASE_PATH)-1); + names.push_back(name); + device++; + } + } + } + return names; +} + +////////////////////////////////////////////////////////////// +uio_device::uio_device(std::string &name, const int mmd_handle, const bool bEnableIRQ) +: _mmd_handle(mmd_handle) +{ + // Map the first address space + if ( !map_region(name, 0) ) { + ERR("Failed to map region 0 on %s\n", name.c_str()); + return; + } +#ifndef RUNTIME_POLLING + if( bEnableIRQ ) { + _spInterrupt = std::make_shared<uio_interrupt>(_fd, _mmd_handle); + if( !_spInterrupt->initialized() ) { + _spInterrupt = nullptr; // If the uio_interrupt failed to initialize then delete + } + _bIrqEnabled = bEnableIRQ; + } +#endif +} + +bool uio_device::bValid() { + bool bValid = (_fd >=0); +#ifndef RUNTIME_POLLING // If we're not polling check that the interrupt handling is working + if( _bIrqEnabled ) { + bValid |= (_spInterrupt != nullptr); + } +#endif + return bValid; +}; + +uio_device::~uio_device() +{ +#ifndef RUNTIME_POLLING + _spInterrupt = nullptr; // Shutdown the interrupt handler +#endif + unmap_region(); +} + +uint32_t uio_device::read(const uint32_t reg) +{ + // NOT YET IMPLEMENTED + return 0; +} + +void uio_device::write(const uint32_t reg, const uint32_t value) +{ + // NOT YET IMPLEMENTED + return; +} + +// Copies the block of data from the FPGA to the host +// memcpy is not used as this can cause multiple transfers of the AXI bus depending +// on the implementation of memcpy +int uio_device::read_block(void *host_addr, size_t offset, size_t size) +{ + // Support for only 32bit aligned transfers + if( (offset % sizeof(uint32_t)) || (size % sizeof(uint32_t)) ){ + return FAILURE; + } + + // Transfer the data in 32bit chunks + volatile const uint32_t *pDeviceMem32 = reinterpret_cast<volatile const uint32_t*>(reinterpret_cast<uint8_t*>(_pPtr) + offset); + uint32_t *host_addr32 = reinterpret_cast<uint32_t *>(host_addr); + while (size >= sizeof(uint32_t)) { + *host_addr32++ = *pDeviceMem32++; + size -= sizeof(uint32_t); + } + + return SUCCESS; +} + +// Copies the block of data from the host to the FPGA +// memcpy is not used as this can cause multiple transfers of the AXI bus depending +// on the implementation of memcpy +int uio_device::write_block(const void *host_addr, size_t offset, size_t size) +{ + // Support for only 32bit aligned transfers + if( (offset % sizeof(uint32_t)) || (size % sizeof(uint32_t)) ){ + return FAILURE; + } + + // Transfer the remaining 32bits of data + volatile uint32_t *pDeviceMem32 = reinterpret_cast<volatile uint32_t*>(reinterpret_cast<uint8_t*>(_pPtr) + offset); + const uint32_t *host_addr32 = reinterpret_cast<const uint32_t*>(host_addr); + while( size >= sizeof(uint32_t) ) { + *pDeviceMem32++ = *host_addr32++; + size -= sizeof(uint32_t); + } + return SUCCESS; +} + +int uio_device::set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void* user_data) { +#ifndef RUNTIME_POLLING + if( _spInterrupt ) { + return _spInterrupt->set_interrupt_handler(fn, user_data); + } +#endif + return FAILURE; +} + +///////////////////////////////////////////////////////////////// +void uio_device::unmap_region() +{ + if( _pBase ) + { + munmap(_pBase, _size); + _pBase = nullptr; + } + + if( _fd >= 0 ) + { + close(_fd); + _fd = -1; + } +} + +bool uio_device::map_region( std::string &name, const uint32_t index) +{ + char map_path[UIO_MAX_PATH]; + + std::string uio_params_path(UIO_BASE_PATH); + uio_params_path += name; + + // char device_path[UIO_MAX_PATH]; + // const char *p; + + if( snprintf(map_path, sizeof(map_path), "maps/map%d/size", index ) < 0 ) + { + ERR("Failed to make map addr name.\n"); + return false; + } + if( !uio_read_sysfs_uint64(uio_params_path.c_str(), map_path, _size) ) + { + ERR("Failed to read size\n"); + return false; + } + // Make sure that the size doesn't exceed 32bits, as this will fail the mapping + // call on 32bit systems + if( _size > UINT32_MAX ) { + ERR("Invalid size value\n"); + return false; + } + + if( snprintf(map_path, sizeof(map_path), "maps/map%d/offset", index ) < 0 ) + { + ERR("Failed to make map offset name.\n"); + return false; + } + if( !uio_read_sysfs_uint64(uio_params_path.c_str(), map_path, _offset) ) + { + ERR("Failed to read offset\n"); + return false; + } + + std::string uio_dev_path("/dev/"); + uio_dev_path += name; + + _fd = open(uio_dev_path.c_str(), O_RDWR ); + if( _fd < 0 ) + { + ERR("Failed to open - %s\n", uio_dev_path.c_str()); + return false; + } + // Map the region into userspace + // The base of the region is the page_size offset of the index + uint32_t page_size = (uint32_t)sysconf(_SC_PAGESIZE); + + _pBase = (uint8_t*)mmap(NULL, (size_t)_size, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, (off_t) (index * page_size)); + if( _pBase == MAP_FAILED ) + { + ERR("Failed to map uio region.\n"); + close(_fd); + _fd = -1; + return false; + } + // CST base address is at _pBase + _offset + _pPtr = (uint32_t*)(_pBase + _offset); + + return true; +}; + +#ifndef RUNTIME_POLLING +/////////////////////////////////////////////////////////////////////////////////// +uio_interrupt::uio_interrupt(const int fd, const int mmd_handle) +: _device_fd(fd), _mmd_handle(mmd_handle) { + if( is_irq_available() ) { + // Create a eventfd_object to be used for shutting down the work_thread + _spShutdown_event = std::make_shared<eventfd_object>(); + if( _spShutdown_event->initialized() ) { + _pThread = new std::thread(work_thread, std::ref(*this)); + } else { + _spShutdown_event = nullptr; + } + } else { + ERR("No device interrupt found.\n"); + } +} + +uio_interrupt::~uio_interrupt() { + // kill the thread + if (_pThread && _spShutdown_event) { + // send message to thread to end it + _spShutdown_event->notify(1); + + // join with thread until it ends + _pThread->join(); + + delete _pThread; + _pThread = NULL; + + _spShutdown_event = nullptr; + } +} + +bool uio_interrupt::is_irq_available() { + // Disable the interrupt handling, this will fail if the IRQ has not been setup correctly. + // For example devicetree is incorrect. + return disable_irq(); +} + +bool uio_interrupt::enable_irq() { + // Enable interrupts from the device + uint32_t info = 1; + ssize_t nb = write(_device_fd, &info, sizeof(info)); + if( nb != (ssize_t)sizeof(info) ) { + ERR( "Failed in enable CoreDLA Interrupt = %s\n", strerror(errno)); + return false; + } + return true; +} + +bool uio_interrupt::disable_irq() { + // Enable interrupts from the device + uint32_t info = 0; + ssize_t nb = write(_device_fd, &info, sizeof(info)); + if( nb != (ssize_t)sizeof(info) ) { + ERR( "Failed in disable CoreDLA Interrupt = %s\n", strerror(errno)); + return false; + } + return true; +} + +void uio_interrupt::work_thread(uio_interrupt& obj) { + obj.run_thread(); +} + +#define UIO_INTERRUPT_TIMEOUT (-1) +void uio_interrupt::run_thread() { + while( true ) { + // Need to re-enable the UIO interrupt handling as UIO disables the IRQ each time it is fired + if ( !enable_irq() ) { + exit(-1); + } + // Poll for the shutdown_event and uio interrupt + struct pollfd pollfd_arr[2]; + pollfd_arr[0].fd = _spShutdown_event->get_fd(); + pollfd_arr[0].events = POLLIN; + pollfd_arr[0].revents = 0; + pollfd_arr[1].fd = _device_fd; + pollfd_arr[1].events = POLLIN; + pollfd_arr[1].revents = 0; + + int res = poll(pollfd_arr, 2, UIO_INTERRUPT_TIMEOUT); + if (res < 0) { + ERR( "Poll error errno = %s\n", strerror(errno)); + exit(-1); + } else if (res > 0 && pollfd_arr[0].revents == POLLIN) { + uint64_t count; + ssize_t bytes_read = read(pollfd_arr[0].fd, &count, sizeof(count)); + if (bytes_read > 0) { + break; // We've been asked to shutdown + } else { + ERR( "Error: poll failed: %s\n", bytes_read < 0 ? strerror(errno) : "zero bytes read"); + exit(-1); + } + } else if (res > 0 && pollfd_arr[1].revents == POLLIN) { + uint32_t count; + ssize_t bytes_read = read(pollfd_arr[1].fd, &count, sizeof(count)); + if (bytes_read > 0) { + if( _interrupt_fn ) { // Run the callback to the application + _interrupt_fn(get_mmd_handle(), _interrupt_fn_user_data ); + } + } else { + ERR( "Error: poll failed: %s\n", bytes_read < 0 ? strerror(errno) : "zero bytes read"); + exit(-1); + } + } + } + // Disable interrupt handling in UIO + if( !disable_irq() ){ + exit(-1); + } +} + +int uio_interrupt::set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void* user_data) { + _interrupt_fn = fn; + _interrupt_fn_user_data = user_data; + return SUCCESS; +} +#endif diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.h new file mode 100644 index 0000000..c5f3ed5 --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/host/uio_device.h @@ -0,0 +1,162 @@ +#ifndef UIO_DEVICE_H_ +#define UIO_DEVICE_H_ + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +/* ===- uio_device.h ------------------------------------------------- C++ -*-=== */ +/* */ +/* uio device access functions */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +/* */ +/* This file implements the functions used access the uio device objects */ +/* */ +/* ===-------------------------------------------------------------------------=== */ +#include <vector> +#include <string> +#include <string.h> +#include <memory> +#include <thread> +#include <mutex> +#include <sys/eventfd.h> +#include <unistd.h> + +#include "aocl_mmd.h" +#include "hps_types.h" + +// simple wrapper class for managing eventfd objects +class eventfd_object final { + public: + eventfd_object() { + m_initialized = false; + // Note: EFD_SEMAPHORE and EFD_NONBLOCK are not set + // The implementation of functions using eventfd assumes that + m_fd = eventfd(0, 0); + if (m_fd < 0) { + fprintf(stderr, "eventfd : %s", strerror(errno)); + return; + } + + m_initialized = true; + } + + ~eventfd_object() { + if (m_initialized) { + if (close(m_fd) < 0) { + fprintf(stderr, "eventfd : %s", strerror(errno)); + } + } + } + + bool notify(uint64_t count) { + ssize_t res = write(m_fd, &count, sizeof(count)); + if (res < 0) { + fprintf(stderr, "eventfd : %s", strerror(errno)); + return false; + } + return true; + } + + int get_fd() { return m_fd; } + bool initialized() { return m_initialized; } + + private: + // not used and not implemented + eventfd_object(eventfd_object& other); + eventfd_object& operator=(const eventfd_object& other); + + // member varaibles + int m_fd; + int m_initialized; +}; // class eventfd_object +typedef std::shared_ptr<eventfd_object> eventfd_object_ptr; + +#ifndef RUNTIME_POLLING +class uio_interrupt final { + public: + uio_interrupt(const int fd, const int mmd_handle); + ~uio_interrupt(); + bool initialized() { return _pThread != nullptr; }; // If the thread is not created then must be invalid + int set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void* user_data); + + private: + bool is_irq_available(); // Checks that the interrupt has been mapped into userspace + bool enable_irq(); // Enables UIO Irq handling + bool disable_irq(); // Disabled UIO Irq handling + + static void work_thread(uio_interrupt &obj); + void run_thread(); // Function which handles waiting for interrupts + + uio_interrupt() = delete; + uio_interrupt(uio_interrupt const&) = delete; + void operator=(uio_interrupt const&) = delete; + + int get_mmd_handle() {return _mmd_handle; }; + + std::thread *_pThread = {nullptr}; // Pointer to a thread object for waiting for interrupts + int _device_fd = {-1}; // /dev/uio* device pointer + int _mmd_handle = {-1}; // handle to the parent mmd_device + eventfd_object_ptr _spShutdown_event = {nullptr}; // Shutdown thread event object + + aocl_mmd_interrupt_handler_fn _interrupt_fn = {nullptr}; + void *_interrupt_fn_user_data = {nullptr}; +}; +typedef std::shared_ptr<uio_interrupt> uio_interrupt_ptr; +#endif + +class uio_device +{ +public: + uio_device(std::string &name, const int mmd_handle, const bool bEnableIrq=false); + ~uio_device(); + + uint32_t read(const uint32_t reg); + void write(const uint32_t reg, const uint32_t value); + + int read_block(void *host_addr, size_t offset, size_t size); + int write_block(const void *host_addr, size_t offset, size_t size); + int set_interrupt_handler(aocl_mmd_interrupt_handler_fn fn, void* user_data); + + bool bValid(); + +private: + bool map_region( std::string &name, const uint32_t index ); + void unmap_region(); + + uio_device() = delete; + uio_device(uio_device const&) = delete; + void operator=(uio_device const &) = delete; + + int _mmd_handle; // Handle to the parent mmd device + int _fd = {-1}; // File pointer to UIO - Used to indicate the the uio_device is valid + uint64_t _size; // Size of the mmapped region + uint64_t _offset; // Offset of the first register + uint8_t *_pBase; // Base of the mmapped region + + uint32_t *_pPtr; // The first register +#ifndef RUNTIME_POLLING + bool _bIrqEnabled; // Indicates that we tried to create with IRQ + uio_interrupt_ptr _spInterrupt; // Object to handle UIO Interrupts +#endif +}; +typedef std::shared_ptr<uio_device> uio_device_ptr; + +extern board_names uio_get_devices(const std::string name, const int max_devices); +extern std::string uio_get_device(const std::string prefix, const int32_t index); + +#endif // UIO_DEVICE_H_ diff --git a/python/openvino/runtime/coredla_device/mmd/hps_platform/include/aocl_mmd.h b/python/openvino/runtime/coredla_device/mmd/hps_platform/include/aocl_mmd.h new file mode 100644 index 0000000..7c1c73d --- /dev/null +++ b/python/openvino/runtime/coredla_device/mmd/hps_platform/include/aocl_mmd.h @@ -0,0 +1,645 @@ +#ifndef AOCL_MMD_H +#define AOCL_MMD_H + +/* (c) 1992-2021 Intel Corporation. */ +/* Intel, the Intel logo, Intel, MegaCore, NIOS II, Quartus and TalkBack words */ +/* and logos are trademarks of Intel Corporation or its subsidiaries in the U.S. */ +/* and/or other countries. Other marks and brands may be claimed as the property */ +/* of others. See Trademarks on intel.com for full list of Intel trademarks or */ +/* the Trademarks & Brands Names Database (if Intel) or See www.Intel.com/legal (if Altera) */ +/* Your use of Intel Corporation's design tools, logic functions and other */ +/* software and tools, and its AMPP partner logic functions, and any output */ +/* files any of the foregoing (including device programming or simulation */ +/* files), and any associated documentation or information are expressly subject */ +/* to the terms and conditions of the Altera Program License Subscription */ +/* Agreement, Intel MegaCore Function License Agreement, or other applicable */ +/* license agreement, including, without limitation, that your use is for the */ +/* sole purpose of programming logic devices manufactured by Intel and sold by */ +/* Intel or its authorized distributors. Please refer to the applicable */ +/* agreement for further details. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Support for memory mapped ACL devices. + * + * Typical API lifecycle, from the perspective of the caller. + * + * 1. aocl_mmd_open must be called first, to provide a handle for further + * operations. + * + * 2. The interrupt and status handlers must be set. + * + * 3. Read and write operations are performed. + * + * 4. aocl_mmd_close may be called to shut down the device. No further + * operations are permitted until a subsequent aocl_mmd_open call. + * + * aocl_mmd_get_offline_info can be called anytime including before + * open. aocl_mmd_get_info can be called anytime between open and close. + */ + +#ifndef AOCL_MMD_CALL +#if defined(_WIN32) +#define AOCL_MMD_CALL __declspec(dllimport) +#else +#define AOCL_MMD_CALL __attribute__((visibility ("default"))) +#endif +#endif + +#ifndef WEAK +#if defined(_WIN32) +#define WEAK +#else +/* This normally comes with "__attribute__((weak))" but for reasons not presently + * understood, the shared library is not properly loaded on Ubuntu18 when the functions + * are weak. + */ +#define WEAK +#endif +#endif + +#ifdef DLA_MMD +#include <cstddef> //size_t +#include <cstdint> //uint32_t +#endif + +/* The MMD API's version - the runtime expects this string when + * AOCL_MMD_VERSION is queried. This changes only if the API has changed */ +#define AOCL_MMD_VERSION_STRING "20.3" + +/* Memory types that can be supported - bitfield. Other than physical memory + * these types closely align with the OpenCL SVM types. + * + * AOCL_MMD_PHYSICAL_MEMORY - The vendor interface includes IP to communicate + * directly with physical memory such as DDR, QDR, etc. + * + * AOCL_MMD_SVM_COARSE_GRAIN_BUFFER - The vendor interface includes support for + * caching SVM pointer data and requires explicit function calls from the user + * to synchronize the cache between the host processor and the FPGA. This level + * of SVM is not currently supported by Altera except as a subset of + * SVM_FINE_GAIN_SYSTEM support. + * + * AOCL_MMD_SVM_FINE_GRAIN_BUFFER - The vendor interface includes support for + * caching SVM pointer data and requires additional information from the user + * and/or host runtime that can be collected during pointer allocation in order + * to synchronize the cache between the host processor and the FPGA. Once this + * additional data is provided for an SVM pointer, the vendor interface handles + * cache synchronization between the host processor & the FPGA automatically. + * This level of SVM is not currently supported by Altera except as a subset + * of SVM_FINE_GRAIN_SYSTEM support. + * + * AOCL_MMD_SVM_FINE_GRAIN_SYSTEM - The vendor interface includes support for + * caching SVM pointer data and does not require any additional information to + * synchronize the cache between the host processor and the FPGA. The vendor + * interface handles cache synchronization between the host processor & the + * FPGA automatically for all SVM pointers. This level of SVM support is + * currently under development by Altera and some features may not be fully + * supported. + */ +#define AOCL_MMD_PHYSICAL_MEMORY (1 << 0) +#define AOCL_MMD_SVM_COARSE_GRAIN_BUFFER (1 << 1) +#define AOCL_MMD_SVM_FINE_GRAIN_BUFFER (1 << 2) +#define AOCL_MMD_SVM_FINE_GRAIN_SYSTEM (1 << 3) + +/* program modes - bitfield + * + * AOCL_MMD_PROGRAM_PRESERVE_GLOBAL_MEM - preserve contents of global memory + * when this bit is set to 1. If programming can't occur without preserving + * global memory contents, the program function must fail, in which case the + * runtime may re-invoke program with this bit set to 0, allowing programming + * to occur even if doing so destroys global memory contents. + * + * more modes are reserved for stacking on in the future + */ +#define AOCL_MMD_PROGRAM_PRESERVE_GLOBAL_MEM (1 << 0) +typedef int aocl_mmd_program_mode_t; + +typedef void* aocl_mmd_op_t; + +typedef struct { + unsigned lo; /* 32 least significant bits of time value. */ + unsigned hi; /* 32 most significant bits of time value. */ +} aocl_mmd_timestamp_t; + +/* Defines the set of characteristics that can be probed about the board before + * opening a device. The type of data returned by each is specified in + * parentheses in the adjacent comment. + * + * AOCL_MMD_NUM_BOARDS and AOCL_MMD_BOARD_NAMES + * These two fields can be used to implement multi-device support. The MMD + * layer may have a list of devices it is capable of interacting with, each + * identified with a unique name. The length of the list should be returned + * in AOCL_MMD_NUM_BOARDS, and the names of these devices returned in + * AOCL_MMD_BOARD_NAMES. The OpenCL runtime will try to call aocl_mmd_open + * for each board name returned in AOCL_MMD_BOARD_NAMES. + */ +typedef enum { + AOCL_MMD_VERSION = 0, /* Version of MMD (char*)*/ + AOCL_MMD_NUM_BOARDS = 1, /* Number of candidate boards (int)*/ + AOCL_MMD_BOARD_NAMES = 2, /* Names of boards available delimiter=; (char*)*/ + AOCL_MMD_VENDOR_NAME = 3, /* Name of vendor (char*) */ + AOCL_MMD_VENDOR_ID = 4, /* An integer ID for the vendor (int) */ + AOCL_MMD_USES_YIELD = 5, /* 1 if yield must be called to poll hw (int) */ + /* The following can be combined in a bit field: + * AOCL_MMD_PHYSICAL_MEMORY, AOCL_MMD_SVM_COARSE_GRAIN_BUFFER, AOCL_MMD_SVM_FINE_GRAIN_BUFFER, + * AOCL_MMD_SVM_FINE_GRAIN_SYSTEM. Prior to 14.1, all existing devices supported physical memory and no types of SVM + * memory, so this is the default when this operation returns '0' for board MMDs with a version prior to 14.1 + */ + AOCL_MMD_MEM_TYPES_SUPPORTED = 6, +} aocl_mmd_offline_info_t; + +/** Possible capabilities to return from AOCL_MMD_*_MEM_CAPABILITIES query */ +/** + * If not set allocation function is not supported, even if other capabilities are set. + */ +#define AOCL_MMD_MEM_CAPABILITY_SUPPORTED (1 << 0) +/** + * Supports atomic access to the memory by either the host or device. + */ +#define AOCL_MMD_MEM_CAPABILITY_ATOMIC (1 << 1) +/** + * Supports concurrent access to the memory either by host or device if the + * accesses are not on the same block. Block granularity is defined by + * AOCL_MMD_*_MEM_CONCURRENT_GRANULARITY., blocks are aligned to this + * granularity + */ +#define AOCL_MMD_MEM_CAPABILITY_CONCURRENT (1 << 2) +/** + * Memory can be accessed by multiple devices at the same time. + */ +#define AOCL_MMD_MEM_CAPABILITY_P2P (1 << 3) + +/* Defines the set of characteristics that can be probed about the board after + * opening a device. This can involve communication to the device + * + * AOCL_MMD_NUM_KERNEL_INTERFACES - The number of kernel interfaces, usually 1 + * + * AOCL_MMD_KERNEL_INTERFACES - the handle for each kernel interface. + * param_value will have size AOCL_MMD_NUM_KERNEL_INTERFACES * sizeof int + * + * AOCL_MMD_PLL_INTERFACES - the handle for each pll associated with each + * kernel interface. If a kernel interface is not clocked by acl_kernel_clk + * then return -1 + * + * */ +typedef enum { + AOCL_MMD_NUM_KERNEL_INTERFACES = 1, /* Number of Kernel interfaces (int) */ + AOCL_MMD_KERNEL_INTERFACES = 2, /* Kernel interface (int*) */ + AOCL_MMD_PLL_INTERFACES = 3, /* Kernel clk handles (int*) */ + AOCL_MMD_MEMORY_INTERFACE = 4, /* Global memory handle (int) */ + AOCL_MMD_TEMPERATURE = 5, /* Temperature measurement (float) */ + AOCL_MMD_PCIE_INFO = 6, /* PCIe information (char*) */ + AOCL_MMD_BOARD_NAME = 7, /* Name of board (char*) */ + AOCL_MMD_BOARD_UNIQUE_ID = 8, /* Unique ID of board (int) */ + AOCL_MMD_CONCURRENT_READS = 9, /* # of parallel reads; 1 is serial*/ + AOCL_MMD_CONCURRENT_WRITES = 10, /* # of parallel writes; 1 is serial*/ + AOCL_MMD_CONCURRENT_READS_OR_WRITES = 11, /* total # of concurrent operations read + writes*/ + AOCL_MMD_MIN_HOST_MEMORY_ALIGNMENT = 12, /* Min alignment that the BSP supports for host allocations (size_t) */ + AOCL_MMD_HOST_MEM_CAPABILITIES = 13, /* Capabilities of aocl_mmd_host_alloc() (unsigned int)*/ + AOCL_MMD_SHARED_MEM_CAPABILITIES = 14, /* Capabilities of aocl_mmd_shared_alloc (unsigned int)*/ + AOCL_MMD_DEVICE_MEM_CAPABILITIES = 15, /* Capabilities of aocl_mmd_device_alloc (unsigned int)*/ + AOCL_MMD_HOST_MEM_CONCURRENT_GRANULARITY = 16, /*(size_t)*/ + AOCL_MMD_SHARED_MEM_CONCURRENT_GRANULARITY = 17, /*(size_t)*/ + AOCL_MMD_DEVICE_MEM_CONCURRENT_GRANULARITY = 18, /*(size_t)*/ +} aocl_mmd_info_t; + +typedef struct { + unsigned long long int exception_type; + void* user_private_info; + size_t user_cb; +} aocl_mmd_interrupt_info; + +typedef void (*aocl_mmd_interrupt_handler_fn)(int handle, void* user_data); +typedef void (*aocl_mmd_device_interrupt_handler_fn)(int handle, aocl_mmd_interrupt_info* data_in, void* user_data); +typedef void (*aocl_mmd_status_handler_fn)(int handle, void* user_data, aocl_mmd_op_t op, int status); + +/* Get information about the board using the enum aocl_mmd_offline_info_t for + * offline info (called without a handle), and the enum aocl_mmd_info_t for + * info specific to a certain board. + * Arguments: + * + * requested_info_id - a value from the aocl_mmd_offline_info_t enum + * + * param_value_size - size of the param_value field in bytes. This should + * match the size of the return type expected as indicated in the enum + * definition. For example, the AOCL_MMD_TEMPERATURE returns a float, so + * the param_value_size should be set to sizeof(float) and you should + * expect the same number of bytes returned in param_size_ret. + * + * param_value - pointer to the variable that will receive the returned info + * + * param_size_ret - receives the number of bytes of data actually returned + * + * Returns: a negative value to indicate error. + */ +AOCL_MMD_CALL int aocl_mmd_get_offline_info(aocl_mmd_offline_info_t requested_info_id, + size_t param_value_size, + void* param_value, + size_t* param_size_ret) WEAK; + +// AOCL_MMD_CALL int aocl_mmd_get_info(int handle, +// aocl_mmd_info_t requested_info_id, +// size_t param_value_size, +// void* param_value, +// size_t* param_size_ret) WEAK; + +/* Open and initialize the named device. + * + * The name is typically one specified by the AOCL_MMD_BOARD_NAMES offline + * info. + * + * Arguments: + * name - open the board with this name (provided as a C-style string, + * i.e. NUL terminated ASCII.) + * + * Returns: the non-negative integer handle for the board, otherwise a + * negative value to indicate error. Upon receiving the error, the OpenCL + * runtime will proceed to open other known devices, hence the MMD mustn't + * exit the application if an open call fails. + */ +AOCL_MMD_CALL int aocl_mmd_open(const char* name) WEAK; + +/* Close an opened device, by its handle. + * Returns: 0 on success, negative values on error. + */ +AOCL_MMD_CALL int aocl_mmd_close(int handle) WEAK; + +/* Set the interrupt handler for the opened device. + * The interrupt handler is called whenever the client needs to be notified + * of an asynchronous event signaled by the device internals. + * For example, the kernel has completed or is stalled. + * + * Important: Interrupts from the kernel must be ignored until this handler is + * set + * + * Arguments: + * fn - the callback function to invoke when a kernel interrupt occurs + * user_data - the data that should be passed to fn when it is called. + * + * Returns: 0 if successful, negative on error + */ +AOCL_MMD_CALL int aocl_mmd_set_interrupt_handler(int handle, aocl_mmd_interrupt_handler_fn fn, void* user_data) WEAK; + +/* Set the device interrupt handler for the opened device. + * The device interrupt handler is called whenever the client needs to be notified + * of a device event signaled by the device internals. + * For example, an ECC error has been reported. + * + * Important: Interrupts from the device must be ignored until this handler is + * set + * + * Arguments: + * fn - the callback function to invoke when a device interrupt occurs + * user_data - the data that should be passed to fn when it is called. + * + * Returns: 0 if successful, negative on error + */ +// AOCL_MMD_CALL int aocl_mmd_set_device_interrupt_handler(int handle, +// aocl_mmd_device_interrupt_handler_fn fn, +// void* user_data) WEAK; + +/* Set the operation status handler for the opened device. + * The operation status handler is called with + * status 0 when the operation has completed successfully. + * status negative when the operation completed with errors. + * + * Arguments: + * fn - the callback function to invoke when a status update is to be + * performed. + * user_data - the data that should be passed to fn when it is called. + * + * Returns: 0 if successful, negative on error + */ +//AOCL_MMD_CALL int aocl_mmd_set_status_handler(int handle, aocl_mmd_status_handler_fn fn, void* user_data) WEAK; + +/* If AOCL_MMD_USES_YIELD is 1, this function is called when the host is idle + * and hence possibly waiting for events to be processed by the device. + * If AOCL_MMD_USES_YIELD is 0, this function is never called and the MMD is + * assumed to provide status/event updates via some other execution thread + * such as through an interrupt handler. + * + * Returns: non-zero if the yield function performed useful work such as + * processing DMA transactions, 0 if there is no useful work to be performed + * + * NOTE: yield may be called continuously as long as it reports that it has useful work + */ +//AOCL_MMD_CALL int aocl_mmd_yield(int handle) WEAK; + +/* Read, write and copy operations on a single interface. + * If op is NULL + * - Then these calls must block until the operation is complete. + * - The status handler is not called for this operation. + * + * If op is non-NULL, then: + * - These may be non-blocking calls + * - The status handler must be called upon completion, with status 0 + * for success, and a negative value for failure. + * + * Arguments: + * op - the operation object used to track this operations progress + * + * len - the size in bytes to transfer + * + * src - the host buffer being read from + * + * dst - the host buffer being written to + * + * mmd_interface - the handle to the interface being accessed. E.g. To + * access global memory this handle will be whatever is returned by + * aocl_mmd_get_info when called with AOCL_MMD_MEMORY_INTERFACE. + * + * offset/src_offset/dst_offset - the byte offset within the interface that + * the transfer will begin at. + * + * The return value is 0 if the operation launch was successful, and + * negative otherwise. + */ +AOCL_MMD_CALL int aocl_mmd_read( + int handle, aocl_mmd_op_t op, size_t len, void* dst, int mmd_interface, size_t offset) WEAK; +AOCL_MMD_CALL int aocl_mmd_write( + int handle, aocl_mmd_op_t op, size_t len, const void* src, int mmd_interface, size_t offset) WEAK; +// AOCL_MMD_CALL int aocl_mmd_copy( +// int handle, aocl_mmd_op_t op, size_t len, int mmd_interface, size_t src_offset, size_t dst_offset) WEAK; + +/* Host Channel create operation + * Opens channel between host and kernel. + * + * Arguments: + * channel_name - name of channel to initialize. Same name as used in board_spec.xml + * + * queue_depth - the size in bytes of pinned memory queue in system memory + * + * direction - the direction of the channel + * + * The return value is negative if initialization was unsuccessful, and + * positive otherwise. Positive return value is handle to the channel to be used for + * subsequent calls for the channel. + */ +//AOCL_MMD_CALL int aocl_mmd_hostchannel_create(int handle, char* channel_name, size_t queue_depth, int direction) WEAK; + +/* Host Channel destroy operation + * Closes channel between host and kernel. + * + * Arguments: + * channel - the handle to the channel to close, that was obtained with + * create channel + * + * The return value is 0 if the destroy was successful, and negative + * otherwise. + */ +//AOCL_MMD_CALL int aocl_mmd_hostchannel_destroy(int handle, int channel) WEAK; + +/* Host Channel get buffer operation + * Provide host with pointer to buffer they can access to write or + * read from kernel, along with space or data available in the buffer + * in bytes. + * + * Arguments: + * channel - the handle to the channel to get the buffer for + * + * buffer_size - the address that this call will write the amount of + * space or data that's available in the buffer, + * depending on direction of the channel, in bytes + * + * status - the address that this call will write to for result of this + * call. Value will be 0 for success, and negative otherwise + * + * The return value is the pointer to the buffer that host can write + * to or read from. NULL if the status is negative. + */ +//AOCL_MMD_CALL void* aocl_mmd_hostchannel_get_buffer(int handle, int channel, size_t* buffer_size, int* status) WEAK; + +/* Host Channel acknowledge buffer operation + * Acknowledge to the channel that the user has written or read data from + * it. This will make the data or additional buffer space available to + * write to or read from kernel. + * + * Arguments: + * channel - the handle to the channel that user is acknowledging + * + * send_size - the size in bytes that the user is acknowledging + * + * status - the address that this call will write to for result of this + * call. Value will be 0 for success, and negative otherwise + * + * The return value is equal to send_size if send_size was less than or + * equal to the buffer_size from get buffer call. If send_size was + * greater, then return value is the amount that was actually sent. + */ +//AOCL_MMD_CALL size_t aocl_mmd_hostchannel_ack_buffer(int handle, int channel, size_t send_size, int* status) WEAK; + +/* Program the device + * + * The host will guarantee that no operations are currently executing on the + * device. That means the kernels will be idle and no read/write/copy + * commands are active. Interrupts should be disabled and the FPGA should + * be reprogrammed with the data from user_data which has size size. The host + * will then call aocl_mmd_set_status_handler and aocl_mmd_set_interrupt_handler + * again. At this point interrupts can be enabled. + * + * The new handle to the board after reprogram does not have to be the same as + * the one before. + * + * Arguments: + * user_data - The binary contents of the fpga.bin file created during + * Quartus II compilation. + * size - the size in bytes of user_data + * program_mode - bit field for programming attributes. See + * aocl_mmd_program_mode_t definition + * + * Returns: the new non-negative integer handle for the board, otherwise a + * negative value to indicate error. + */ + +// #ifdef DLA_MMD +// // CoreDLA BSP has removed some stuff that MMD tries to handshake with, so provide a "raw access" function to +// // reprogram the FPGA directly from the sof. Can't call quartus_pgm directly since the MMD still needs to mask +// // the PCIe surprise down error (when full-chip programming the FPGA, the CPU thinks a PCIe device has disappeared). +// // BEWARE: reprogramming will invalidate the handle +// AOCL_MMD_CALL int aocl_mmd_program_sof(int handle, const char* sof_filename) WEAK; +// #else +// AOCL_MMD_CALL int aocl_mmd_program(int handle, void* user_data, size_t size, aocl_mmd_program_mode_t program_mode) WEAK; +// #endif + +/** Error values*/ +#define AOCL_MMD_ERROR_SUCCESS 0 +#define AOCL_MMD_ERROR_INVALID_HANDLE -1 +#define AOCL_MMD_ERROR_OUT_OF_MEMORY -2 +#define AOCL_MMD_ERROR_UNSUPPORTED_ALIGNMENT -3 +#define AOCL_MMD_ERROR_UNSUPPORTED_PROPERTY -4 +#define AOCL_MMD_ERROR_INVALID_POINTER -5 +#define AOCL_MMD_ERROR_INVALID_MIGRATION_SIZE -6 + +/** Memory properties*/ +typedef enum { + /** + * Specifies the name of a global memory that can be found in the + * board_spec.xml file for the BSP. Allocations will be allocated to this + * global memory interface. + */ + AOCL_MMD_MEM_PROPERTIES_GLOBAL_MEMORY = 1, + /** + * Specifies the index of a bank inside the global memory interface that can be found in + * the board_spec.xml file for the BSP. Allocations will be allocated to this + * memory bank. It is invalid to specify this property without also specifying + * AOCL_MMD_GLOBAL_MEMORY_INTERFACE. + */ + AOCL_MMD_MEM_PROPERTIES_MEMORY_BANK +} aocl_mmd_mem_properties_t; + +/** + * Host allocations provide memory that is allocated on the host. Host + * allocations are accessible by the host and one or more devices. + * The same pointer to a host allocation may be used on the host and all + * supported devices; they have address equivalence. This memory must be + * deallocated with aocl_mmd_free(); + * + * Once the device has signaled completion through + * aocl_mmd_interrupt_handler_fn() the host can assume it has access to the + * latest contents of the memory, allocated by this call. + * + * @param handles Handles for devices that will need access to this memory + * @param num_devices Number of devices in the handles + * @param size The size of the memory region + * @param alignment The alignment in bytes of the allocation + * @param properties Specifies additional information about the allocated + * memory, described by a property type name and its corresponding value. + * Each property type name is immediately followed by the corresponding + * desired value. The list is terminated with 0. Supported values are + * described above. Example: [<property1>, <value1>, <property2>, <value2>, 0] + * @param error The error code defined by AOCL_MMD_ERROR* + * @return valid pointer, on error NULL + */ +// AOCL_MMD_CALL void* aocl_mmd_host_alloc(int* handles, +// size_t num_devices, +// size_t size, +// size_t alignment, +// aocl_mmd_mem_properties_t* properties, +// int* error) WEAK; + +/** + * Frees memory that has been allocated by MMD + * + * @param mem The pointer to the memory region. Must be a pointer that is + * allocated by the MMD. + * @return AOCL_MMD_ERROR_SUCCESS if success, else error code + */ +// AOCL_MMD_CALL int aocl_mmd_free(void* mem) WEAK; + +/** + * Allocate memory that is owned by the device. This pointer can only be + * accessed by the kernel; can't be accessed by the host. The host is able to + * manipulate the pointer (e.g. increment it) just not access the underlying + * data. This memory must be deallocated by aocl_mmd_free(); + * + * @param handle Device that will have access to this memory + * @param size The size of the memory region + * @param alignment The alignment in bytes of the memory region + * @param properties Specifies additional information about the allocated + * memory, described by a property type name and its corresponding value. + * Each property type name is immediately followed by the corresponding + * desired value. The list is terminated with 0. Supported values are + * described above. Example: [<property1>, <value1>, <property2>, <value2>, 0] + * @param error The error code defined by AOCL_MMD_ERROR* + * @return Pointer that can be passed into the kernel. NULL on failure. + */ +// AOCL_MMD_CALL void* aocl_mmd_device_alloc( +// int handle, size_t size, size_t alignment, aocl_mmd_mem_properties_t* properties, int* error) WEAK; + +/** + * Shared allocations may migrate between the host and one or more associated + * device. The same pointer to a shared allocation may be used on the host and + * the supported device; they have address equivalence. + * + * If the device does not support concurrent access to memory allocated by + * aocl_mmd_shared_alloc() then a call must be made to + * aocl_mmd_shared_mem_migrate() to indicate that the shared allocation should + * be migrated to the device before the device accesses this memory. For + * example, a call to aocl_mmd_shared_mem_migrate() should be made before a + * kernel accessing this memory is launched). Conversely, + * aocl_mmd_shared_mem_migrate() should be called again to indicate that the + * shared allocation should be migrated to the host before the host accesses + * this memory again. If the device supports concurrent access to memory + * allocated with aocl_mmd_shared_alloc(), then the call to + * aocl_mmd_shared_mem_migrate() is not necessary, but may still be made. In + * the case of concurrent access, it is the responsibility of the MMD to ensure + * both the device and host can access aocl_mmd_shared_alloc() allocations at + * all times. + * + * Memory allocated by aocl_mmd_shared_alloc() must be deallocated with + * aocl_mmd_free(). + * + * @param handle Device that will have access to this memory + * @param size The size of the memory region + * @param alignment The alignment in bytes of the memory region + * @param properties Specifies additional information about the allocated + * memory, described by a property type name and its corresponding value. + * Each property type name is immediately followed by the corresponding + * desired value. The list is terminated with 0. Supported properties are + * listed above and have the prefix AOCL_MMD_MEM_PROPERTIES_. + * Example: [<property1>, <value1>, <property2>, <value2>, 0] + * @param error The error code defined by AOCL_MMD_ERROR* + * @return valid pointer, on error NULL + */ +// AOCL_MMD_CALL void* aocl_mmd_shared_alloc( +// int handle, size_t size, size_t alignment, aocl_mmd_mem_properties_t* properties, int* error) WEAK; + +typedef enum { AOCL_MMD_MIGRATE_TO_HOST = 0, AOCL_MMD_MIGRATE_TO_DEVICE = 1 } aocl_mmd_migrate_t; + +/** + * A call to aocl_mmd_shared_migrate() must be made for non-concurrent shared + * allocations any time the accessor of the allocation changes. For example, + * aocl_mmd_shared_migrate() should be called indicating that the allocation + * should be migrated to the device before a kernel accessing the allocation + * is launched on the device. Similarly, aocl_mmd_shared_migrate() should be + * called indicating that the allocation is migrated to the host before the + * host accesses the memory after kernel completion. + * + * For concurrent allocations this call may be used as a performance hint, but + * is not strictly required for functionality. + * + * @param handle Device that will have access to this memory + * @param shared_ptr Pointer allocated by aocl_mmd_shared_alloc() + * @param size In bytes, the size of the migration. Must be of multiple of a + * page boundary that the BSP supports. + * @param destination The destination of migration + * @return The error code defined by AOCL_MMD_ERROR* + */ +// AOCL_MMD_CALL int aocl_mmd_shared_migrate(int handle, +// void* shared_ptr, +// size_t size, +// aocl_mmd_migrate_t destination) WEAK; + +// CoreDLA modifications +// To support multiple different FPGA boards, anything board specific must be implemented in a +// board-specific MMD instead of the CoreDLA runtime layer. +#ifdef DLA_MMD +// Query functions to get board-specific values +AOCL_MMD_CALL int dla_mmd_get_max_num_instances() WEAK; +AOCL_MMD_CALL uint64_t dla_mmd_get_ddr_size_per_instance() WEAK; +AOCL_MMD_CALL double dla_mmd_get_ddr_clock_freq() WEAK; + +// Wrappers around CSR and DDR reads and writes to abstract away board-specific offsets +AOCL_MMD_CALL int dla_mmd_csr_write(int handle, int instance, uint64_t addr, const uint32_t* data) WEAK; +AOCL_MMD_CALL int dla_mmd_csr_read(int handle, int instance, uint64_t addr, uint32_t* data) WEAK; +AOCL_MMD_CALL int dla_mmd_ddr_write(int handle, int instance, uint64_t addr, uint64_t length, const void* data) WEAK; +AOCL_MMD_CALL int dla_mmd_ddr_read(int handle, int instance, uint64_t addr, uint64_t length, void* data) WEAK; + +#define STREAM_CONTROLLER_ACCESS +#ifdef STREAM_CONTROLLER_ACCESS +AOCL_MMD_CALL bool dla_is_stream_controller_valid(int handle, int instance) WEAK; +AOCL_MMD_CALL int dla_mmd_stream_controller_write(int handle, int instance, uint64_t addr, uint64_t length, const void* data) WEAK; +AOCL_MMD_CALL int dla_mmd_stream_controller_read(int handle, int instance, uint64_t addr, uint64_t length, void* data) WEAK; +#endif + +// Get the PLL clock frequency in MHz, returns a negative value if there is an error +AOCL_MMD_CALL double dla_mmd_get_coredla_clock_freq(int handle) WEAK; +#endif + +#ifdef __cplusplus +} +#endif + +#endif |
