libhsakmt/virtio: add virtio support for libhsakmt
This patch adds VirtIO support to the libhsakmt library, enabling communication
with AMD GPUs via VirtIO.
Details
- CMakeLists.txt: Added a new CMakeLists.txt file for the VirtIO component
of libhsakmt.
- hsakmt_virtio.c/h: Implemented the core VirtIO functionality, including
VirtIO GPU device initialization, command execution, and memory management.
- virtio_gpu.c/h: Contains the implementation of the VirtIO GPU device,
including ioctl handling, shared memory management, and command execution.
- hsakmt_virtio_events.c: Implements event handling for VirtIO, such as event
creation, destruction, setting, resetting, and querying event states.
- hsakmt_virtio_memory.c: Manages memory operations for VirtIO, including memory
allocation, freeing, mapping, and unmapping.
- hsakmt_virtio_queues.c: Implements queue management for VirtIO, including
queue creation, destruction, and updating.
- hsakmt_virtio_topology.c: Handles system and node properties for VirtIO.
- hsakmt_virtio_vm.c: Manages VM-related operations for VirtIO, such as
reserving and dereserving VA space.
- include/linux/virtgpu_drm.h: Contains DRM definitions for VirtIO GPU.
Key Features
- VirtIO GPU Initialization: The library can now initialize a VirtIO GPU device
and communicate with it.
- Command Execution: Supports executing commands on the VirtIO GPU device.
- Memory Management: Provides functions for allocating, freeing, mapping, and
unmapping memory for VirtIO operations.
- Event Handling: Implements a comprehensive event system for VirtIO.
- Queue Management: Allows for creating, destroying, and updating queues
on the VirtIO GPU device.
- System and Node Properties: Retrieves and manages system and node
properties for VirtIO.
Signed-off-by: Honglei Huang <Honglei1.Huang@amd.com>
[ROCm/ROCR-Runtime commit: 48d3719dba]
This commit is contained in:
committed by
Huang, Honglei1
parent
2bd0f85f80
commit
5e68bd163a
@@ -108,12 +108,20 @@ if (HSA_DEP_ROCPROFILER_REGISTER)
|
||||
string(APPEND CPACK_RPM_BINARY_PACKAGE_REQUIRES " rocprofiler-register")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED BUILD_THUNK_VIRTIO)
|
||||
set(BUILD_THUNK_VIRTIO OFF)
|
||||
endif()
|
||||
|
||||
add_rocm_subdir(libhsakmt "${THUNK_DEFINITIONS}")
|
||||
set_target_properties(hsakmt PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/libhsakmt/archive"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/libhsakmt/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/libhsakmt/runtime")
|
||||
|
||||
if (BUILD_THUNK_VIRTIO)
|
||||
add_rocm_subdir(libhsakmt/src/virtio "${THUNK_VIRTIO_DEFINITIONS}")
|
||||
endif()
|
||||
|
||||
if (BUILD_ROCR)
|
||||
add_rocm_subdir(runtime/hsa-runtime "${ROCR_DEFINITIONS}")
|
||||
set_target_properties(hsa-runtime64 PROPERTIES
|
||||
@@ -123,6 +131,9 @@ if (BUILD_ROCR)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_dependencies(hsa-runtime64 hsakmt)
|
||||
if (BUILD_THUNK_VIRTIO)
|
||||
add_dependencies(hsa-runtime64 hsakmt_virtio)
|
||||
endif()
|
||||
else()
|
||||
add_dependencies(hsa-runtime64 hsakmt-staticdrm)
|
||||
endif()
|
||||
|
||||
@@ -211,7 +211,7 @@ install ( TARGETS ${HSAKMT_TARGET}
|
||||
|
||||
# Install public headers
|
||||
install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/${HSAKMT_TARGET} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT dev PATTERN "linux" EXCLUDE )
|
||||
COMPONENT dev PATTERN "linux" EXCLUDE PATTERN "*virtio*" EXCLUDE)
|
||||
|
||||
# Record our usage data for clients find_package calls.
|
||||
install ( EXPORT ${HSAKMT_TARGET}Targets
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright © 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including
|
||||
* the next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HSAKMT_VIRTIO_H
|
||||
#define HSAKMT_VIRTIO_H
|
||||
|
||||
#include "hsakmt/linux/kfd_ioctl.h"
|
||||
#include "hsakmt/hsakmt.h"
|
||||
#include <libdrm/amdgpu.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtOpenKFD(void);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCloseKFD(void);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAllocMemory(HSAuint32 PreferredNode, HSAuint64 SizeInBytes,
|
||||
HsaMemFlags MemFlags, void** MemoryAddress);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtFreeMemory(void* MemoryAddress, HSAuint64 SizeInBytes);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtMapMemoryToGPUNodes(void* MemoryAddress, HSAuint64 MemorySizeInBytes,
|
||||
HSAuint64* AlternateVAGPU,
|
||||
HsaMemMapFlags MemMapFlags,
|
||||
HSAuint64 NumberOfNodes, HSAuint32* NodeArray);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtUnmapMemoryToGPU(void* MemoryAddress);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAvailableMemory(HSAuint32 Node, HSAuint64* AvailableBytes);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtMapMemoryToGPU(void* MemoryAddress, HSAuint64 MemorySizeInBytes,
|
||||
HSAuint64* AlternateVAGPU);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRegisterMemoryWithFlags(void* MemoryAddress,
|
||||
HSAuint64 MemorySizeInBytes,
|
||||
HsaMemFlags MemFlags);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDeregisterMemory(void* MemoryAddress);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetVersion(HsaVersionInfo* v);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAcquireSystemProperties(HsaSystemProperties* SystemProperties);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtReleaseSystemProperties(void);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeProperties(HSAuint32 NodeId,
|
||||
HsaNodeProperties* NodeProperties);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetXNACKMode(HSAint32* enable);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRuntimeEnable(void* rDebug, bool setupTtmp);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRuntimeDisable(void);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeMemoryProperties(HSAuint32 NodeId, HSAuint32 NumBanks,
|
||||
HsaMemoryProperties* MemoryProperties);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeCacheProperties(HSAuint32 NodeId, HSAuint32 ProcessorId,
|
||||
HSAuint32 NumCaches,
|
||||
HsaCacheProperties* CacheProperties);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeIoLinkProperties(HSAuint32 NodeId, HSAuint32 NumIoLinks,
|
||||
HsaIoLinkProperties* IoLinkProperties);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetClockCounters(HSAuint32 NodeId, HsaClockCounters* Counters);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetAMDGPUDeviceHandle(HSAuint32 NodeId,
|
||||
HsaAMDGPUDeviceHandle* DeviceHandle);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtQueryPointerInfo(const void* Pointer, HsaPointerInfo* PointerInfo);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetTileConfig(HSAuint32 NodeId, HsaGpuTileConfig* config);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateEvent(HsaEventDescriptor* EventDesc, _Bool ManualReset,
|
||||
_Bool IsSignaled, HsaEvent** Event);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDestroyEvent(HsaEvent* Event);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtSetEvent(HsaEvent* Event);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtResetEvent(HsaEvent* Event);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtQueryEventState(HsaEvent* Event);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnMultipleEvents(HsaEvent* Events[], HSAuint32 NumEvents,
|
||||
bool WaitOnAll, HSAuint32 Milliseconds);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnEvent(HsaEvent* Event, HSAuint32 Milliseconds);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnEvent_Ext(HsaEvent* Event, HSAuint32 Milliseconds,
|
||||
uint64_t* event_age);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnMultipleEvents_Ext(HsaEvent* Events[], HSAuint32 NumEvents,
|
||||
bool WaitOnAll, HSAuint32 Milliseconds,
|
||||
uint64_t* event_age);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtSetTrapHandler(HSAuint32 NodeId, void* TrapHandlerBaseAddress,
|
||||
HSAuint64 TrapHandlerSizeInBytes,
|
||||
void* TrapBufferBaseAddress,
|
||||
HSAuint64 TrapBufferSizeInBytes);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateQueueExt(HSAuint32 NodeId, HSA_QUEUE_TYPE Type,
|
||||
HSAuint32 QueuePercentage,
|
||||
HSA_QUEUE_PRIORITY Priority, HSAuint32 SdmaEngineId,
|
||||
void* QueueAddress, HSAuint64 QueueSizeInBytes,
|
||||
HsaEvent* Event, HsaQueueResource* QueueResource);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateQueue(HSAuint32 NodeId, HSA_QUEUE_TYPE Type,
|
||||
HSAuint32 QueuePercentage, HSA_QUEUE_PRIORITY Priority,
|
||||
void* QueueAddress, HSAuint64 QueueSizeInBytes,
|
||||
HsaEvent* Event, HsaQueueResource* QueueResource);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDestroyQueue(HSA_QUEUEID QueueId);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRegisterGraphicsHandleToNodes(
|
||||
HSAuint64 GraphicsResourceHandle, HsaGraphicsResourceInfo* GraphicsResourceInfo,
|
||||
HSAuint64 NumberOfNodes, HSAuint32* NodeArray);
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetRuntimeCapabilities(HSAuint32* caps_mask);
|
||||
|
||||
int vamdgpu_query_gpu_info(amdgpu_device_handle dev, void* out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HSAKMT_VIRTIO_H */
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
# Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
cmake_minimum_required ( VERSION 3.7 )
|
||||
|
||||
set (CMAKE_VERBOSE_MAKEFILE ON)
|
||||
|
||||
set ( HSAKMT_VIRTIO "hsakmt_virtio" )
|
||||
set ( HSAKMT_VIRTIO_TARGET "${HSAKMT_VIRTIO}" )
|
||||
|
||||
project ( ${HSAKMT_VIRTIO_TARGET} VERSION 1.0)
|
||||
|
||||
## Compiler flags
|
||||
set ( HSAKMT_VIRTIO_C_FLAGS -fPIC -W -Wall -Wextra -Wno-unused-parameter -Wformat-security -Wswitch-default -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wunreachable-code -std=gnu99 -fvisibility=hidden )
|
||||
if ( CMAKE_COMPILER_IS_GNUCC )
|
||||
set ( HSAKMT_VIRTIO_C_FLAGS "${HSAKMT_VIRTIO_C_FLAGS}" -Wlogical-op )
|
||||
endif ()
|
||||
|
||||
set ( HSAKMT_VIRTIO_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libhsakmt_virtio.ver" )
|
||||
|
||||
set ( HSAKMT_VIRTIO_LINK_FLAGS "-Wl,--enable-new-dtags -Wl,--version-script=${HSAKMT_VIRTIO_LINKER_SCRIPT} -Wl,-z,nodelete")
|
||||
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL Release )
|
||||
set ( HSAKMT_VIRTIO_C_FLAGS "${HSAKMT_VIRTIO_C_FLAGS}" -O2 )
|
||||
else ()
|
||||
set ( HSAKMT_VIRTIO_C_FLAGS "${HSAKMT_VIRTIO_C_FLAGS}" -g )
|
||||
endif ()
|
||||
|
||||
set ( HSAKMT_VIRTIO_SRC "virtio_gpu.c"
|
||||
"hsakmt_virtio_vm.c"
|
||||
"hsakmt_virtio_device.c"
|
||||
"hsakmt_virtio_memory.c"
|
||||
"hsakmt_virtio_amdgpu.c"
|
||||
"hsakmt_virtio_events.c"
|
||||
"hsakmt_virtio_queues.c"
|
||||
"hsakmt_virtio_topology.c"
|
||||
"hsakmt_virtio_openclose.c"
|
||||
"../rbtree.c" )
|
||||
|
||||
add_library ( ${HSAKMT_VIRTIO_TARGET} STATIC ${HSAKMT_VIRTIO_SRC} )
|
||||
|
||||
target_sources ( ${HSAKMT_VIRTIO_TARGET} PRIVATE ${HSAKMT_VIRTIO_SRC} )
|
||||
|
||||
target_compile_options ( ${HSAKMT_VIRTIO_TARGET} PRIVATE ${HSAKMT_VIRTIO_C_FLAGS} )
|
||||
|
||||
target_include_directories ( ${HSAKMT_VIRTIO_TARGET}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/virtio
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/linux )
|
||||
|
||||
set_property(TARGET ${HSAKMT_VIRTIO_TARGET} PROPERTY LINK_FLAGS ${HSAKMT_VIRTIO_LINK_FLAGS})
|
||||
|
||||
find_package ( PkgConfig )
|
||||
|
||||
## If environment variable DRM_DIR is set, the script
|
||||
## will pick up the corresponding libraries from that path.
|
||||
list ( PREPEND CMAKE_PREFIX_PATH "${DRM_DIR}" )
|
||||
|
||||
pkg_check_modules ( DRM REQUIRED IMPORTED_TARGET libdrm )
|
||||
pkg_check_modules ( DRM_AMDGPU REQUIRED IMPORTED_TARGET libdrm_amdgpu )
|
||||
target_include_directories ( ${HSAKMT_VIRTIO_TARGET} PRIVATE ${DRM_AMDGPU_INCLUDE_DIRS} )
|
||||
target_include_directories ( ${HSAKMT_VIRTIO_TARGET} PRIVATE ${DRM_INCLUDE_DIRS} )
|
||||
|
||||
target_link_libraries ( ${HSAKMT_VIRTIO_TARGET}
|
||||
PRIVATE ${DRM_LDFLAGS} ${DRM_AMDGPU_LDFLAGS} pthread rt c ${CMAKE_DL_LIBS} )
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
int vamdgpu_query_gpu_info(amdgpu_device_handle handle, void* out) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GPU_INFO,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
int ret = vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
if (!ret) memcpy(out, &rsp->gpu_info, sizeof(struct amdgpu_gpu_info));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS vhsaKmtGetAMDGPUDeviceHandle(HSAuint32 NodeId, HsaAMDGPUDeviceHandle* DeviceHandle) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
return HSAKMT_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
||||
* license, and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
int vhsakmt_execbuf_cpu(vhsakmt_device_handle dev, struct vhsakmt_ccmd_req* req, const char* from) {
|
||||
return virtio_gpu_exec_cmd(dev->vgdev, req, true);
|
||||
}
|
||||
|
||||
void* vhsakmt_alloc_rsp(vhsakmt_device_handle dev, struct vhsakmt_ccmd_req* req, uint32_t sz) {
|
||||
return virtio_gpu_alloc_rsp(dev->vgdev, req, sz);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
||||
* license, and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HSAKMT_VIRTIO_DEVICE_H
|
||||
#define HSAKMT_VIRTIO_DEVICE_H
|
||||
|
||||
#include "hsakmt_virtio_proto.h"
|
||||
#include "rbtree.h"
|
||||
#include "virtio_gpu.h"
|
||||
#include <stdatomic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define vhsakmt_atomic_inc_return(ptr) (atomic_fetch_add((ptr), 1) + 1)
|
||||
#define vhsakmt_atomic_dec_return(ptr) (atomic_fetch_sub((ptr), 1) - 1)
|
||||
|
||||
#define VHSA_VPTR_TO_UINT64(vptr) ((uint64_t)(unsigned long)(vptr))
|
||||
#define VHSA_UINT64_TO_VPTR(v) ((void*)(unsigned long)(v))
|
||||
|
||||
extern int vhsakmt_debug_level;
|
||||
#define vhsakmt_print(level, fmt, ...) \
|
||||
do { \
|
||||
if (level <= vhsakmt_debug_level) fprintf(stderr, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define VHSAKMT_DEBUG_LEVEL_DEFAULT -1
|
||||
#define VHSAKMT_DEBUG_LEVEL_ERR 3
|
||||
#define VHSAKMT_DEBUG_LEVEL_WARNING 4
|
||||
#define VHSAKMT_DEBUG_LEVEL_INFO 6
|
||||
#define VHSAKMT_DEBUG_LEVEL_DEBUG 7
|
||||
#define vhsa_err(fmt, ...) vhsakmt_print(VHSAKMT_DEBUG_LEVEL_ERR, fmt, ##__VA_ARGS__)
|
||||
#define vhsa_warn(fmt, ...) vhsakmt_print(VHSAKMT_DEBUG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
|
||||
#define vhsa_info(fmt, ...) vhsakmt_print(VHSAKMT_DEBUG_LEVEL_INFO, fmt, ##__VA_ARGS__)
|
||||
#define vhsa_debug(fmt, ...) vhsakmt_print(VHSAKMT_DEBUG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
|
||||
|
||||
struct vhsakmt_device;
|
||||
struct vhsakmt_bo;
|
||||
|
||||
typedef struct vhsakmt_device* vhsakmt_device_handle;
|
||||
typedef struct vhsakmt_bo* vhsakmt_bo_handle;
|
||||
typedef rbtree_node_t* bo_entry;
|
||||
|
||||
extern pthread_mutex_t dev_mutex;
|
||||
extern vhsakmt_device_handle dev_list;
|
||||
|
||||
#define VHSA_BO_KFD_MEM 1 << 0 /* allocated from KFD (hsaKmtAllocMemory) */
|
||||
#define VHSA_BO_USERPTR 1 << 1
|
||||
#define VHSA_BO_QUEUE_BUFFER 1 << 2 /* allocated from KFD, but used for queue CMD submit */
|
||||
#define VHSA_BO_QUEUE_DOORBELL 1 << 3 /* doorbell memory */
|
||||
#define VHSA_BO_QUEUE_RW_PTR 1 << 4 /* queue read write ptr, from host map to guest*/
|
||||
/* allocated from KFD, but used for AQL queue read write ptr */
|
||||
#define VHSA_BO_QUEUE_AQL_RW_PTR 1 << 5
|
||||
#define VHSA_BO_CLGL 1 << 6 /* CLGL memory, imported from mesa GL */
|
||||
/* allocated from KFD, but is scratch memory, do not need map and unmap in ioctrl */
|
||||
#define VHSA_BO_SCRATCH 1 << 7
|
||||
#define VHSA_BO_QUEUE 1 << 8
|
||||
#define VHSA_BO_EVENT 1 << 9
|
||||
#define VHSA_BO_SCRATCH_MAP 1 << 10
|
||||
|
||||
#define VHSA_SDMA_NONE UINT32_MAX
|
||||
|
||||
#define CHECK_VIRTIO_KFD_OPEN() \
|
||||
do { \
|
||||
if (dev_list == NULL) return HSAKMT_STATUS_KERNEL_IO_CHANNEL_NOT_OPENED; \
|
||||
} while (0)
|
||||
|
||||
struct vhsakmt_node {
|
||||
HsaNodeProperties node_props;
|
||||
void* doorbell_base;
|
||||
uint64_t scratch_start;
|
||||
uint64_t scratch_size;
|
||||
};
|
||||
|
||||
struct vhsakmt_device {
|
||||
struct virtio_gpu_device* vgdev;
|
||||
int refcount;
|
||||
pthread_mutex_t bo_handles_mutex;
|
||||
rbtree_t bo_rbt;
|
||||
|
||||
struct vhsakmt_bo* shmem_bo;
|
||||
|
||||
uint32_t reqbuf_max;
|
||||
uint32_t next_blob_id;
|
||||
|
||||
uint64_t vm_start;
|
||||
uint64_t vm_size;
|
||||
|
||||
pthread_mutex_t vhsakmt_mutex;
|
||||
struct vhsakmt_node* vhsakmt_nodes;
|
||||
HsaSystemProperties* sys_props;
|
||||
};
|
||||
|
||||
struct vhsakmt_bo {
|
||||
rbtree_node_t rbtn;
|
||||
struct vhsakmt_device* dev;
|
||||
|
||||
int refcount;
|
||||
unsigned size;
|
||||
void* cpu_addr;
|
||||
void* host_addr;
|
||||
HsaMemFlags flags;
|
||||
uint32_t bo_type;
|
||||
uint32_t blob_id;
|
||||
pthread_mutex_t map_mutex;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t handle;
|
||||
uint32_t res_id;
|
||||
uint64_t offset;
|
||||
uint64_t alloc_size;
|
||||
int map_count;
|
||||
} real;
|
||||
};
|
||||
|
||||
vHsaEvent* event;
|
||||
uint64_t queue_id;
|
||||
vhsakmt_bo_handle rw_bo;
|
||||
void* gl_meta_data;
|
||||
};
|
||||
|
||||
/*hsakmt_virtio_memory.c*/
|
||||
vhsakmt_bo_handle vhsakmt_entry_to_bo_handle(bo_entry e);
|
||||
bo_entry vhsakmt_bo_handle_to_entry(vhsakmt_bo_handle bo);
|
||||
|
||||
void vhsakmt_insert_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo, void* addr, uint64_t size);
|
||||
void vhsakmt_remove_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo);
|
||||
vhsakmt_bo_handle vhsakmt_find_bo_by_addr(vhsakmt_device_handle dev, void* addr);
|
||||
void* vhsakmt_gpu_va(vhsakmt_device_handle dev, void* va);
|
||||
|
||||
int vhsakmt_bo_cpu_unmap(vhsakmt_bo_handle bo);
|
||||
int vhsakmt_bo_cpu_map(vhsakmt_bo_handle bo_handle, void** cpu, void* fixed_cpu);
|
||||
int vhsakmt_create_mappable_blob_bo(vhsakmt_device_handle dev, size_t size, uint32_t blob_id,
|
||||
uint32_t bo_type, void* va_handle,
|
||||
vhsakmt_bo_handle* bo_handle);
|
||||
int vhsakmt_bo_free(vhsakmt_device_handle dev, vhsakmt_bo_handle bo);
|
||||
int vhsakmt_init_host_blob(vhsakmt_device_handle dev, size_t size, uint32_t blob_type,
|
||||
uint32_t blob_flag, uint32_t blob_id, uint32_t bo_type, void* va_handle,
|
||||
vhsakmt_bo_handle* bo_handle);
|
||||
|
||||
/*hsakmt_virtio_openclose.c*/
|
||||
vhsakmt_device_handle vhsakmt_dev(void);
|
||||
|
||||
/*hsakmt_virtio_vm.c*/
|
||||
void* vhsakmt_vm_start(void);
|
||||
int vhsakmt_reserve_va(uint64_t start, uint64_t size);
|
||||
void vhsakmt_dereserve_va(uint64_t start, uint64_t size);
|
||||
void vhsakmt_set_scratch_area(vhsakmt_device_handle dev, uint32_t node, uint64_t start,
|
||||
uint64_t size);
|
||||
void vhsakmt_set_vm_area(vhsakmt_device_handle dev, uint64_t start, uint64_t size);
|
||||
int vhsakmt_set_node_doorbell(vhsakmt_device_handle dev, uint32_t node, void* doorbell);
|
||||
void* vhsakmt_node_doorbell(vhsakmt_device_handle dev, uint32_t node);
|
||||
bool vhsakmt_is_scratch_mem(vhsakmt_device_handle dev, void* addr);
|
||||
bool vhsakmt_is_userptr(vhsakmt_device_handle dev, void* addr);
|
||||
|
||||
/*hsakmt_virtio_device.c*/
|
||||
int vhsakmt_execbuf_cpu(vhsakmt_device_handle dev, struct vhsakmt_ccmd_req* req, const char* from);
|
||||
void* vhsakmt_alloc_rsp(vhsakmt_device_handle dev, struct vhsakmt_ccmd_req* req, uint32_t sz);
|
||||
|
||||
/*hsakmt_virtio_event.c*/
|
||||
void* vhsakmt_event_host_handle(HsaEvent* h);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
int vhsakmt_debug_level;
|
||||
|
||||
void* vhsakmt_event_host_handle(HsaEvent* h) { return (void*)((vHsaEvent*)h)->event_handle; }
|
||||
|
||||
static inline int32_t vhsakmt_event_res_id(HsaEvent* h) { return ((vHsaEvent*)h)->res_id; }
|
||||
|
||||
static inline vhsakmt_bo_handle vhsakmt_event_bo_handle(HsaEvent* h) {
|
||||
return (vhsakmt_bo_handle)((vHsaEvent*)h)->bo_handle;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_event_blob_bo(vhsakmt_device_handle dev, size_t size, uint32_t blob_id,
|
||||
vHsaEvent* vevent_handle, vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
|
||||
r = vhsakmt_init_host_blob(dev, size, VIRTGPU_BLOB_MEM_HOST3D, 0, blob_id, VHSA_BO_EVENT,
|
||||
(void*)vevent_handle->event_handle, bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
(*bo_handle)->event = vevent_handle;
|
||||
vevent_handle->bo_handle = (uint64_t)(*bo_handle);
|
||||
vevent_handle->res_id = (*bo_handle)->real.res_id;
|
||||
vhsakmt_insert_bo(dev, *bo_handle, vevent_handle, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateEvent(HsaEventDescriptor* EventDesc, _Bool ManualReset,
|
||||
_Bool IsSignaled, HsaEvent** Event) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_event_rsp* rsp;
|
||||
vhsakmt_bo_handle event_bo;
|
||||
vHsaEvent* e;
|
||||
int r;
|
||||
struct vhsakmt_ccmd_event_req req = {
|
||||
.hdr = VHSAKMT_CCMD(EVENT, sizeof(struct vhsakmt_ccmd_event_req)),
|
||||
.type = VHSAKMT_CCMD_EVENT_CREATE,
|
||||
.create_args.EventDesc = *EventDesc,
|
||||
.create_args.ManualReset = ManualReset,
|
||||
.create_args.IsSignaled = IsSignaled,
|
||||
.blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id),
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_event_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (rsp->ret) return rsp->ret;
|
||||
|
||||
e = calloc(1, sizeof(vHsaEvent));
|
||||
if (!e) return -ENOMEM;
|
||||
|
||||
memcpy(e, &rsp->vevent, sizeof(vHsaEvent));
|
||||
|
||||
r = vhsakmt_create_event_blob_bo(dev, sizeof(vHsaEvent), req.blob_id, e, &event_bo);
|
||||
if (r) {
|
||||
free(e);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*Event = (HsaEvent*)e;
|
||||
|
||||
vhsa_debug(
|
||||
"%s: event addr: %p, hw123: %lx, %lx, %x, type: %d, id: %x, host handle: 0x%lx, res id: %d\n",
|
||||
__FUNCTION__, e, e->event.EventData.HWData1, e->event.EventData.HWData2,
|
||||
e->event.EventData.HWData3, e->event.EventData.EventType, e->event.EventId, e->event_handle,
|
||||
event_bo->real.res_id);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDestroyEvent(HsaEvent* Event) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_bo* bo;
|
||||
|
||||
if (Event == NULL) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
bo = vhsakmt_event_bo_handle(Event);
|
||||
if (!bo) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
return vhsakmt_bo_free(dev, bo);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtSetEvent(HsaEvent* Event) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_event_rsp* rsp;
|
||||
struct vhsakmt_ccmd_event_req req = {
|
||||
.hdr = VHSAKMT_CCMD(EVENT, sizeof(struct vhsakmt_ccmd_event_req)),
|
||||
.type = VHSAKMT_CCMD_EVENT_SET,
|
||||
.event_hanele = vhsakmt_event_host_handle(Event),
|
||||
.res_id = vhsakmt_event_res_id(Event),
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_event_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtResetEvent(HsaEvent* Event) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_event_rsp* rsp;
|
||||
struct vhsakmt_ccmd_event_req req = {
|
||||
.hdr = VHSAKMT_CCMD(EVENT, sizeof(struct vhsakmt_ccmd_event_req)),
|
||||
.type = VHSAKMT_CCMD_EVENT_RESET,
|
||||
.event_hanele = vhsakmt_event_host_handle(Event),
|
||||
.res_id = vhsakmt_event_res_id(Event),
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_event_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtQueryEventState(HsaEvent* Event) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_event_rsp* rsp;
|
||||
struct vhsakmt_ccmd_event_req req = {
|
||||
.hdr = VHSAKMT_CCMD(EVENT, sizeof(struct vhsakmt_ccmd_event_req)),
|
||||
.type = VHSAKMT_CCMD_EVENT_QUERY_STATE,
|
||||
.event_hanele = vhsakmt_event_host_handle(Event),
|
||||
.res_id = vhsakmt_event_res_id(Event),
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_event_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnMultipleEvents(HsaEvent* Events[], HSAuint32 NumEvents,
|
||||
bool WaitOnAll, HSAuint32 Milliseconds) {
|
||||
return HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnEvent(HsaEvent* Event, HSAuint32 Milliseconds) {
|
||||
return vhsaKmtWaitOnMultipleEvents(&Event, 1, true, Milliseconds);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnEvent_Ext(HsaEvent* Event, HSAuint32 Milliseconds,
|
||||
uint64_t* event_age) {
|
||||
return vhsaKmtWaitOnMultipleEvents(&Event, 1, true, Milliseconds);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtWaitOnMultipleEvents_Ext(HsaEvent* Events[], HSAuint32 NumEvents,
|
||||
bool WaitOnAll, HSAuint32 Milliseconds,
|
||||
uint64_t* event_age) {
|
||||
return vhsaKmtWaitOnMultipleEvents(Events, NumEvents, WaitOnAll, Milliseconds);
|
||||
}
|
||||
@@ -0,0 +1,852 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
#define VHSA_GL_METADATA_MAX_SIZE (0x50)
|
||||
|
||||
vhsakmt_bo_handle vhsakmt_entry_to_bo_handle(bo_entry e) { return (vhsakmt_bo_handle)e; }
|
||||
bo_entry vhsakmt_bo_handle_to_entry(vhsakmt_bo_handle bo) { return &bo->rbtn; }
|
||||
static inline bool vhsakmt_is_mem_bo(vhsakmt_bo_handle bo) { return (!bo->queue_id && !bo->event); }
|
||||
|
||||
static bool vhsakmt_mappable(HsaMemFlags flags) { return (!flags.ui32.Scratch); }
|
||||
|
||||
static bool vhsakmt_bo_mappable(vhsakmt_bo_handle bo) { return vhsakmt_mappable(bo->flags); }
|
||||
|
||||
void vhsakmt_insert_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo, void* addr, uint64_t size) {
|
||||
bo->rbtn.key.addr = (unsigned long)addr;
|
||||
bo->rbtn.key.size = (unsigned long)size;
|
||||
|
||||
pthread_mutex_lock(&dev->bo_handles_mutex);
|
||||
hsakmt_rbtree_insert(&dev->bo_rbt, &bo->rbtn);
|
||||
pthread_mutex_unlock(&dev->bo_handles_mutex);
|
||||
}
|
||||
|
||||
static void vhsakmt_remove_entry(vhsakmt_device_handle dev, bo_entry entry) {
|
||||
if (!entry) return;
|
||||
|
||||
pthread_mutex_lock(&dev->bo_handles_mutex);
|
||||
hsakmt_rbtree_delete(&dev->bo_rbt, entry);
|
||||
pthread_mutex_unlock(&dev->bo_handles_mutex);
|
||||
}
|
||||
|
||||
void vhsakmt_remove_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo) {
|
||||
bo_entry entry = vhsakmt_bo_handle_to_entry(bo);
|
||||
if (entry->key.addr == 0 && entry->key.size == 0) return;
|
||||
|
||||
vhsakmt_remove_entry(dev, entry);
|
||||
}
|
||||
|
||||
static bo_entry vhsakmt_rbt_search(vhsakmt_device_handle dev, void* addr) {
|
||||
vhsakmt_bo_handle bo;
|
||||
|
||||
rbtree_key_t key = rbtree_key((uint64_t)addr, 0);
|
||||
pthread_mutex_lock(&dev->bo_handles_mutex);
|
||||
bo_entry n = rbtree_lookup_nearest(&dev->bo_rbt, &key, LKP_ADDR, RIGHT);
|
||||
pthread_mutex_unlock(&dev->bo_handles_mutex);
|
||||
if (n) {
|
||||
bo = vhsakmt_entry_to_bo_handle(n);
|
||||
if (bo->cpu_addr != addr) return NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bo_entry vhsakmt_find_entry_by_addr(vhsakmt_device_handle dev, void* addr) {
|
||||
return vhsakmt_rbt_search(dev, addr);
|
||||
}
|
||||
|
||||
vhsakmt_bo_handle vhsakmt_find_bo_by_addr(vhsakmt_device_handle dev, void* addr) {
|
||||
bo_entry entry = vhsakmt_find_entry_by_addr(dev, addr);
|
||||
|
||||
if (entry) {
|
||||
vhsakmt_bo_handle bo = vhsakmt_entry_to_bo_handle(entry);
|
||||
if (!vhsakmt_is_mem_bo(bo)) return NULL;
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* vhsakmt_gpu_va(vhsakmt_device_handle dev, void* va) {
|
||||
if (!vhsakmt_is_userptr(dev, va)) return va;
|
||||
|
||||
bo_entry entry = vhsakmt_find_entry_by_addr(dev, va);
|
||||
|
||||
if (!entry) return NULL;
|
||||
|
||||
return vhsakmt_entry_to_bo_handle(entry)->host_addr;
|
||||
}
|
||||
|
||||
int vhsakmt_bo_cpu_map(vhsakmt_bo_handle bo, void** cpu, void* fixed_cpu) {
|
||||
int r;
|
||||
|
||||
if (!vhsakmt_bo_mappable(bo)) return 0;
|
||||
|
||||
pthread_mutex_lock(&bo->map_mutex);
|
||||
|
||||
if (!bo->cpu_addr) {
|
||||
r = virtio_gpu_map_handle(bo->dev->vgdev, bo->real.handle, bo->size, cpu, fixed_cpu);
|
||||
if (r) {
|
||||
pthread_mutex_unlock(&bo->map_mutex);
|
||||
return r;
|
||||
}
|
||||
bo->cpu_addr = *cpu;
|
||||
atomic_fetch_add(&bo->real.map_count, 1);
|
||||
}
|
||||
pthread_mutex_unlock(&bo->map_mutex);
|
||||
|
||||
return *cpu == MAP_FAILED;
|
||||
}
|
||||
|
||||
int vhsakmt_bo_cpu_unmap(vhsakmt_bo_handle bo) {
|
||||
int r = 0;
|
||||
|
||||
if (!vhsakmt_bo_mappable(bo)) return 0;
|
||||
|
||||
pthread_mutex_lock(&bo->map_mutex);
|
||||
|
||||
if (!bo->cpu_addr || bo->real.map_count == 0) {
|
||||
pthread_mutex_unlock(&bo->map_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vhsakmt_atomic_dec_return(&bo->real.map_count) <= 0) {
|
||||
if (bo->bo_type & VHSA_BO_KFD_MEM) {
|
||||
virtio_gpu_unmap(bo->cpu_addr, bo->size);
|
||||
vhsakmt_reserve_va(VHSA_VPTR_TO_UINT64(bo->cpu_addr), bo->size);
|
||||
bo->cpu_addr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&bo->map_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhsakmt_destroy_handle(vhsakmt_device_handle dev, vhsakmt_bo_handle bo) {
|
||||
int r = virtio_gpu_destroy_handle(dev->vgdev, bo->real.handle);
|
||||
free(bo);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int vhsakmt_init_host_blob(vhsakmt_device_handle dev, size_t size, uint32_t blob_type,
|
||||
uint32_t blob_flag, uint32_t blob_id, uint32_t bo_type, void* va_handle,
|
||||
vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
vhsakmt_bo_handle bo;
|
||||
struct drm_virtgpu_resource_create_blob args = {
|
||||
.blob_mem = blob_type,
|
||||
.size = size,
|
||||
.blob_id = blob_id,
|
||||
.blob_flags = blob_flag,
|
||||
};
|
||||
|
||||
r = virtio_gpu_create_blob(dev->vgdev, &args);
|
||||
if (r) return -EINVAL;
|
||||
|
||||
bo = calloc(1, sizeof(struct vhsakmt_bo));
|
||||
if (!bo) {
|
||||
virtio_gpu_destroy_handle(dev->vgdev, args.bo_handle);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bo->dev = dev;
|
||||
bo->size = size;
|
||||
bo->real.alloc_size = size;
|
||||
bo->bo_type = bo_type;
|
||||
bo->host_addr = va_handle;
|
||||
pthread_mutex_init(&bo->map_mutex, NULL);
|
||||
atomic_store(&bo->real.map_count, 0);
|
||||
atomic_store(&bo->refcount, 1);
|
||||
bo->real.handle = args.bo_handle;
|
||||
|
||||
virtio_gpu_res_id(dev->vgdev, bo->real.handle, &bo->real.res_id);
|
||||
|
||||
*bo_handle = bo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhsakmt_init_userptr_blob(vhsakmt_device_handle dev, void* addr, size_t size,
|
||||
vhsakmt_bo_handle* bo_handle, uint64_t* offset) {
|
||||
int r;
|
||||
struct drm_virtgpu_resource_create_blob args = {
|
||||
.blob_mem = VIRTGPU_BLOB_MEM_HOST3D_GUEST,
|
||||
.blob_flags = VIRTGPU_BLOB_FLAG_USE_USERPTR,
|
||||
.size = size,
|
||||
.blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id),
|
||||
.blob_userptr = (uint64_t)addr,
|
||||
};
|
||||
|
||||
r = virtio_gpu_create_blob(dev->vgdev, &args);
|
||||
if (r < 0) return r;
|
||||
|
||||
vhsakmt_bo_handle userptr = calloc(1, sizeof(struct vhsakmt_bo));
|
||||
if (!userptr) {
|
||||
virtio_gpu_destroy_handle(dev->vgdev, args.bo_handle);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
userptr->dev = dev;
|
||||
userptr->size = size;
|
||||
userptr->real.alloc_size = size;
|
||||
userptr->bo_type = VHSA_BO_USERPTR;
|
||||
userptr->cpu_addr = addr;
|
||||
pthread_mutex_init(&userptr->map_mutex, NULL);
|
||||
atomic_store(&userptr->real.map_count, 0);
|
||||
atomic_store(&userptr->refcount, 1);
|
||||
userptr->real.handle = args.bo_handle;
|
||||
|
||||
virtio_gpu_res_id(dev->vgdev, userptr->real.handle, &userptr->real.res_id);
|
||||
|
||||
*bo_handle = userptr;
|
||||
*offset = args.offset;
|
||||
return r;
|
||||
}
|
||||
|
||||
int vhsakmt_create_mappable_blob_bo(vhsakmt_device_handle dev, size_t size, uint32_t blob_id,
|
||||
uint32_t bo_type, void* va_handle,
|
||||
vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
|
||||
r = vhsakmt_init_host_blob(dev, size, VIRTGPU_BLOB_MEM_HOST3D, VIRTGPU_BLOB_FLAG_USE_MAPPABLE,
|
||||
blob_id, bo_type, va_handle, bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
r = vhsakmt_bo_cpu_map(*bo_handle, &((*bo_handle)->cpu_addr), va_handle);
|
||||
if (r) {
|
||||
free(*bo_handle);
|
||||
*bo_handle = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (va_handle && (va_handle != (*bo_handle)->cpu_addr))
|
||||
vhsa_warn("%s: target map: %p != real map: %p\n", __FUNCTION__, va_handle,
|
||||
(*bo_handle)->cpu_addr);
|
||||
|
||||
vhsakmt_insert_bo(dev, *bo_handle, (*bo_handle)->cpu_addr, (*bo_handle)->size);
|
||||
return r;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAllocMemory(HSAuint32 PreferredNode, HSAuint64 SizeInBytes,
|
||||
HsaMemFlags MemFlags, void** MemoryAddress) {
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
vhsakmt_bo_handle bo;
|
||||
int r;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_ALLOC,
|
||||
.blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id),
|
||||
.alloc_args =
|
||||
{
|
||||
.PreferredNode = PreferredNode,
|
||||
.SizeInBytes = SizeInBytes,
|
||||
.MemFlags = MemFlags,
|
||||
},
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (rsp->ret) return rsp->ret;
|
||||
|
||||
if (!rsp->memory_handle) return -ENOMEM;
|
||||
|
||||
r = vhsakmt_init_host_blob(dev, SizeInBytes, VIRTGPU_BLOB_MEM_HOST3D,
|
||||
vhsakmt_mappable(MemFlags) ? VIRTGPU_BLOB_FLAG_USE_MAPPABLE : 0,
|
||||
req.blob_id, VHSA_BO_KFD_MEM, (void*)rsp->memory_handle, &bo);
|
||||
if (r) return r;
|
||||
|
||||
if (!vhsakmt_mappable(MemFlags)) {
|
||||
bo->cpu_addr = bo->host_addr;
|
||||
if (MemFlags.ui32.Scratch) {
|
||||
vhsakmt_set_scratch_area(dev, PreferredNode, (uint64_t)bo->cpu_addr, SizeInBytes);
|
||||
bo->bo_type |= VHSA_BO_SCRATCH;
|
||||
}
|
||||
} else {
|
||||
r = vhsakmt_bo_cpu_map(bo, &bo->cpu_addr, bo->host_addr);
|
||||
if (r) {
|
||||
free(bo);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MemFlags.ui32.Scratch) vhsakmt_insert_bo(dev, bo, bo->cpu_addr, bo->size);
|
||||
|
||||
*MemoryAddress = bo->cpu_addr;
|
||||
|
||||
vhsa_debug("alloc mem addr: %p, host addr: %p, size: %lx, res-id: %d, handble: %d\n",
|
||||
*MemoryAddress, bo->host_addr, SizeInBytes, bo->real.res_id, bo->real.handle);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
int vhsakmt_bo_free(vhsakmt_device_handle dev, vhsakmt_bo_handle bo) {
|
||||
bo_entry entry;
|
||||
int r;
|
||||
|
||||
if (vhsakmt_atomic_dec_return(&bo->refcount) > 0) return 0;
|
||||
|
||||
entry = vhsakmt_bo_handle_to_entry(bo);
|
||||
if (entry->key.addr == 0 && entry->key.size == 0) return -EINVAL;
|
||||
|
||||
/* do not free BOs of queue, let them be freed with queue */
|
||||
if (bo->bo_type & VHSA_BO_QUEUE_DOORBELL) {
|
||||
vhsa_err("%s: Try to free VHSA_BO_QUEUE_DOORBELL memory: %p\n", __FUNCTION__, bo->cpu_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vhsakmt_remove_bo(dev, bo);
|
||||
|
||||
if (bo->cpu_addr) vhsakmt_bo_cpu_unmap(bo);
|
||||
|
||||
if (bo->event) free(bo->event);
|
||||
|
||||
if (bo->gl_meta_data) free(bo->gl_meta_data);
|
||||
|
||||
pthread_mutex_destroy(&bo->map_mutex);
|
||||
|
||||
r = vhsakmt_destroy_handle(dev, bo);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Only remove bo in rbtree */
|
||||
static void vhsakmt_remove_userptr_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo) {
|
||||
vhsakmt_remove_bo(dev, bo);
|
||||
free(bo);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtFreeMemory(void* MemoryAddress, HSAuint64 SizeInBytes) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
vhsakmt_bo_handle bo = vhsakmt_find_bo_by_addr(dev, MemoryAddress);
|
||||
if (!bo) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
vhsa_debug("%s: addr: %p, size: %lx, res_id: %d\n", __FUNCTION__, MemoryAddress, SizeInBytes,
|
||||
bo->real.res_id);
|
||||
|
||||
return vhsakmt_bo_free(dev, bo);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtMapMemoryToGPUNodes(void* MemoryAddress, HSAuint64 MemorySizeInBytes,
|
||||
HSAuint64* AlternateVAGPU,
|
||||
HsaMemMapFlags MemMapFlags,
|
||||
HSAuint64 NumberOfNodes, HSAuint32* NodeArray) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
size_t req_len =
|
||||
VHSA_ALIGN_UP(sizeof(struct vhsakmt_ccmd_memory_req) + NumberOfNodes * sizeof(*NodeArray), 8);
|
||||
struct vhsakmt_ccmd_memory_req* req;
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
vhsakmt_bo_handle bo;
|
||||
|
||||
req = (void*)calloc(1, req_len);
|
||||
if (!req) return -ENOMEM;
|
||||
req->hdr = VHSAKMT_CCMD(MEMORY, req_len);
|
||||
req->type = VHSAKMT_CCMD_MEMORY_MAP_TO_GPU_NODES;
|
||||
req->map_to_GPU_nodes_args.MemorySizeInBytes = MemorySizeInBytes;
|
||||
req->map_to_GPU_nodes_args.MemMapFlags = MemMapFlags;
|
||||
req->map_to_GPU_nodes_args.NumberOfNodes = NumberOfNodes;
|
||||
|
||||
bo = vhsakmt_find_bo_by_addr(dev, MemoryAddress);
|
||||
if (bo) {
|
||||
req->map_to_GPU_nodes_args.MemoryAddress = (uint64_t)bo->host_addr;
|
||||
if (bo->bo_type & VHSA_BO_USERPTR) vhsakmt_remove_userptr_bo(dev, bo);
|
||||
} else
|
||||
req->map_to_GPU_nodes_args.MemoryAddress = (uint64_t)MemoryAddress;
|
||||
|
||||
memcpy(req->payload, NodeArray, NumberOfNodes * sizeof(*NodeArray));
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req->hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) {
|
||||
free(req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req->hdr, __FUNCTION__);
|
||||
|
||||
*AlternateVAGPU = rsp->alternate_vagpu;
|
||||
|
||||
vhsa_debug("%s: gva: %p, hva: 0x%lx, size: %lx, AlternateVAGPU: %lx, ret: %d\n", __FUNCTION__,
|
||||
MemoryAddress, req->map_to_GPU_nodes_args.MemoryAddress, MemorySizeInBytes,
|
||||
*AlternateVAGPU, rsp->ret);
|
||||
|
||||
free(req);
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtUnmapMemoryToGPU(void* MemoryAddress) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
vhsakmt_bo_handle bo = vhsakmt_find_bo_by_addr(dev, MemoryAddress);
|
||||
if (!bo) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_UNMAP_TO_GPU,
|
||||
.MemoryAddress = (uint64_t)bo->host_addr,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
vhsa_debug("%s: gva: %p, hva: 0x%lx\n", __FUNCTION__, MemoryAddress, req.MemoryAddress);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAvailableMemory(HSAuint32 Node, HSAuint64* AvailableBytes) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_AVAIL_MEM,
|
||||
.Node = Node,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
*AvailableBytes = rsp->available_bytes;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_scratch_map_memory(vhsakmt_device_handle dev, void* MemoryAddress,
|
||||
HSAuint64 MemorySizeInBytes,
|
||||
HSAuint64* AlternateVAGPU) {
|
||||
vhsakmt_bo_handle out;
|
||||
int r;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_MAP_MEM_TO_GPU,
|
||||
.blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id),
|
||||
.map_to_GPU_args =
|
||||
{
|
||||
.MemoryAddress = (uint64_t)MemoryAddress,
|
||||
.MemorySizeInBytes = MemorySizeInBytes,
|
||||
.need_create_bo = true,
|
||||
},
|
||||
};
|
||||
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp =
|
||||
vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
if (rsp->ret) return rsp->ret;
|
||||
|
||||
r = vhsakmt_init_host_blob(dev, MemorySizeInBytes, VIRTGPU_BLOB_MEM_HOST3D, 0, req.blob_id,
|
||||
VHSA_BO_SCRATCH_MAP, NULL, &out);
|
||||
if (r) return r;
|
||||
|
||||
// TODO: insert scratch bo into rbtree, or insert it in dev nodes.
|
||||
|
||||
out->cpu_addr = MemoryAddress;
|
||||
out->host_addr = (void*)rsp->memory_handle;
|
||||
*AlternateVAGPU = rsp->alternate_vagpu;
|
||||
|
||||
vhsa_debug(
|
||||
"%s: create scratch memory, gva: %p, memory_handle: 0x%p, alternate_vagpu: %p, size: %lx\n",
|
||||
__FUNCTION__, MemoryAddress, (void*)rsp->memory_handle, (void*)rsp->alternate_vagpu,
|
||||
MemorySizeInBytes);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtMapMemoryToGPU(void* MemoryAddress, HSAuint64 MemorySizeInBytes,
|
||||
HSAuint64* AlternateVAGPU) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
vhsakmt_bo_handle bo = vhsakmt_find_bo_by_addr(dev, MemoryAddress);
|
||||
if (!bo && vhsakmt_is_scratch_mem(dev, MemoryAddress))
|
||||
return vhsakmt_create_scratch_map_memory(dev, MemoryAddress, MemorySizeInBytes, AlternateVAGPU);
|
||||
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_MAP_MEM_TO_GPU,
|
||||
.map_to_GPU_args =
|
||||
{
|
||||
.MemoryAddress = bo ? (uint64_t)bo->host_addr : (uint64_t)MemoryAddress,
|
||||
.MemorySizeInBytes = MemorySizeInBytes,
|
||||
},
|
||||
};
|
||||
|
||||
if (bo && (bo->bo_type & VHSA_BO_USERPTR)) vhsakmt_remove_userptr_bo(dev, bo);
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
vhsa_debug("%s: gva: %p, hva: 0x%lx, size: %lx\n", __FUNCTION__, MemoryAddress, req.MemoryAddress,
|
||||
MemorySizeInBytes);
|
||||
|
||||
*AlternateVAGPU = rsp->alternate_vagpu;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static int vhsakmt_map_userptr(vhsakmt_device_handle dev, void* addr, size_t size, uint32_t res_id,
|
||||
uint64_t* userptr_handle) {
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_MAP_USERPTR,
|
||||
.res_id = res_id,
|
||||
};
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp =
|
||||
vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
rsp->map_userptr_rsp.userptr_handle = 0;
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
*userptr_handle = rsp->map_userptr_rsp.userptr_handle;
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static void* vhsakmt_map_to_gpu(void* addr, size_t size) {
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
size_t offset = (uint64_t)addr % getpagesize();
|
||||
size_t map_size = (VHSA_ALIGN_UP(size + offset, getpagesize()) / getpagesize()) * getpagesize();
|
||||
uint64_t userptr_offset, userptr_handle = 0;
|
||||
vhsakmt_bo_handle userptr;
|
||||
int r;
|
||||
|
||||
vhsa_debug("%s: addr: %p, size: 0x%lx, size + offset: 0x%lx, map_size: 0x%lx\n", __FUNCTION__,
|
||||
addr, size, size + offset, map_size);
|
||||
|
||||
r = vhsakmt_init_userptr_blob(dev, addr, size, &userptr, &userptr_offset);
|
||||
if (r < 0) {
|
||||
vhsa_debug("%s: userptr create failed at address: %p, ret = %d\n", __FUNCTION__, addr, r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vhsakmt_map_userptr(dev, addr, size, userptr->real.res_id, &userptr_handle);
|
||||
if (!userptr_handle) {
|
||||
vhsa_debug("%s: map userptr failed at address: %p, ret = %d\n", __FUNCTION__, addr, r);
|
||||
vhsakmt_destroy_handle(dev, userptr);
|
||||
vhsakmt_remove_userptr_bo(dev, userptr);
|
||||
return NULL;
|
||||
}
|
||||
userptr->host_addr = VHSA_UINT64_TO_VPTR(VHSA_VPTR_TO_UINT64(userptr_handle) + offset);
|
||||
|
||||
if (r > 0) {
|
||||
vhsa_debug("%s: userptr: %p already registered, offset: %lx\n", __FUNCTION__, addr,
|
||||
userptr_offset);
|
||||
userptr->host_addr =
|
||||
VHSA_UINT64_TO_VPTR(VHSA_VPTR_TO_UINT64(userptr->host_addr) + userptr_offset);
|
||||
}
|
||||
vhsakmt_insert_bo(dev, userptr, userptr->cpu_addr, userptr->size);
|
||||
|
||||
vhsa_debug("%s: real gva: %p, gva: %p, hva: %p, size: %lx, offset: %" PRIu64
|
||||
", map_size: 0x%lx\n",
|
||||
__FUNCTION__, addr, userptr->cpu_addr, userptr->host_addr, size, offset, map_size);
|
||||
return userptr->host_addr;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRegisterMemoryWithFlags(void* MemoryAddress,
|
||||
HSAuint64 MemorySizeInBytes,
|
||||
HsaMemFlags MemFlags) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
void* addr;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_REG_MEM_WITH_FLAG,
|
||||
.reg_mem_with_flag =
|
||||
{
|
||||
.MemorySizeInBytes = MemorySizeInBytes,
|
||||
.MemFlags = MemFlags,
|
||||
},
|
||||
};
|
||||
|
||||
/* no need to register memory from lihsakmt / not a userptr */
|
||||
if (!vhsakmt_is_userptr(dev, MemoryAddress)) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
addr = vhsakmt_map_to_gpu(MemoryAddress, MemorySizeInBytes);
|
||||
if (!addr) {
|
||||
vhsa_debug("%s: register memory failed, gva: %p, size: %lx\n", __FUNCTION__, MemoryAddress,
|
||||
MemorySizeInBytes);
|
||||
return HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
req.reg_mem_with_flag.MemoryAddress = (uint64_t)addr;
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static int vhsakmt_remove_clgl_bo(vhsakmt_device_handle dev, vhsakmt_bo_handle bo) {
|
||||
struct vhsakmt_ccmd_memory_rsp* rsp;
|
||||
struct vhsakmt_ccmd_memory_req req = {
|
||||
.hdr = VHSAKMT_CCMD(MEMORY, sizeof(struct vhsakmt_ccmd_memory_req)),
|
||||
.type = VHSAKMT_CCMD_MEMORY_DEREG_MEM,
|
||||
.res_id = bo->real.res_id,
|
||||
.MemoryAddress = (uint64_t)bo->cpu_addr,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_memory_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (rsp->ret) vhsa_err("%s: deregister failed clgl memory gva: %p\n", __FUNCTION__, bo->cpu_addr);
|
||||
|
||||
vhsakmt_bo_free(dev, bo);
|
||||
|
||||
vhsa_debug("%s: deregister clgl memory gva: %p, ret: %d\n", __FUNCTION__, bo->cpu_addr, rsp->ret);
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDeregisterMemory(void* MemoryAddress) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
vhsakmt_bo_handle bo = vhsakmt_find_bo_by_addr(dev, MemoryAddress);
|
||||
if (!bo) return HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
vhsa_debug("%s: remove userptr %p size: 0x%lx, res id: %d\n", __FUNCTION__, MemoryAddress,
|
||||
(size_t)bo->size, bo->real.res_id);
|
||||
|
||||
if (bo->bo_type & VHSA_BO_CLGL)
|
||||
return vhsakmt_remove_clgl_bo(dev, bo);
|
||||
else {
|
||||
vhsakmt_remove_bo(dev, bo);
|
||||
free(bo);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtQueryPointerInfo(const void* Pointer, HsaPointerInfo* PointerInfo) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
void* gpu_va = vhsakmt_gpu_va(dev, VHSA_UINT64_TO_VPTR(Pointer));
|
||||
if (!gpu_va) return -HSAKMT_STATUS_ERROR;
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_POINTER_INFO,
|
||||
.pointer = VHSA_VPTR_TO_UINT64(gpu_va),
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr,
|
||||
sizeof(struct vhsakmt_ccmd_query_info_rsp) +
|
||||
QUERY_PTR_INFO_MAX_MAPPED_NODES * sizeof(uint32_t));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(PointerInfo, &rsp->ptr_info, sizeof(HsaPointerInfo));
|
||||
|
||||
if (PointerInfo->NMappedNodes && PointerInfo->MappedNodes) {
|
||||
if (PointerInfo->NMappedNodes > QUERY_PTR_INFO_MAX_MAPPED_NODES) {
|
||||
PointerInfo->NMappedNodes = QUERY_PTR_INFO_MAX_MAPPED_NODES;
|
||||
vhsa_debug(
|
||||
"%s: query pointer: %p info mapped nodes greater than QUERY_PTR_INFO_MAX_MAPPED_NODES\n",
|
||||
__FUNCTION__, Pointer);
|
||||
}
|
||||
|
||||
PointerInfo->MappedNodes = calloc(PointerInfo->NMappedNodes, sizeof(uint32_t));
|
||||
if (!PointerInfo->MappedNodes) {
|
||||
PointerInfo->NMappedNodes = 0;
|
||||
return -HSAKMT_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy(VHSA_UINT64_TO_VPTR(PointerInfo->MappedNodes), rsp->payload,
|
||||
PointerInfo->NMappedNodes * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetTileConfig(HSAuint32 NodeId, HsaGpuTileConfig* config) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
uint8_t* config_cpy_addr = NULL;
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
unsigned req_len = sizeof(struct vhsakmt_ccmd_query_info_req);
|
||||
unsigned rsp_len = sizeof(struct vhsakmt_ccmd_query_info_rsp) +
|
||||
config->NumTileConfigs * sizeof(HSAuint32) + config->NumMacroTileConfigs * sizeof(HSAuint32);
|
||||
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, req_len),
|
||||
.type = VHSAKMT_CCMD_QUERY_TILE_CONFIG,
|
||||
.tile_config_args.NodeId = NodeId,
|
||||
.tile_config_args.config = *config,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, rsp_len);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(config, &rsp->tile_config_rsp, sizeof(HsaGpuTileConfig));
|
||||
config_cpy_addr = ((uint8_t*)rsp->payload);
|
||||
memcpy(config->TileConfig, config_cpy_addr, config->NumTileConfigs * sizeof(HSAuint32));
|
||||
config_cpy_addr += config->NumTileConfigs * sizeof(HSAuint32);
|
||||
memcpy(config->MacroTileConfig, config_cpy_addr, config->NumMacroTileConfigs * sizeof(HSAuint32));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_clgl_bo(vhsakmt_device_handle dev, void* addr, size_t size,
|
||||
uint32_t res_id, uint32_t bo_handle, void* meta_data) {
|
||||
vhsakmt_bo_handle out = calloc(1, sizeof(struct vhsakmt_bo));
|
||||
if (!out) return -ENOMEM;
|
||||
|
||||
out->dev = dev;
|
||||
out->size = size;
|
||||
atomic_store(&out->real.map_count, 0);
|
||||
atomic_store(&out->refcount, 1);
|
||||
|
||||
#ifdef CLGL_EXPORT_RESID
|
||||
out->real.res_id = GraphicsResourceHandle;
|
||||
#else
|
||||
out->real.res_id = res_id;
|
||||
#endif
|
||||
|
||||
/* GL bo handle from GL context*/
|
||||
out->real.handle = bo_handle;
|
||||
out->bo_type |= VHSA_BO_CLGL;
|
||||
if (meta_data) out->gl_meta_data = meta_data;
|
||||
|
||||
out->host_addr = addr;
|
||||
|
||||
vhsakmt_insert_bo(dev, out, addr, out->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhsakmt_gfxhandle_to_resid(vhsakmt_device_handle dev, uint32_t gfx_handle,
|
||||
uint32_t* res_id, uint32_t* bo_handle) {
|
||||
int r = drmPrimeFDToHandle(dev->vgdev->fd, gfx_handle, bo_handle);
|
||||
if (r) {
|
||||
vhsa_err("%s: drmPrimeFDToHandle failed for handle: %u\n", __FUNCTION__, gfx_handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
virtio_gpu_res_id(dev->vgdev, *bo_handle, res_id);
|
||||
|
||||
vhsa_debug("%s: register praphics handle: handle: %d, bo_handle: %d, res_id: %d\n", __FUNCTION__,
|
||||
gfx_handle, *bo_handle, *res_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRegisterGraphicsHandleToNodes(
|
||||
HSAuint64 GraphicsResourceHandle, HsaGraphicsResourceInfo* GraphicsResourceInfo,
|
||||
HSAuint64 NumberOfNodes, HSAuint32* NodeArray) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
uint32_t bo_handle, res_id;
|
||||
uint64_t meta_data_size = VHSA_GL_METADATA_MAX_SIZE;
|
||||
unsigned req_len = sizeof(struct vhsakmt_ccmd_gl_inter_req) + NumberOfNodes * sizeof(NodeArray);
|
||||
struct vhsakmt_ccmd_gl_inter_req* req;
|
||||
struct vhsakmt_ccmd_gl_inter_rsp* rsp;
|
||||
int r;
|
||||
|
||||
req = calloc(1, req_len);
|
||||
if (!req) return -ENOMEM;
|
||||
|
||||
req->hdr = VHSAKMT_CCMD(GL_INTER, req_len);
|
||||
req->type = VHSAKMT_CCMD_GL_REG_GHD_TO_NODES;
|
||||
req->reg_ghd_to_nodes.NumberOfNodes = NumberOfNodes;
|
||||
req->reg_ghd_to_nodes.res_handle = GraphicsResourceHandle;
|
||||
|
||||
#ifdef CLGL_EXPORT_RESID
|
||||
req->reg_ghd_to_nodes.GraphicsResourceHandle = GraphicsResourceHandle;
|
||||
#else
|
||||
r = vhsakmt_gfxhandle_to_resid(dev, GraphicsResourceHandle, &res_id, &bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
req->reg_ghd_to_nodes.GraphicsResourceHandle = bo_handle;
|
||||
req->reg_ghd_to_nodes.res_handle = res_id;
|
||||
#endif
|
||||
|
||||
memcpy(req->payload, NodeArray, NumberOfNodes * sizeof(NodeArray));
|
||||
|
||||
rsp =
|
||||
vhsakmt_alloc_rsp(dev, &req->hdr, sizeof(struct vhsakmt_ccmd_gl_inter_rsp) + meta_data_size);
|
||||
if (!rsp) {
|
||||
r = -ENOMEM;
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req->hdr, __FUNCTION__);
|
||||
if (rsp->ret) return rsp->ret;
|
||||
|
||||
memcpy(GraphicsResourceInfo, &rsp->info, sizeof(HsaGraphicsResourceInfo));
|
||||
if (rsp->info.MetadataSizeInBytes) {
|
||||
GraphicsResourceInfo->Metadata = calloc(1, GraphicsResourceInfo->MetadataSizeInBytes);
|
||||
if (!GraphicsResourceInfo->Metadata) {
|
||||
r = -ENOMEM;
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
memcpy(VHSA_UINT64_TO_VPTR(GraphicsResourceInfo->Metadata), rsp->payload,
|
||||
GraphicsResourceInfo->MetadataSizeInBytes);
|
||||
} else
|
||||
GraphicsResourceInfo->Metadata = NULL;
|
||||
|
||||
vhsa_debug("%s: register graphics handle: handle: %ld hva: %p, size: %lx\n", __FUNCTION__,
|
||||
GraphicsResourceHandle, GraphicsResourceInfo->MemoryAddress,
|
||||
GraphicsResourceInfo->SizeInBytes);
|
||||
|
||||
r = vhsakmt_create_clgl_bo(dev, GraphicsResourceInfo->MemoryAddress,
|
||||
GraphicsResourceInfo->SizeInBytes, res_id, bo_handle,
|
||||
VHSA_UINT64_TO_VPTR(GraphicsResourceInfo->Metadata));
|
||||
if (r) goto free_out;
|
||||
|
||||
r = rsp->ret;
|
||||
|
||||
free_out:
|
||||
/* close exported FD after register or close it when deregistre. Close after register here. */
|
||||
close(GraphicsResourceHandle);
|
||||
free(req);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
pthread_mutex_t dev_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
vhsakmt_device_handle dev_list = NULL;
|
||||
|
||||
vhsakmt_device_handle vhsakmt_dev(void) { return dev_list; }
|
||||
|
||||
static HSAKMT_STATUS vhsakmt_openKFD_cmd(vhsakmt_device_handle dev) {
|
||||
void* vm_start = vhsakmt_vm_start();
|
||||
if (!vm_start) return -HSAKMT_STATUS_NO_MEMORY;
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_OPEN_KFD,
|
||||
.open_kfd_args =
|
||||
{
|
||||
.cur_vm_start = VHSA_VPTR_TO_UINT64(vm_start),
|
||||
},
|
||||
};
|
||||
|
||||
if (!req.open_kfd_args.cur_vm_start) {
|
||||
vhsa_err("%s: failed to get current heap start address\n", __FUNCTION__);
|
||||
return -HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -HSAKMT_STATUS_NO_MEMORY;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp->open_kfd_rsp.vm_start || !rsp->open_kfd_rsp.vm_size) {
|
||||
vhsa_err("%s: failed to get KFD VM area\n", __FUNCTION__);
|
||||
return -HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
vhsakmt_set_vm_area(dev, rsp->open_kfd_rsp.vm_start, rsp->open_kfd_rsp.vm_size);
|
||||
if (vhsakmt_reserve_va(dev->vm_start, dev->vm_size)) {
|
||||
vhsa_err("%s: failed to reserve VM area: [%lx-%lx]-0x%lx\n", __FUNCTION__, dev->vm_start,
|
||||
dev->vm_start + dev->vm_size, dev->vm_size);
|
||||
return -HSAKMT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
vhsa_debug("%s: kfd vm range: [%lx-%lx]-0x%lx\n", __FUNCTION__, dev->vm_start,
|
||||
dev->vm_start + dev->vm_size, dev->vm_size);
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static vhsakmt_device_handle vhsakmt_device_init(void) {
|
||||
int fd;
|
||||
vhsakmt_device_handle dev = NULL;
|
||||
|
||||
if (vhsakmt_dev()) return vhsakmt_dev();
|
||||
|
||||
pthread_mutex_lock(&dev_mutex);
|
||||
|
||||
fd = virtio_gpu_kfd_open();
|
||||
if (fd < 0) goto open_failed;
|
||||
|
||||
dev = calloc(1, sizeof(struct vhsakmt_device));
|
||||
if (!dev) goto open_failed;
|
||||
|
||||
dev->vgdev = virtio_gpu_init(fd, 0);
|
||||
if (!dev->vgdev) goto malloc_failed;
|
||||
|
||||
rbtree_init(&dev->bo_rbt);
|
||||
atomic_store(&dev->next_blob_id, 1);
|
||||
atomic_store(&dev->refcount, 1);
|
||||
pthread_mutex_init(&dev->bo_handles_mutex, NULL);
|
||||
pthread_mutex_init(&dev->vhsakmt_mutex, NULL);
|
||||
dev_list = dev;
|
||||
|
||||
pthread_mutex_unlock(&dev_mutex);
|
||||
return dev;
|
||||
|
||||
malloc_failed:
|
||||
free(dev);
|
||||
dev = NULL;
|
||||
open_failed:
|
||||
pthread_mutex_unlock(&dev_mutex);
|
||||
return dev;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtOpenKFD(void) {
|
||||
vhsakmt_device_handle dev;
|
||||
char* d = getenv("VHSAKMT_DEBUG_LEVEL");
|
||||
if (d) vhsakmt_debug_level = atoi(d);
|
||||
|
||||
dev = vhsakmt_device_init();
|
||||
if (!dev) return HSAKMT_STATUS_ERROR;
|
||||
|
||||
return vhsakmt_openKFD_cmd(vhsakmt_dev());
|
||||
}
|
||||
|
||||
static void vhsakmt_device_destroy(struct vhsakmt_device* dev) {
|
||||
pthread_mutex_destroy(&dev->bo_handles_mutex);
|
||||
vhsakmt_dereserve_va(dev->vm_start, dev->vm_size);
|
||||
|
||||
if (dev->sys_props) free(dev->sys_props);
|
||||
if (dev->vhsakmt_nodes) free(dev->vhsakmt_nodes);
|
||||
|
||||
virtio_gpu_close(dev->vgdev);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCloseKFD(void) {
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
pthread_mutex_lock(&dev_mutex);
|
||||
if (vhsakmt_atomic_dec_return(&dev->refcount) <= 0) vhsakmt_device_destroy(dev);
|
||||
pthread_mutex_unlock(&dev_mutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef VHSAKMT_VIRTIO_PROTO_H
|
||||
#define VHSAKMT_VIRTIO_PROTO_H
|
||||
|
||||
#include "hsakmt/linux/kfd_ioctl.h"
|
||||
#include "hsakmt/hsakmt.h"
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <libdrm/amdgpu.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "virtio_gpu.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic error "-Wpadded"
|
||||
#endif
|
||||
|
||||
/* defined in other header file in virglrenderer */
|
||||
#define VHSAKMT_DEFINE_CAST(parent, child) \
|
||||
static inline struct child* to_##child(struct parent* x) { return (struct child*)x; }
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define VHSAKMT_STATIC_ASSERT_SIZE(t) \
|
||||
static_assert(sizeof(struct t) % 8 == 0, "sizeof(struct " #t ") not multiple of 8"); \
|
||||
static_assert(_Alignof(struct t) <= 8, "alignof(struct " #t ") too large");
|
||||
#else
|
||||
#define VHSAKMT_STATIC_ASSERT_SIZE(t)
|
||||
#endif
|
||||
|
||||
enum vhsakmt_ccmd {
|
||||
VHSAKMT_CCMD_NOP = 1, /* No payload, can be used to sync with host */
|
||||
VHSAKMT_CCMD_QUERY_INFO,
|
||||
VHSAKMT_CCMD_EVENT,
|
||||
VHSAKMT_CCMD_MEMORY,
|
||||
VHSAKMT_CCMD_QUEUE,
|
||||
VHSAKMT_CCMD_GL_INTER,
|
||||
};
|
||||
|
||||
typedef struct _vHsaEvent {
|
||||
HsaEvent event;
|
||||
uint64_t event_handle;
|
||||
uint64_t bo_handle;
|
||||
uint32_t res_id;
|
||||
uint32_t pad;
|
||||
} vHsaEvent;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_vHsaEvent)
|
||||
|
||||
struct vhsakmt_event_shmem {
|
||||
uint32_t trigered_events_num;
|
||||
uint32_t pad;
|
||||
HsaEvent trigered_events[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_event_shmem)
|
||||
|
||||
#define VHSAKMT_CCMD(_cmd, _len) \
|
||||
((struct vhsakmt_ccmd_req){ \
|
||||
.cmd = VHSAKMT_CCMD_##_cmd, \
|
||||
.len = (_len), \
|
||||
})
|
||||
|
||||
struct vhsakmt_ccmd_nop_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
};
|
||||
|
||||
/*
|
||||
* VHSAKMT_CCMD_QUERY
|
||||
*/
|
||||
enum vhsakmt_ccmd_query_type {
|
||||
VHSAKMT_CCMD_QUERY_GPU_INFO = 0,
|
||||
VHSAKMT_CCMD_QUERY_OPEN_KFD,
|
||||
VHSAKMT_CCMD_QUERY_GET_VER,
|
||||
VHSAKMT_CCMD_QUERY_REL_SYS_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_SYS_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_NODE_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_XNACK_MODE,
|
||||
VHSAKMT_CCMD_QUERY_RUN_TIME_ENABLE,
|
||||
VHSAKMT_CCMD_QUERY_RUN_TIME_DISABLE,
|
||||
VHSAKMT_CCMD_QUERY_GET_NOD_MEM_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_NOD_CACHE_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_NOD_IO_LINK_PROP,
|
||||
VHSAKMT_CCMD_QUERY_GET_CLOCK_COUNTERS,
|
||||
VHSAKMT_CCMD_QUERY_POINTER_INFO,
|
||||
VHSAKMT_CCMD_QUERY_TILE_CONFIG,
|
||||
VHSAKMT_CCMD_QUERY_NANO_TIME,
|
||||
VHSAKMT_CCMD_QUERY_GET_RUNTIME_CAPS,
|
||||
};
|
||||
|
||||
#define QUERY_PTR_INFO_MAX_MAPPED_NODES 3
|
||||
|
||||
typedef struct _query_req_run_time_enable_args {
|
||||
/* void* rDebug, bypassed by payload */
|
||||
uint8_t pad[3];
|
||||
uint8_t setupTtmp;
|
||||
uint32_t __pad;
|
||||
} query_req_run_time_enable_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_req_run_time_enable_args)
|
||||
|
||||
typedef struct _query_req_node_mem_prop_args {
|
||||
uint32_t NodeId;
|
||||
uint32_t NumBanks;
|
||||
} query_req_node_mem_prop_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_req_node_mem_prop_args)
|
||||
|
||||
typedef struct _query_req_node_cache_prop_args {
|
||||
uint32_t NodeId;
|
||||
uint32_t ProcessorId;
|
||||
uint32_t NumCaches;
|
||||
uint32_t pad;
|
||||
} query_req_node_cache_prop_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_req_node_cache_prop_args)
|
||||
|
||||
typedef struct _query_req_node_io_link_args {
|
||||
uint32_t NodeId;
|
||||
uint32_t NumIoLinks;
|
||||
} query_req_node_io_link_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_req_node_io_link_args)
|
||||
|
||||
typedef struct _query_tile_config {
|
||||
HsaGpuTileConfig config;
|
||||
uint32_t NodeId;
|
||||
uint32_t pad;
|
||||
} query_tile_config;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_tile_config)
|
||||
|
||||
typedef struct _query_open_kfd_args {
|
||||
uint64_t cur_vm_start;
|
||||
} query_open_kfd_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_open_kfd_args)
|
||||
|
||||
typedef struct _query_open_kfd_rsp {
|
||||
uint64_t vm_start;
|
||||
uint64_t vm_size;
|
||||
} query_open_kfd_rsp;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_open_kfd_rsp)
|
||||
|
||||
typedef struct _query_nano_time_rsp {
|
||||
uint64_t nano_time;
|
||||
} query_nano_time_rsp;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_query_nano_time_rsp)
|
||||
|
||||
struct vhsakmt_ccmd_query_info_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
struct drm_amdgpu_info info;
|
||||
uint32_t type;
|
||||
uint32_t pad;
|
||||
union {
|
||||
uint64_t pointer;
|
||||
uint32_t NodeID; /* some query API just need node ID */
|
||||
query_req_run_time_enable_args run_time_enable_args;
|
||||
query_req_node_mem_prop_args node_mem_prop_args;
|
||||
query_req_node_cache_prop_args node_cache_prop_args;
|
||||
query_req_node_io_link_args node_io_link_args;
|
||||
query_tile_config tile_config_args;
|
||||
query_open_kfd_args open_kfd_args;
|
||||
};
|
||||
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_DEFINE_CAST(vhsakmt_ccmd_req, vhsakmt_ccmd_query_info_req)
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_query_info_req)
|
||||
#define VHSAKMT_CCMD_QUERY_MAX_TILE_CONFIG 128
|
||||
#define VHSAKMT_CCMD_QUERY_MAX_GET_NOD_MEM_PROP 128
|
||||
#define VHSAKMT_CCMD_QUERY_MAX_GET_NOD_CACHE_PROP 128
|
||||
#define VHSAKMT_CCMD_QUERY_MAX_GET_NOD_IO_LINK_PROP 128
|
||||
|
||||
struct vhsakmt_ccmd_query_info_rsp {
|
||||
struct vhsakmt_ccmd_rsp hdr;
|
||||
int32_t ret;
|
||||
union {
|
||||
query_open_kfd_rsp open_kfd_rsp;
|
||||
query_nano_time_rsp nano_time_rsp;
|
||||
HsaGpuTileConfig tile_config_rsp;
|
||||
HsaPointerInfo ptr_info;
|
||||
struct amdgpu_gpu_info gpu_info;
|
||||
HsaVersionInfo kfd_version;
|
||||
HsaSystemProperties sys_props;
|
||||
HsaNodeProperties node_props;
|
||||
int32_t xnack_mode;
|
||||
HsaClockCounters clock_counters;
|
||||
uint32_t caps;
|
||||
uint64_t pad[9];
|
||||
};
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_query_info_rsp)
|
||||
|
||||
/*
|
||||
* VHSAKMT_CCMD_EVENT
|
||||
*/
|
||||
enum vhsakmt_ccmd_event_type {
|
||||
VHSAKMT_CCMD_EVENT_CREATE,
|
||||
VHSAKMT_CCMD_EVENT_DESTROY,
|
||||
VHSAKMT_CCMD_EVENT_SET,
|
||||
VHSAKMT_CCMD_EVENT_RESET,
|
||||
VHSAKMT_CCMD_EVENT_QUERY_STATE,
|
||||
VHSAKMT_CCMD_EVENT_WAIT_ON_MULTI_EVENTS,
|
||||
|
||||
VHSAKMT_CCMD_EVENT_SET_TRAP,
|
||||
|
||||
};
|
||||
typedef struct _event_req_create_args {
|
||||
HsaEventDescriptor EventDesc;
|
||||
uint8_t ManualReset;
|
||||
uint8_t IsSignaled;
|
||||
uint8_t pad[6];
|
||||
} event_req_create_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_req_create_args)
|
||||
|
||||
typedef struct _event_req_wait_args {
|
||||
HsaEvent Event;
|
||||
uint32_t Milliseconds;
|
||||
uint32_t pad;
|
||||
} event_req_wait_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_req_wait_args)
|
||||
|
||||
typedef struct _event_req_wait_ext_args {
|
||||
HsaEvent Event;
|
||||
uint64_t event_age;
|
||||
uint32_t Milliseconds;
|
||||
uint32_t pad;
|
||||
} event_req_wait_ext_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_req_wait_ext_args)
|
||||
|
||||
typedef struct _event_req_wait_on_multi_args {
|
||||
/*HsaEvent* Events[], in playloud*/
|
||||
uint32_t NumEvents;
|
||||
uint32_t Milliseconds;
|
||||
uint8_t WaitOnAll;
|
||||
uint8_t pad[7];
|
||||
} event_req_wait_on_multi_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_req_wait_on_multi_args)
|
||||
|
||||
typedef struct _event_req_wait_on_multi_ext_args {
|
||||
/*HsaEvent* Events[], in playloud*/
|
||||
uint32_t NumEvents;
|
||||
uint32_t Milliseconds;
|
||||
uint64_t event_age;
|
||||
uint8_t WaitOnAll;
|
||||
uint8_t pad[7];
|
||||
} event_req_wait_on_multi_ext_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_req_wait_on_multi_ext_args)
|
||||
|
||||
typedef struct _event_set_trap_handler_args {
|
||||
uint64_t TrapHandlerBaseAddress;
|
||||
uint64_t TrapHandlerSizeInBytes;
|
||||
uint64_t TrapBufferBaseAddress;
|
||||
uint64_t TrapBufferSizeInBytes;
|
||||
uint32_t NodeId;
|
||||
uint32_t pad;
|
||||
} event_set_trap_handler_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_event_set_trap_handler_args)
|
||||
|
||||
struct vhsakmt_ccmd_event_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
union {
|
||||
HsaEvent Event; /* For set, reset, query. */
|
||||
HsaEvent* event_hanele;
|
||||
event_req_wait_args wait_args;
|
||||
event_req_create_args create_args;
|
||||
event_req_wait_ext_args wait_ext_args;
|
||||
event_req_wait_on_multi_args wait_on_multi_args;
|
||||
event_req_wait_on_multi_ext_args wait_on_multi_ext_args;
|
||||
event_set_trap_handler_args set_trap_handler_args;
|
||||
};
|
||||
uint32_t type;
|
||||
uint32_t sync_shmem_res_id;
|
||||
uint64_t blob_id;
|
||||
uint32_t res_id;
|
||||
uint32_t pad;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_event_req)
|
||||
VHSAKMT_DEFINE_CAST(vhsakmt_ccmd_req, vhsakmt_ccmd_event_req)
|
||||
|
||||
struct vhsakmt_ccmd_event_rsp {
|
||||
struct vhsakmt_ccmd_rsp hdr;
|
||||
int32_t ret;
|
||||
vHsaEvent vevent;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_event_rsp)
|
||||
|
||||
/*
|
||||
* VHSAKMT_CCMD_MEMORY
|
||||
*/
|
||||
enum vhsakmt_ccmd_memory_type {
|
||||
VHSAKMT_CCMD_MEMORY_ALLOC,
|
||||
VHSAKMT_CCMD_MEMORY_MAP_TO_GPU_NODES,
|
||||
VHSAKMT_CCMD_MEMORY_FREE,
|
||||
VHSAKMT_CCMD_MEMORY_UNMAP_TO_GPU,
|
||||
VHSAKMT_CCMD_MEMORY_AVAIL_MEM,
|
||||
VHSAKMT_CCMD_MEMORY_MAP_MEM_TO_GPU,
|
||||
VHSAKMT_CCMD_MEMORY_REG_MEM_WITH_FLAG,
|
||||
VHSAKMT_CCMD_MEMORY_DEREG_MEM,
|
||||
VHSAKMT_CCMD_MEMORY_MAP_USERPTR,
|
||||
};
|
||||
|
||||
typedef struct _memory_req_alloc_args {
|
||||
uint32_t PreferredNode;
|
||||
HsaMemFlags MemFlags;
|
||||
uint64_t SizeInBytes;
|
||||
uint64_t MemoryAddress;
|
||||
} memory_req_alloc_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_memory_req_alloc_args)
|
||||
|
||||
typedef struct _memory_req_free_args {
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t SizeInBytes;
|
||||
} memory_req_free_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_memory_req_free_args)
|
||||
|
||||
typedef struct _memory_req_map_to_GPU_nodes_args {
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t MemorySizeInBytes;
|
||||
uint64_t AlternateVAGPU;
|
||||
HsaMemMapFlags MemMapFlags;
|
||||
uint32_t pad;
|
||||
uint64_t NumberOfNodes;
|
||||
uint32_t* NodeArray;
|
||||
} memory_req_map_to_GPU_nodes_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_memory_req_map_to_GPU_nodes_args)
|
||||
|
||||
typedef struct _memory_map_mem_to_gpu_args {
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t MemorySizeInBytes;
|
||||
uint8_t need_create_bo;
|
||||
uint8_t pad[7];
|
||||
} memory_map_mem_to_gpu_args;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_memory_map_mem_to_gpu_args)
|
||||
|
||||
typedef struct _memory_reg_mem_with_flag {
|
||||
uint64_t MemoryAddress;
|
||||
uint64_t MemorySizeInBytes;
|
||||
HsaMemFlags MemFlags;
|
||||
uint32_t pad;
|
||||
} memory_reg_mem_with_flag;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_memory_reg_mem_with_flag)
|
||||
|
||||
struct vhsakmt_ccmd_memory_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
union {
|
||||
uint64_t MemoryAddress;
|
||||
uint32_t Node;
|
||||
memory_req_alloc_args alloc_args;
|
||||
memory_req_map_to_GPU_nodes_args map_to_GPU_nodes_args;
|
||||
memory_req_free_args free_args;
|
||||
memory_map_mem_to_gpu_args map_to_GPU_args;
|
||||
memory_reg_mem_with_flag reg_mem_with_flag;
|
||||
};
|
||||
uint64_t blob_id;
|
||||
uint32_t type;
|
||||
uint32_t res_id;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_memory_req)
|
||||
VHSAKMT_DEFINE_CAST(vhsakmt_ccmd_req, vhsakmt_ccmd_memory_req)
|
||||
|
||||
typedef struct _vhsakmt_ccmd_memory_map_userptr_rsp {
|
||||
uint64_t userptr_handle;
|
||||
uint32_t npfns;
|
||||
uint32_t pad;
|
||||
} vhsakmt_ccmd_memory_map_userptr_rsp;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_vhsakmt_ccmd_memory_map_userptr_rsp)
|
||||
|
||||
struct vhsakmt_ccmd_memory_rsp {
|
||||
struct vhsakmt_ccmd_rsp hdr;
|
||||
int32_t ret;
|
||||
union {
|
||||
vhsakmt_ccmd_memory_map_userptr_rsp map_userptr_rsp;
|
||||
uint64_t memory_handle;
|
||||
uint64_t alternate_vagpu;
|
||||
uint64_t available_bytes;
|
||||
};
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_memory_rsp)
|
||||
|
||||
/*
|
||||
* VHSAKMT_CCMD_QUEUE
|
||||
*/
|
||||
enum vhsakmt_ccmd_queue_type {
|
||||
VHSAKMT_CCMD_QUEUE_CREATE,
|
||||
VHSAKMT_CCMD_QUEUE_DESTROY,
|
||||
};
|
||||
|
||||
typedef struct _vHsaQueueResource {
|
||||
HsaQueueResource r;
|
||||
uint64_t host_doorbell;
|
||||
uint64_t host_doorbell_offset;
|
||||
uint64_t host_write_offset;
|
||||
uint64_t host_read_offset;
|
||||
uint64_t host_rw_handle;
|
||||
uint64_t queue_handle;
|
||||
} vHsaQueueResource;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_vHsaQueueResource)
|
||||
|
||||
typedef struct _queue_req_create {
|
||||
uint32_t NodeId;
|
||||
HSA_QUEUE_TYPE Type;
|
||||
uint32_t QueuePercentage;
|
||||
uint32_t pad;
|
||||
HSA_QUEUE_PRIORITY Priority;
|
||||
uint32_t pad1;
|
||||
uint32_t SdmaEngineId;
|
||||
uint64_t QueueAddress;
|
||||
uint64_t QueueSizeInBytes;
|
||||
HsaEvent* Event;
|
||||
HsaQueueResource* QueueResource;
|
||||
uint64_t* Queue_write_ptr_aql;
|
||||
uint64_t* Queue_read_ptr_aql;
|
||||
} queue_req_create;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_queue_req_create)
|
||||
|
||||
struct vhsakmt_ccmd_queue_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
union {
|
||||
HSA_QUEUEID QueueId;
|
||||
queue_req_create create_queue_args;
|
||||
};
|
||||
uint64_t blob_id; /* For queue create, queue resource */
|
||||
uint64_t rw_ptr_blob_id; /* For queue create, r/w ptr memory mapping */
|
||||
uint64_t doorbell_blob_id; /* For queue create, doorbell ptr memory mapping */
|
||||
uint32_t res_id;
|
||||
uint32_t type;
|
||||
uint32_t queue_mem_res_id;
|
||||
uint32_t pad;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_queue_req)
|
||||
VHSAKMT_DEFINE_CAST(vhsakmt_ccmd_req, vhsakmt_ccmd_queue_req)
|
||||
|
||||
struct vhsakmt_ccmd_queue_rsp {
|
||||
struct vhsakmt_ccmd_rsp hdr;
|
||||
int32_t ret;
|
||||
vHsaQueueResource vqueue_res;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_queue_rsp)
|
||||
|
||||
/*
|
||||
* VHSAKMT_CCMD_GL_INTER
|
||||
*/
|
||||
enum vhsakmt_ccmd_gl_inter_type {
|
||||
VHSAKMT_CCMD_GL_REG_GHD_TO_NODES,
|
||||
};
|
||||
|
||||
typedef struct _gl_inter_req_reg_ghd_to_nodes {
|
||||
uint64_t GraphicsResourceHandle;
|
||||
uint64_t NumberOfNodes; // NodeArray in payload
|
||||
uint32_t res_handle;
|
||||
uint32_t pad;
|
||||
} gl_inter_req_reg_ghd_to_nodes;
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(_gl_inter_req_reg_ghd_to_nodes)
|
||||
|
||||
struct vhsakmt_ccmd_gl_inter_req {
|
||||
struct vhsakmt_ccmd_req hdr;
|
||||
union {
|
||||
gl_inter_req_reg_ghd_to_nodes reg_ghd_to_nodes;
|
||||
};
|
||||
uint32_t type;
|
||||
uint32_t pad;
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_gl_inter_req)
|
||||
VHSAKMT_DEFINE_CAST(vhsakmt_ccmd_req, vhsakmt_ccmd_gl_inter_req)
|
||||
|
||||
struct vhsakmt_ccmd_gl_inter_rsp {
|
||||
struct vhsakmt_ccmd_rsp hdr;
|
||||
int32_t ret;
|
||||
union {
|
||||
HsaGraphicsResourceInfo info;
|
||||
};
|
||||
uint8_t payload[];
|
||||
};
|
||||
VHSAKMT_STATIC_ASSERT_SIZE(vhsakmt_ccmd_gl_inter_rsp)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
static inline uint64_t vhsakmt_doorbell_page_size(void) { return 0x2000; }
|
||||
static inline uint64_t vhsakmt_queue_page_size(void) { return getpagesize(); }
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtSetTrapHandler(HSAuint32 NodeId, void* TrapHandlerBaseAddress,
|
||||
HSAuint64 TrapHandlerSizeInBytes,
|
||||
void* TrapBufferBaseAddress,
|
||||
HSAuint64 TrapBufferSizeInBytes) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_event_rsp* rsp;
|
||||
struct vhsakmt_ccmd_event_req req = {
|
||||
.hdr = VHSAKMT_CCMD(EVENT, sizeof(struct vhsakmt_ccmd_event_req)),
|
||||
.type = VHSAKMT_CCMD_EVENT_SET_TRAP,
|
||||
.set_trap_handler_args =
|
||||
{
|
||||
.NodeId = NodeId,
|
||||
.TrapHandlerBaseAddress = (uint64_t)TrapHandlerBaseAddress,
|
||||
.TrapHandlerSizeInBytes = TrapHandlerSizeInBytes,
|
||||
.TrapBufferBaseAddress = (uint64_t)TrapBufferBaseAddress,
|
||||
.TrapBufferSizeInBytes = TrapBufferSizeInBytes,
|
||||
},
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_event_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
static int vhsakmt_find_aql_rw_bo(vhsakmt_device_handle dev, uint64_t aql_ptr,
|
||||
uint32_t* aql_bo_res_id) {
|
||||
uint64_t aql_base_ptr = VHSA_ALIGN_DOWN(aql_ptr, getpagesize());
|
||||
|
||||
vhsakmt_bo_handle bo = vhsakmt_find_bo_by_addr(dev, (void*)aql_base_ptr);
|
||||
if (!bo) return -EINVAL;
|
||||
|
||||
bo->bo_type |= VHSA_BO_QUEUE_AQL_RW_PTR;
|
||||
*aql_bo_res_id = bo->real.res_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_doorbell_blob_bo(vhsakmt_device_handle dev, uint32_t node, size_t size,
|
||||
uint32_t blob_id, uint64_t host_handle,
|
||||
vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
|
||||
r = vhsakmt_create_mappable_blob_bo(dev, size, blob_id, VHSA_BO_QUEUE_DOORBELL,
|
||||
(void*)host_handle, bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
r = vhsakmt_set_node_doorbell(dev, node, (*bo_handle)->cpu_addr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_queue_rw_blob_bo(vhsakmt_device_handle dev, size_t size, uint32_t blob_id,
|
||||
uint64_t host_handle, vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
|
||||
r = vhsakmt_create_mappable_blob_bo(dev, size, blob_id, VHSA_BO_QUEUE_RW_PTR, NULL, bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
(*bo_handle)->host_addr = (void*)host_handle;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhsakmt_create_queue_blob_bo(vhsakmt_device_handle dev, size_t size, uint32_t blob_id,
|
||||
uint64_t queue_id, vhsakmt_bo_handle rw_bo_handle,
|
||||
vhsakmt_bo_handle* bo_handle) {
|
||||
int r;
|
||||
|
||||
r = vhsakmt_init_host_blob(dev, size, VIRTGPU_BLOB_MEM_HOST3D, 0, blob_id, VHSA_BO_QUEUE, NULL,
|
||||
bo_handle);
|
||||
if (r) return r;
|
||||
|
||||
vhsakmt_insert_bo(dev, *bo_handle, *bo_handle, (*bo_handle)->size);
|
||||
|
||||
(*bo_handle)->queue_id = queue_id;
|
||||
(*bo_handle)->rw_bo = rw_bo_handle;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateQueueExt(HSAuint32 NodeId, HSA_QUEUE_TYPE Type,
|
||||
HSAuint32 QueuePercentage,
|
||||
HSA_QUEUE_PRIORITY Priority, HSAuint32 SdmaEngineId,
|
||||
void* QueueAddress, HSAuint64 QueueSizeInBytes,
|
||||
HsaEvent* Event, HsaQueueResource* QueueResource) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
vhsakmt_bo_handle rw_bo_handle = NULL, doorbell_bo, queue_bo, queue_mem_bo;
|
||||
struct vhsakmt_ccmd_queue_rsp* rsp;
|
||||
struct vhsakmt_ccmd_queue_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUEUE, sizeof(struct vhsakmt_ccmd_queue_req)),
|
||||
.type = VHSAKMT_CCMD_QUEUE_CREATE,
|
||||
.create_queue_args =
|
||||
{
|
||||
.NodeId = NodeId,
|
||||
.Type = Type,
|
||||
.QueuePercentage = QueuePercentage,
|
||||
.Priority = Priority,
|
||||
.SdmaEngineId = SdmaEngineId,
|
||||
.QueueAddress = (uint64_t)QueueAddress,
|
||||
.QueueSizeInBytes = QueueSizeInBytes,
|
||||
.Event = Event ? vhsakmt_event_host_handle(Event) : 0,
|
||||
.Queue_write_ptr_aql = QueueResource->Queue_write_ptr_aql,
|
||||
.Queue_read_ptr_aql = QueueResource->Queue_read_ptr_aql,
|
||||
},
|
||||
.blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id), /* For queue resource */
|
||||
.doorbell_blob_id = vhsakmt_node_doorbell(dev, NodeId)
|
||||
? 0
|
||||
: vhsakmt_atomic_inc_return(&dev->next_blob_id), /* For queue doorbell memory map */
|
||||
};
|
||||
int r;
|
||||
|
||||
/* Queue ptr memory is allocated by hsakmtallocmemory in host then mapped into guest, but their
|
||||
* address are not aligned. */
|
||||
if (Type == HSA_QUEUE_COMPUTE_AQL) {
|
||||
r = vhsakmt_find_aql_rw_bo(dev, QueueResource->QueueWptrValue, &req.res_id);
|
||||
if (r) {
|
||||
vhsa_debug("%s: can not find the AQL queue R/W BO: %p\n", __FUNCTION__,
|
||||
QueueResource->Queue_write_ptr_aql);
|
||||
return HSAKMT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
vhsa_debug("%s: create AQL queue, read ptr: %p, write ptr: %p, res id: %d\n", __FUNCTION__,
|
||||
QueueResource->Queue_read_ptr_aql, QueueResource->Queue_write_ptr_aql, req.res_id);
|
||||
} else
|
||||
/* For queue not CP AQL, it use r/w ptr by itself. */
|
||||
req.rw_ptr_blob_id = vhsakmt_atomic_inc_return(&dev->next_blob_id);
|
||||
|
||||
queue_mem_bo = vhsakmt_find_bo_by_addr(dev, QueueAddress);
|
||||
if (!queue_mem_bo) {
|
||||
vhsa_err("%s: can not find the queue memory BO: %p\n", __FUNCTION__, QueueAddress);
|
||||
return HSAKMT_STATUS_NO_MEMORY;
|
||||
}
|
||||
queue_mem_bo->bo_type |= VHSA_BO_QUEUE_AQL_RW_PTR;
|
||||
req.queue_mem_res_id = queue_mem_bo->real.res_id;
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_queue_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (rsp->ret) {
|
||||
vhsa_err("%s: queue create failed, ret: %d", __FUNCTION__, rsp->ret);
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
/* Map doorbell */
|
||||
if (req.doorbell_blob_id) {
|
||||
r = vhsakmt_create_doorbell_blob_bo(
|
||||
dev, NodeId, vhsakmt_doorbell_page_size(), req.doorbell_blob_id,
|
||||
rsp->vqueue_res.host_doorbell - rsp->vqueue_res.host_doorbell_offset, &doorbell_bo);
|
||||
if (r) {
|
||||
vhsa_err("%s: doorbell create failed, doorbell: %lx\n", __FUNCTION__,
|
||||
rsp->vqueue_res.host_doorbell);
|
||||
return r;
|
||||
}
|
||||
vhsa_debug("%s: create doorbell: %p, size: 0x%x\n", __FUNCTION__, doorbell_bo->cpu_addr,
|
||||
doorbell_bo->size);
|
||||
}
|
||||
|
||||
QueueResource->Queue_DoorBell_aql = (void*)rsp->vqueue_res.host_doorbell;
|
||||
vhsa_debug("%s: queue create, Doorbell: %p\n", __FUNCTION__, QueueResource->Queue_DoorBell_aql);
|
||||
|
||||
/* Map R/W pointer.
|
||||
* For a queue is not a COMPUTE AQL, the R/W PTR not using the input address,
|
||||
* uses the queue memory allocated by hsakmtallocmemory, a page align address.
|
||||
*/
|
||||
if (Type != HSA_QUEUE_COMPUTE_AQL) {
|
||||
r = vhsakmt_create_queue_rw_blob_bo(dev, vhsakmt_queue_page_size(), req.rw_ptr_blob_id,
|
||||
rsp->vqueue_res.host_rw_handle, &rw_bo_handle);
|
||||
if (r) {
|
||||
vhsa_debug("%s: queue rw ptr create failed, host addr: %p\n", __FUNCTION__,
|
||||
(void*)rsp->vqueue_res.host_rw_handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
QueueResource->Queue_write_ptr_aql = VHSA_UINT64_TO_VPTR(
|
||||
VHSA_VPTR_TO_UINT64(rw_bo_handle->cpu_addr) + rsp->vqueue_res.host_write_offset);
|
||||
QueueResource->Queue_read_ptr_aql = VHSA_UINT64_TO_VPTR(
|
||||
VHSA_VPTR_TO_UINT64(rw_bo_handle->cpu_addr) + rsp->vqueue_res.host_read_offset);
|
||||
|
||||
vhsa_debug("%s: queue create: write ptr gva: %p, read ptr gva: %p, base hva: %lx\n",
|
||||
__FUNCTION__, QueueResource->Queue_write_ptr_aql, QueueResource->Queue_read_ptr_aql,
|
||||
rsp->vqueue_res.host_rw_handle);
|
||||
}
|
||||
|
||||
r = vhsakmt_create_queue_blob_bo(dev, QueueSizeInBytes, req.blob_id, rsp->vqueue_res.r.QueueId,
|
||||
rw_bo_handle, &queue_bo);
|
||||
if (r) {
|
||||
vhsa_err("%s: queue create failed, queue ID: 0x%lx\n", __FUNCTION__, rsp->vqueue_res.r.QueueId);
|
||||
return r;
|
||||
}
|
||||
QueueResource->QueueId = (uint64_t)queue_bo;
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtCreateQueue(HSAuint32 NodeId, HSA_QUEUE_TYPE Type,
|
||||
HSAuint32 QueuePercentage, HSA_QUEUE_PRIORITY Priority,
|
||||
void* QueueAddress, HSAuint64 QueueSizeInBytes,
|
||||
HsaEvent* Event, HsaQueueResource* QueueResource) {
|
||||
return vhsaKmtCreateQueueExt(NodeId, Type, QueuePercentage, Priority, VHSA_SDMA_NONE,
|
||||
QueueAddress, QueueSizeInBytes, Event, QueueResource);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtDestroyQueue(HSA_QUEUEID QueueId) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
int r;
|
||||
|
||||
/* queue ID: vhsakmt_bo_handle -> real queue ID*/
|
||||
vhsakmt_bo_handle bo = (vhsakmt_bo_handle)QueueId;
|
||||
vhsakmt_bo_handle rw_bo = bo->rw_bo;
|
||||
|
||||
r = vhsakmt_bo_free(dev, bo);
|
||||
if (rw_bo) vhsakmt_bo_free(dev, rw_bo);
|
||||
|
||||
vhsa_debug("%s: queue res id: %d, queue ID: %" PRIu64 ", ret = %d\n", __FUNCTION__,
|
||||
bo->real.res_id, bo->queue_id, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hsakmt/hsakmt_virtio.h"
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
static int vhsakmt_set_sys_props(vhsakmt_device_handle dev, HsaSystemProperties* sys_props) {
|
||||
int r = 0;
|
||||
|
||||
pthread_mutex_lock(&dev->vhsakmt_mutex);
|
||||
if (dev->sys_props) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->sys_props = calloc(1, sizeof(HsaSystemProperties));
|
||||
if (!dev->sys_props) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(dev->sys_props, sys_props, sizeof(HsaSystemProperties));
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dev->vhsakmt_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhsakmt_set_node_props(vhsakmt_device_handle dev, uint32_t node,
|
||||
HsaNodeProperties* node_props) {
|
||||
int r = 0;
|
||||
if (!dev->sys_props) return -EINVAL;
|
||||
if (node >= dev->sys_props->NumNodes) return -EINVAL;
|
||||
|
||||
pthread_mutex_lock(&dev->vhsakmt_mutex);
|
||||
|
||||
if (!dev->vhsakmt_nodes) {
|
||||
dev->vhsakmt_nodes = calloc(dev->sys_props->NumNodes, sizeof(struct vhsakmt_node));
|
||||
if (!dev->vhsakmt_nodes) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&dev->vhsakmt_nodes[node].node_props, node_props, sizeof(HsaNodeProperties));
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dev->vhsakmt_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetVersion(HsaVersionInfo* v) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_VER,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
memcpy(v, &rsp->kfd_version, sizeof(HsaVersionInfo));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtAcquireSystemProperties(HsaSystemProperties* SystemProperties) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
int r;
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_SYS_PROP,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
memcpy(SystemProperties, &rsp->sys_props, sizeof(HsaSystemProperties));
|
||||
|
||||
r = vhsakmt_set_sys_props(dev, SystemProperties);
|
||||
if (r) return r;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtReleaseSystemProperties(void) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_REL_SYS_PROP,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
if (dev->sys_props) {
|
||||
free(dev->sys_props);
|
||||
dev->sys_props = NULL;
|
||||
}
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeProperties(HSAuint32 NodeId,
|
||||
HsaNodeProperties* NodeProperties) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
int r;
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.NodeID = NodeId,
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_NODE_PROP,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
memcpy(NodeProperties, &rsp->node_props, sizeof(HsaNodeProperties));
|
||||
|
||||
r = vhsakmt_set_node_props(dev, NodeId, NodeProperties);
|
||||
if (r) return r;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetXNACKMode(HSAint32* enable) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_XNACK_MODE,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
memcpy(enable, &rsp->xnack_mode, sizeof(HSAint32));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRuntimeEnable(void* rDebug, bool setupTtmp) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.run_time_enable_args.setupTtmp = setupTtmp,
|
||||
.type = VHSAKMT_CCMD_QUERY_RUN_TIME_ENABLE,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtRuntimeDisable(void) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_RUN_TIME_DISABLE,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeMemoryProperties(HSAuint32 NodeId, HSAuint32 NumBanks,
|
||||
HsaMemoryProperties* MemoryProperties) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_NOD_MEM_PROP,
|
||||
.node_mem_prop_args.NodeId = NodeId,
|
||||
.node_mem_prop_args.NumBanks = NumBanks,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(
|
||||
dev, &req.hdr,
|
||||
sizeof(struct vhsakmt_ccmd_query_info_rsp) + NumBanks * sizeof(HsaMemoryProperties));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(MemoryProperties, rsp->payload, NumBanks * sizeof(HsaMemoryProperties));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeCacheProperties(HSAuint32 NodeId, HSAuint32 ProcessorId,
|
||||
HSAuint32 NumCaches,
|
||||
HsaCacheProperties* CacheProperties) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_NOD_CACHE_PROP,
|
||||
.node_cache_prop_args.NodeId = NodeId,
|
||||
.node_cache_prop_args.ProcessorId = ProcessorId,
|
||||
.node_cache_prop_args.NumCaches = NumCaches,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(
|
||||
dev, &req.hdr,
|
||||
sizeof(struct vhsakmt_ccmd_query_info_rsp) + NumCaches * sizeof(HsaCacheProperties));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(CacheProperties, rsp->payload, NumCaches * sizeof(HsaCacheProperties));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetNodeIoLinkProperties(HSAuint32 NodeId, HSAuint32 NumIoLinks,
|
||||
HsaIoLinkProperties* IoLinkProperties) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_NOD_IO_LINK_PROP,
|
||||
.node_io_link_args.NodeId = NodeId,
|
||||
.node_io_link_args.NumIoLinks = NumIoLinks,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(
|
||||
dev, &req.hdr,
|
||||
sizeof(struct vhsakmt_ccmd_query_info_rsp) + NumIoLinks * sizeof(HsaIoLinkProperties));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(IoLinkProperties, rsp->payload, NumIoLinks * sizeof(HsaIoLinkProperties));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetClockCounters(HSAuint32 NodeId, HsaClockCounters* Counters) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_CLOCK_COUNTERS,
|
||||
.NodeID = NodeId,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
memcpy(Counters, &rsp->clock_counters, sizeof(HsaClockCounters));
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS HSAKMTAPI vhsaKmtGetRuntimeCapabilities(HSAuint32* caps_mask) {
|
||||
CHECK_VIRTIO_KFD_OPEN();
|
||||
|
||||
vhsakmt_device_handle dev = vhsakmt_dev();
|
||||
struct vhsakmt_ccmd_query_info_rsp* rsp;
|
||||
struct vhsakmt_ccmd_query_info_req req = {
|
||||
.hdr = VHSAKMT_CCMD(QUERY_INFO, sizeof(struct vhsakmt_ccmd_query_info_req)),
|
||||
.type = VHSAKMT_CCMD_QUERY_GET_RUNTIME_CAPS,
|
||||
};
|
||||
|
||||
rsp = vhsakmt_alloc_rsp(dev, &req.hdr, sizeof(struct vhsakmt_ccmd_query_info_rsp));
|
||||
if (!rsp) return -ENOMEM;
|
||||
|
||||
vhsakmt_execbuf_cpu(dev, &req.hdr, __FUNCTION__);
|
||||
|
||||
*caps_mask = rsp->caps;
|
||||
|
||||
return rsp->ret;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hsakmt_virtio_device.h"
|
||||
|
||||
void* vhsakmt_vm_start(void) {
|
||||
void* vm_start = malloc(getpagesize());
|
||||
if (!vm_start) return NULL;
|
||||
|
||||
free(vm_start);
|
||||
return vm_start;
|
||||
}
|
||||
|
||||
int vhsakmt_reserve_va(uint64_t start, uint64_t size) {
|
||||
int32_t protFlags = PROT_NONE;
|
||||
int32_t mapFlags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||
void* va = mmap((void*)start, size, protFlags, mapFlags, -1, 0);
|
||||
if (va == MAP_FAILED) return -ENOMEM;
|
||||
|
||||
if (va != (void*)start) return -ENOMEM;
|
||||
|
||||
madvise(va, size, MADV_DONTFORK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vhsakmt_dereserve_va(uint64_t start, uint64_t size) { munmap((void*)start, size); }
|
||||
|
||||
void vhsakmt_set_scratch_area(vhsakmt_device_handle dev, uint32_t node, uint64_t start,
|
||||
uint64_t size) {
|
||||
if (!dev->vhsakmt_nodes || !dev->sys_props) return;
|
||||
if (node >= dev->sys_props->NumNodes) return;
|
||||
|
||||
pthread_mutex_lock(&dev->vhsakmt_mutex);
|
||||
|
||||
if (dev->vhsakmt_nodes[node].scratch_start && dev->vhsakmt_nodes[node].scratch_size) goto out;
|
||||
|
||||
dev->vhsakmt_nodes[node].scratch_start = start;
|
||||
dev->vhsakmt_nodes[node].scratch_size = size;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dev->vhsakmt_mutex);
|
||||
}
|
||||
|
||||
bool vhsakmt_is_scratch_mem(vhsakmt_device_handle dev, void* addr) {
|
||||
uint32_t i;
|
||||
if (!dev->vhsakmt_nodes || !dev->sys_props) return false;
|
||||
|
||||
for (i = 0; i < dev->sys_props->NumNodes; i++) {
|
||||
if ((uint64_t)addr >= dev->vhsakmt_nodes[i].scratch_start &&
|
||||
(uint64_t)addr <= dev->vhsakmt_nodes[i].scratch_start + dev->vhsakmt_nodes[i].scratch_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void vhsakmt_set_vm_area(vhsakmt_device_handle dev, uint64_t start, uint64_t size) {
|
||||
pthread_mutex_lock(&dev->vhsakmt_mutex);
|
||||
if (dev->vm_start && dev->vm_size) goto out;
|
||||
|
||||
dev->vm_start = start;
|
||||
dev->vm_size = size;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dev->vhsakmt_mutex);
|
||||
}
|
||||
|
||||
bool vhsakmt_is_userptr(vhsakmt_device_handle dev, void* addr) {
|
||||
return !((uint64_t)addr >= dev->vm_start && (uint64_t)addr <= dev->vm_start + dev->vm_size);
|
||||
}
|
||||
|
||||
int vhsakmt_set_node_doorbell(vhsakmt_device_handle dev, uint32_t node, void* doorbell) {
|
||||
if (!dev->vhsakmt_nodes || !dev->sys_props) return -EINVAL;
|
||||
if (node >= dev->sys_props->NumNodes) return -EINVAL;
|
||||
|
||||
pthread_mutex_lock(&dev->vhsakmt_mutex);
|
||||
|
||||
dev->vhsakmt_nodes[node].doorbell_base = doorbell;
|
||||
|
||||
pthread_mutex_unlock(&dev->vhsakmt_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* vhsakmt_node_doorbell(vhsakmt_device_handle dev, uint32_t node) {
|
||||
if (!dev->vhsakmt_nodes || !dev->sys_props) return NULL;
|
||||
if (node >= dev->sys_props->NumNodes) return NULL;
|
||||
|
||||
return dev->vhsakmt_nodes[node].doorbell_base;
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2013 Red Hat
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef VIRTGPU_DRM_H
|
||||
#define VIRTGPU_DRM_H
|
||||
|
||||
#include "drm.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Please note that modifications to all structs defined here are
|
||||
* subject to backwards-compatibility constraints.
|
||||
*
|
||||
* Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel
|
||||
* compatibility Keep fields aligned to their size
|
||||
*/
|
||||
|
||||
#define DRM_VIRTGPU_MAP 0x01
|
||||
#define DRM_VIRTGPU_EXECBUFFER 0x02
|
||||
#define DRM_VIRTGPU_GETPARAM 0x03
|
||||
#define DRM_VIRTGPU_RESOURCE_CREATE 0x04
|
||||
#define DRM_VIRTGPU_RESOURCE_INFO 0x05
|
||||
#define DRM_VIRTGPU_TRANSFER_FROM_HOST 0x06
|
||||
#define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07
|
||||
#define DRM_VIRTGPU_WAIT 0x08
|
||||
#define DRM_VIRTGPU_GET_CAPS 0x09
|
||||
#define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a
|
||||
#define DRM_VIRTGPU_CONTEXT_INIT 0x0b
|
||||
|
||||
#define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01
|
||||
#define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02
|
||||
#define VIRTGPU_EXECBUF_RING_IDX 0x04
|
||||
#define VIRTGPU_EXECBUF_FLAGS (\
|
||||
VIRTGPU_EXECBUF_FENCE_FD_IN |\
|
||||
VIRTGPU_EXECBUF_FENCE_FD_OUT |\
|
||||
VIRTGPU_EXECBUF_RING_IDX |\
|
||||
0)
|
||||
|
||||
struct drm_virtgpu_map {
|
||||
__u64 offset; /* use for mmap system call */
|
||||
__u32 handle;
|
||||
__u32 pad;
|
||||
};
|
||||
|
||||
#define VIRTGPU_EXECBUF_SYNCOBJ_RESET 0x01
|
||||
#define VIRTGPU_EXECBUF_SYNCOBJ_FLAGS ( \
|
||||
VIRTGPU_EXECBUF_SYNCOBJ_RESET | \
|
||||
0)
|
||||
struct drm_virtgpu_execbuffer_syncobj {
|
||||
__u32 handle;
|
||||
__u32 flags;
|
||||
__u64 point;
|
||||
};
|
||||
|
||||
/* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */
|
||||
struct drm_virtgpu_execbuffer {
|
||||
__u32 flags;
|
||||
__u32 size;
|
||||
__u64 command; /* void* */
|
||||
__u64 bo_handles;
|
||||
__u32 num_bo_handles;
|
||||
__s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */
|
||||
__u32 ring_idx; /* command ring index (see VIRTGPU_EXECBUF_RING_IDX) */
|
||||
__u32 syncobj_stride; /* size of @drm_virtgpu_execbuffer_syncobj */
|
||||
__u32 num_in_syncobjs;
|
||||
__u32 num_out_syncobjs;
|
||||
__u64 in_syncobjs;
|
||||
__u64 out_syncobjs;
|
||||
};
|
||||
|
||||
#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
|
||||
#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */
|
||||
#define VIRTGPU_PARAM_RESOURCE_BLOB 3 /* DRM_VIRTGPU_RESOURCE_CREATE_BLOB */
|
||||
#define VIRTGPU_PARAM_HOST_VISIBLE 4 /* Host blob resources are mappable */
|
||||
#define VIRTGPU_PARAM_CROSS_DEVICE 5 /* Cross virtio-device resource sharing */
|
||||
#define VIRTGPU_PARAM_CONTEXT_INIT 6 /* DRM_VIRTGPU_CONTEXT_INIT */
|
||||
#define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */
|
||||
#define VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME 8 /* Ability to set debug name from userspace */
|
||||
|
||||
struct drm_virtgpu_getparam {
|
||||
__u64 param;
|
||||
__u64 value;
|
||||
};
|
||||
|
||||
/* NO_BO flags? NO resource flag? */
|
||||
/* resource flag for y_0_top */
|
||||
struct drm_virtgpu_resource_create {
|
||||
__u32 target;
|
||||
__u32 format;
|
||||
__u32 bind;
|
||||
__u32 width;
|
||||
__u32 height;
|
||||
__u32 depth;
|
||||
__u32 array_size;
|
||||
__u32 last_level;
|
||||
__u32 nr_samples;
|
||||
__u32 flags;
|
||||
__u32 bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
|
||||
__u32 res_handle; /* returned by kernel */
|
||||
__u32 size; /* validate transfer in the host */
|
||||
__u32 stride; /* validate transfer in the host */
|
||||
};
|
||||
|
||||
struct drm_virtgpu_resource_info {
|
||||
__u32 bo_handle;
|
||||
__u32 res_handle;
|
||||
__u32 size;
|
||||
__u32 blob_mem;
|
||||
};
|
||||
|
||||
struct drm_virtgpu_3d_box {
|
||||
__u32 x;
|
||||
__u32 y;
|
||||
__u32 z;
|
||||
__u32 w;
|
||||
__u32 h;
|
||||
__u32 d;
|
||||
};
|
||||
|
||||
struct drm_virtgpu_3d_transfer_to_host {
|
||||
__u32 bo_handle;
|
||||
struct drm_virtgpu_3d_box box;
|
||||
__u32 level;
|
||||
__u32 offset;
|
||||
__u32 stride;
|
||||
__u32 layer_stride;
|
||||
};
|
||||
|
||||
struct drm_virtgpu_3d_transfer_from_host {
|
||||
__u32 bo_handle;
|
||||
struct drm_virtgpu_3d_box box;
|
||||
__u32 level;
|
||||
__u32 offset;
|
||||
__u32 stride;
|
||||
__u32 layer_stride;
|
||||
};
|
||||
|
||||
#define VIRTGPU_WAIT_NOWAIT 1 /* like it */
|
||||
struct drm_virtgpu_3d_wait {
|
||||
__u32 handle; /* 0 is an invalid handle */
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
#define VIRTGPU_DRM_CAPSET_VIRGL 1
|
||||
#define VIRTGPU_DRM_CAPSET_VIRGL2 2
|
||||
#define VIRTGPU_DRM_CAPSET_GFXSTREAM_VULKAN 3
|
||||
#define VIRTGPU_DRM_CAPSET_VENUS 4
|
||||
#define VIRTGPU_DRM_CAPSET_CROSS_DOMAIN 5
|
||||
#define VIRTGPU_DRM_CAPSET_DRM 6
|
||||
struct drm_virtgpu_get_caps {
|
||||
__u32 cap_set_id;
|
||||
__u32 cap_set_ver;
|
||||
__u64 addr;
|
||||
__u32 size;
|
||||
__u32 pad;
|
||||
};
|
||||
|
||||
struct drm_virtgpu_resource_create_blob {
|
||||
#define VIRTGPU_BLOB_MEM_GUEST 0x0001
|
||||
#define VIRTGPU_BLOB_MEM_HOST3D 0x0002
|
||||
#define VIRTGPU_BLOB_MEM_HOST3D_GUEST 0x0003
|
||||
|
||||
#define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001
|
||||
#define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002
|
||||
#define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
|
||||
#define VIRTGPU_BLOB_FLAG_USE_USERPTR 0x0008
|
||||
/* zero is invalid blob_mem */
|
||||
__u32 blob_mem;
|
||||
__u32 blob_flags;
|
||||
__u32 bo_handle;
|
||||
__u32 res_handle;
|
||||
__u64 size;
|
||||
|
||||
/*
|
||||
* for 3D contexts with VIRTGPU_BLOB_MEM_HOST3D_GUEST and
|
||||
* VIRTGPU_BLOB_MEM_HOST3D otherwise, must be zero.
|
||||
*/
|
||||
__u32 pad;
|
||||
__u32 cmd_size;
|
||||
__u64 cmd;
|
||||
__u64 blob_id;
|
||||
__u64 blob_userptr;
|
||||
__s64 offset;
|
||||
};
|
||||
|
||||
#define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001
|
||||
#define VIRTGPU_CONTEXT_PARAM_NUM_RINGS 0x0002
|
||||
#define VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK 0x0003
|
||||
#define VIRTGPU_CONTEXT_PARAM_DEBUG_NAME 0x0004
|
||||
struct drm_virtgpu_context_set_param {
|
||||
__u64 param;
|
||||
__u64 value;
|
||||
};
|
||||
|
||||
struct drm_virtgpu_context_init {
|
||||
__u32 num_params;
|
||||
__u32 pad;
|
||||
|
||||
/* pointer to drm_virtgpu_context_set_param array */
|
||||
__u64 ctx_set_params;
|
||||
};
|
||||
|
||||
/*
|
||||
* Event code that's given when VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK is in
|
||||
* effect. The event size is sizeof(drm_event), since there is no additional
|
||||
* payload.
|
||||
*/
|
||||
#define VIRTGPU_EVENT_FENCE_SIGNALED 0x90000000
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_MAP \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_EXECBUFFER \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
|
||||
struct drm_virtgpu_execbuffer)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_GETPARAM \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GETPARAM,\
|
||||
struct drm_virtgpu_getparam)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE, \
|
||||
struct drm_virtgpu_resource_create)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_RESOURCE_INFO \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_INFO, \
|
||||
struct drm_virtgpu_resource_info)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_FROM_HOST, \
|
||||
struct drm_virtgpu_3d_transfer_from_host)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_TO_HOST, \
|
||||
struct drm_virtgpu_3d_transfer_to_host)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_WAIT \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WAIT, \
|
||||
struct drm_virtgpu_3d_wait)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_GET_CAPS \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \
|
||||
struct drm_virtgpu_get_caps)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_BLOB, \
|
||||
struct drm_virtgpu_resource_create_blob)
|
||||
|
||||
#define DRM_IOCTL_VIRTGPU_CONTEXT_INIT \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_CONTEXT_INIT, \
|
||||
struct drm_virtgpu_context_init)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
global:
|
||||
vhsaKmtOpenKFD;
|
||||
vhsaKmtCloseKFD;
|
||||
vhsaKmtAllocMemory;
|
||||
vhsaKmtFreeMemory;
|
||||
vhsaKmtMapMemoryToGPUNodes;
|
||||
vhsaKmtUnmapMemoryToGPU;
|
||||
vhsaKmtAvailableMemory;
|
||||
vhsaKmtMapMemoryToGPU;
|
||||
vhsaKmtRegisterMemoryWithFlags;
|
||||
vhsaKmtDeregisterMemory;
|
||||
vhsaKmtGetVersion;
|
||||
vhsaKmtAcquireSystemProperties;
|
||||
vhsaKmtReleaseSystemProperties;
|
||||
vhsaKmtGetNodeProperties;
|
||||
vhsaKmtGetXNACKMode;
|
||||
vhsaKmtRuntimeEnable;
|
||||
vhsaKmtRuntimeDisable;
|
||||
vhsaKmtGetNodeMemoryProperties;
|
||||
vhsaKmtGetNodeCacheProperties;
|
||||
vhsaKmtGetNodeIoLinkProperties;
|
||||
vhsaKmtGetClockCounters;
|
||||
vhsaKmtGetAMDGPUDeviceHandle;
|
||||
vhsaKmtQueryPointerInfo;
|
||||
vhsaKmtGetTileConfig;
|
||||
vhsaKmtCreateEvent;
|
||||
vhsaKmtDestroyEvent;
|
||||
vhsaKmtSetEvent;
|
||||
vhsaKmtResetEvent;
|
||||
vhsaKmtQueryEventState;
|
||||
vhsaKmtWaitOnMultipleEvents;
|
||||
vhsaKmtWaitOnEvent;
|
||||
vhsaKmtWaitOnEvent_Ext;
|
||||
vhsaKmtWaitOnMultipleEvents_Ext;
|
||||
vhsaKmtSetTrapHandler;
|
||||
vhsaKmtCreateQueueExt;
|
||||
vhsaKmtCreateQueue;
|
||||
vhsaKmtDestroyQueue;
|
||||
vhsaKmtRegisterGraphicsHandleToNodes;
|
||||
vhsaKmtGetRuntimeCapabilities;
|
||||
vamdgpu_query_gpu_info;
|
||||
local: *;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libsync.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "virtio_gpu.h"
|
||||
|
||||
#define SHMEM_SZ (25 * 0x1000)
|
||||
|
||||
static int set_context(int fd) {
|
||||
struct drm_virtgpu_context_set_param params[] = {
|
||||
{VIRTGPU_CONTEXT_PARAM_CAPSET_ID, VIRGL_RENDERER_CAPSET_HSAKMT},
|
||||
{VIRTGPU_CONTEXT_PARAM_NUM_RINGS, 64},
|
||||
};
|
||||
struct drm_virtgpu_context_init args = {
|
||||
.num_params = ARRAY_SIZE(params),
|
||||
.ctx_set_params = (uintptr_t)(params),
|
||||
};
|
||||
|
||||
return virtio_gpu_ioctl(fd, VIRTGPU_CONTEXT_INIT, &args);
|
||||
}
|
||||
|
||||
int virtio_gpu_map_handle(struct virtio_gpu_device* vgdev, uint32_t handle, uint64_t size,
|
||||
void** addr, void* fixed_map) {
|
||||
struct drm_virtgpu_map args = {
|
||||
.handle = handle,
|
||||
};
|
||||
int r;
|
||||
|
||||
r = virtio_gpu_ioctl(vgdev->fd, VIRTGPU_MAP, &args);
|
||||
if (r) return r;
|
||||
|
||||
*addr = mmap(fixed_map, size, PROT_READ | PROT_WRITE, MAP_SHARED | (fixed_map ? MAP_FIXED : 0),
|
||||
vgdev->fd, args.offset);
|
||||
|
||||
if (*addr == MAP_FAILED) return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void virtio_gpu_unmap(void* addr, uint64_t size) { munmap(addr, size); }
|
||||
|
||||
static void virtio_gpu_bo_close(struct virtio_gpu_device* vgdev, uint32_t handle) {
|
||||
struct drm_gem_close args = {
|
||||
.handle = handle,
|
||||
};
|
||||
|
||||
virtio_gpu_ioctl(vgdev->fd, GEM_CLOSE, &args);
|
||||
}
|
||||
|
||||
static int virtio_gpu_shmem_init(struct virtio_gpu_device* vgdev, size_t size) {
|
||||
struct drm_virtgpu_resource_create_blob args = {
|
||||
.blob_mem = VIRTGPU_BLOB_MEM_HOST3D,
|
||||
.blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE,
|
||||
.size = size,
|
||||
.blob_id = 0,
|
||||
};
|
||||
|
||||
int r = virtio_gpu_ioctl(vgdev->fd, VIRTGPU_RESOURCE_CREATE_BLOB, &args);
|
||||
if (r) return r;
|
||||
|
||||
r = virtio_gpu_map_handle(vgdev, args.bo_handle, size, (void**)&vgdev->shmem, NULL);
|
||||
if (r) {
|
||||
virtio_gpu_bo_close(vgdev, args.bo_handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
vgdev->shmem_handle = args.bo_handle;
|
||||
|
||||
uint32_t offset = vgdev->shmem->base.rsp_mem_offset;
|
||||
vgdev->rsp_mem_len = size - offset;
|
||||
vgdev->rsp_mem = &((uint8_t*)vgdev->shmem)[offset];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct virtio_gpu_device* virtio_gpu_init(int fd, uint32_t context_id) {
|
||||
struct virtio_gpu_device* vgdev;
|
||||
int r;
|
||||
|
||||
r = set_context(fd);
|
||||
|
||||
if (r) return NULL;
|
||||
|
||||
vgdev = calloc(1, sizeof(*vgdev));
|
||||
if (!vgdev) return NULL;
|
||||
|
||||
vgdev->fd = fd;
|
||||
|
||||
vgdev->reqbuf = calloc(1, SHMEM_SZ);
|
||||
if (!vgdev->reqbuf) {
|
||||
free(vgdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = virtio_gpu_shmem_init(vgdev, SHMEM_SZ);
|
||||
if (r) {
|
||||
free(vgdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&vgdev->rsp_lock, NULL);
|
||||
pthread_mutex_init(&vgdev->eb_lock, NULL);
|
||||
|
||||
return vgdev;
|
||||
}
|
||||
|
||||
void virtio_gpu_close(struct virtio_gpu_device* vgdev) {
|
||||
virtio_gpu_unmap(vgdev->shmem, SHMEM_SZ);
|
||||
virtio_gpu_bo_close(vgdev, vgdev->shmem_handle);
|
||||
|
||||
pthread_mutex_destroy(&vgdev->rsp_lock);
|
||||
pthread_mutex_destroy(&vgdev->eb_lock);
|
||||
|
||||
close(vgdev->fd);
|
||||
free(vgdev->reqbuf);
|
||||
free(vgdev);
|
||||
}
|
||||
|
||||
void* virtio_gpu_alloc_rsp(struct virtio_gpu_device* vgdev, struct virtio_gpu_ccmd_req* req,
|
||||
uint32_t size) {
|
||||
uint32_t off;
|
||||
|
||||
pthread_mutex_lock(&vgdev->rsp_lock);
|
||||
|
||||
size = VHSA_ALIGN_UP(size, 8);
|
||||
|
||||
if ((vgdev->next_rsp_off + size) >= vgdev->rsp_mem_len) vgdev->next_rsp_off = 0;
|
||||
|
||||
off = vgdev->next_rsp_off;
|
||||
vgdev->next_rsp_off += size;
|
||||
|
||||
pthread_mutex_unlock(&vgdev->rsp_lock);
|
||||
|
||||
req->rsp_off = off;
|
||||
struct virtio_gpu_ccmd_rsp* rsp = (void*)&vgdev->rsp_mem[off];
|
||||
rsp->len = size;
|
||||
|
||||
return rsp;
|
||||
}
|
||||
|
||||
static int virtio_gpu_execbuffer_locked(struct virtio_gpu_device* vgdev, void* cmd,
|
||||
uint32_t cmd_size, uint32_t* handles, uint32_t num_handles,
|
||||
int* fence_fd, int ring_idx, uint32_t num_in_syncobjs,
|
||||
uint32_t num_out_syncobjs,
|
||||
struct drm_virtgpu_execbuffer_syncobj* in_syncobjs,
|
||||
struct drm_virtgpu_execbuffer_syncobj* out_syncobjs,
|
||||
bool in_fence, bool out_fence) {
|
||||
struct drm_virtgpu_execbuffer eb = {
|
||||
.flags = (out_fence ? VIRTGPU_EXECBUF_FENCE_FD_OUT : 0) |
|
||||
(in_fence ? VIRTGPU_EXECBUF_FENCE_FD_IN : 0) | VIRTGPU_EXECBUF_RING_IDX,
|
||||
.size = cmd_size,
|
||||
.command = (uintptr_t)cmd,
|
||||
.bo_handles = (uintptr_t)handles,
|
||||
.num_bo_handles = num_handles,
|
||||
.fence_fd = *fence_fd,
|
||||
.ring_idx = ring_idx,
|
||||
.syncobj_stride = sizeof(struct drm_virtgpu_execbuffer_syncobj),
|
||||
.num_in_syncobjs = num_in_syncobjs,
|
||||
.num_out_syncobjs = num_out_syncobjs,
|
||||
.in_syncobjs = (uintptr_t)in_syncobjs,
|
||||
.out_syncobjs = (uintptr_t)out_syncobjs,
|
||||
};
|
||||
int r = virtio_gpu_ioctl(vgdev->fd, VIRTGPU_EXECBUFFER, &eb);
|
||||
if (r) return r;
|
||||
|
||||
if (out_fence) *fence_fd = eb.fence_fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_flush_locked(struct virtio_gpu_device* vgdev, int* fence) {
|
||||
int r;
|
||||
|
||||
if (!vgdev->reqbuf_len) return 0;
|
||||
|
||||
r = virtio_gpu_execbuffer_locked(vgdev, vgdev->reqbuf, vgdev->reqbuf_len, NULL, 0, fence, 0, 0, 0,
|
||||
NULL, NULL, false, !!fence);
|
||||
if (r) return r;
|
||||
|
||||
vgdev->reqbuf_len = 0;
|
||||
vgdev->reqbuf_cnt = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_add_cmd(struct virtio_gpu_device* vgdev, struct virtio_gpu_ccmd_req* req) {
|
||||
req->seqno = ++vgdev->next_seqno;
|
||||
int r;
|
||||
|
||||
if (vgdev->reqbuf_len + req->len > sizeof(vgdev->reqbuf)) {
|
||||
r = virtio_gpu_flush_locked(vgdev, NULL);
|
||||
if (r) return r;
|
||||
}
|
||||
|
||||
memcpy(&vgdev->reqbuf[vgdev->reqbuf_len], req, req->len);
|
||||
vgdev->reqbuf_len += req->len;
|
||||
vgdev->reqbuf_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool fence_before(uint32_t a, uint32_t b) { return (int32_t)(a - b) < 0; }
|
||||
|
||||
static void virtio_gpu_seqno_sync(struct virtio_gpu_device* vgdev,
|
||||
struct virtio_gpu_ccmd_req* req) {
|
||||
while (fence_before(vgdev->shmem->base.seqno, req->seqno)) sched_yield();
|
||||
}
|
||||
|
||||
int virtio_gpu_exec_cmd(struct virtio_gpu_device* vgdev, struct virtio_gpu_ccmd_req* req,
|
||||
bool sync) {
|
||||
int r = 0;
|
||||
int fence;
|
||||
|
||||
pthread_mutex_lock(&vgdev->eb_lock);
|
||||
|
||||
r = virtio_gpu_add_cmd(vgdev, req);
|
||||
|
||||
if (r || !sync) goto out;
|
||||
|
||||
r = virtio_gpu_flush_locked(vgdev, &fence);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&vgdev->eb_lock);
|
||||
if (r) return r;
|
||||
|
||||
if (sync) {
|
||||
sync_wait(fence, -1);
|
||||
close(fence);
|
||||
virtio_gpu_seqno_sync(vgdev, req);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int virtio_gpu_create_blob(struct virtio_gpu_device* vgdev,
|
||||
struct drm_virtgpu_resource_create_blob* args) {
|
||||
return virtio_gpu_ioctl(vgdev->fd, VIRTGPU_RESOURCE_CREATE_BLOB, args);
|
||||
}
|
||||
|
||||
int virtio_gpu_destroy_handle(struct virtio_gpu_device* vgdev, uint32_t bo_handle) {
|
||||
struct drm_gem_close args = {
|
||||
.handle = bo_handle,
|
||||
};
|
||||
|
||||
return virtio_gpu_ioctl(vgdev->fd, GEM_CLOSE, &args);
|
||||
}
|
||||
|
||||
int virtio_gpu_res_id(struct virtio_gpu_device* vgdev, uint32_t handle, uint32_t* res_id) {
|
||||
struct drm_virtgpu_resource_info args = {
|
||||
.bo_handle = handle,
|
||||
};
|
||||
int r = virtio_gpu_ioctl(vgdev->fd, VIRTGPU_RESOURCE_INFO, &args);
|
||||
if (r) return r;
|
||||
|
||||
*res_id = args.res_handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_get_capset(int fd, struct virgl_renderer_capset_hsakmt* caps) {
|
||||
struct drm_virtgpu_get_caps args = {
|
||||
.cap_set_id = VIRGL_RENDERER_CAPSET_HSAKMT,
|
||||
.cap_set_ver = 0,
|
||||
.addr = (uintptr_t)caps,
|
||||
.size = sizeof(*caps),
|
||||
};
|
||||
|
||||
memset(caps, 0, sizeof(*caps));
|
||||
|
||||
return virtio_gpu_ioctl(fd, VIRTGPU_GET_CAPS, &args);
|
||||
}
|
||||
|
||||
int virtio_gpu_kfd_open(void) {
|
||||
drmDevicePtr devices[VHSA_MAX_DEVICES];
|
||||
int num_devices = 0;
|
||||
int i, fd, ret;
|
||||
|
||||
num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
|
||||
if (num_devices <= 0) return -1;
|
||||
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) continue;
|
||||
|
||||
struct virgl_renderer_capset_hsakmt caps;
|
||||
ret = virtio_gpu_get_capset(fd, &caps);
|
||||
if (ret || caps.context_type != VIRTGPU_DRM_CONTEXT_AMDGPU) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
drmFreeDevices(devices, num_devices);
|
||||
return fd;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2025 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef VIRTIO_GPU_H
|
||||
#define VIRTIO_GPU_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "virtgpu_drm.h"
|
||||
|
||||
#define VIRGL_RENDERER_CAPSET_HSAKMT 8
|
||||
#define VIRTGPU_DRM_CONTEXT_AMDGPU 1
|
||||
#define VHSA_MAX_DEVICES 10
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#define VHSA_ALIGN_UP(x, align) (((uint64_t)(x) + (align)-1) & ~(uint64_t)((align)-1))
|
||||
#define VHSA_ALIGN_DOWN(x, align) ((uint64_t)(x) & ~(uint64_t)((align)-1))
|
||||
|
||||
#define virtio_gpu_ioctl(fd, name, args) \
|
||||
({ \
|
||||
int ret = drmIoctl((fd), DRM_IOCTL_##name, (args)); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
struct virgl_renderer_capset_hsakmt {
|
||||
uint32_t wire_format_version;
|
||||
/* Underlying drm device version: */
|
||||
uint32_t version_major;
|
||||
uint32_t version_minor;
|
||||
uint32_t version_patchlevel;
|
||||
uint32_t context_type;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct virtio_gpu_shmem_base {
|
||||
uint32_t seqno;
|
||||
uint32_t rsp_mem_offset;
|
||||
};
|
||||
|
||||
struct virtio_gpu_ccmd_req {
|
||||
uint32_t cmd;
|
||||
uint32_t len;
|
||||
uint32_t seqno;
|
||||
uint32_t rsp_off;
|
||||
};
|
||||
|
||||
struct virtio_gpu_ccmd_rsp {
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
struct virtio_gpu_shmem {
|
||||
struct virtio_gpu_shmem_base base;
|
||||
uint32_t async_error;
|
||||
uint32_t global_faults;
|
||||
};
|
||||
|
||||
#define vhsakmt_shmem virtio_gpu_shmem
|
||||
#define vhsakmt_ccmd_req virtio_gpu_ccmd_req
|
||||
#define vhsakmt_ccmd_rsp virtio_gpu_ccmd_rsp
|
||||
|
||||
struct virtio_gpu_device {
|
||||
int fd;
|
||||
|
||||
struct virtio_gpu_shmem* shmem;
|
||||
uint32_t shmem_handle;
|
||||
|
||||
uint8_t* rsp_mem;
|
||||
uint32_t rsp_mem_len;
|
||||
uint32_t next_rsp_off;
|
||||
pthread_mutex_t rsp_lock;
|
||||
pthread_mutex_t eb_lock;
|
||||
|
||||
uint32_t next_seqno;
|
||||
uint32_t reqbuf_len;
|
||||
uint32_t reqbuf_cnt;
|
||||
uint8_t* reqbuf;
|
||||
};
|
||||
|
||||
struct virtio_gpu_device* virtio_gpu_init(int fd, uint32_t context_id);
|
||||
void virtio_gpu_close(struct virtio_gpu_device* vgdev);
|
||||
int virtio_gpu_exec_cmd(struct virtio_gpu_device* vgdev, struct virtio_gpu_ccmd_req* req,
|
||||
bool sync);
|
||||
void* virtio_gpu_alloc_rsp(struct virtio_gpu_device* vgdev, struct virtio_gpu_ccmd_req* req,
|
||||
uint32_t size);
|
||||
int virtio_gpu_map_handle(struct virtio_gpu_device* vgdev, uint32_t handle, uint64_t size,
|
||||
void** addr, void* fixed_map);
|
||||
void virtio_gpu_unmap(void* addr, uint64_t size);
|
||||
int virtio_gpu_create_blob(struct virtio_gpu_device* vgdev,
|
||||
struct drm_virtgpu_resource_create_blob* args);
|
||||
int virtio_gpu_destroy_handle(struct virtio_gpu_device* vgdev, uint32_t bo_handle);
|
||||
int virtio_gpu_res_id(struct virtio_gpu_device* vgdev, uint32_t handle, uint32_t* res_id);
|
||||
int virtio_gpu_kfd_open(void);
|
||||
|
||||
#endif /* VIRTIO_GPU_H */
|
||||
@@ -302,6 +302,10 @@ target_link_libraries ( ${CORE_RUNTIME_TARGET} PRIVATE elf::elf dl pthread rt )
|
||||
# Link to hsakmt-staticdrm target for static library builds
|
||||
if( BUILD_SHARED_LIBS )
|
||||
target_link_libraries ( ${CORE_RUNTIME_TARGET} PRIVATE hsakmt::hsakmt PkgConfig::drm)
|
||||
if( BUILD_THUNK_VIRTIO )
|
||||
message(STATUS "Building with virtio support")
|
||||
target_link_libraries ( ${CORE_RUNTIME_TARGET} PRIVATE hsakmt_virtio)
|
||||
endif()
|
||||
find_package(rocprofiler-register)
|
||||
if(rocprofiler-register_FOUND)
|
||||
target_compile_definitions(${CORE_RUNTIME_TARGET} PRIVATE HSA_ROCPROFILER_REGISTER=1
|
||||
|
||||
Reference in New Issue
Block a user