diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b1b66dd81..f24a2bb3e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ set ( HSAKMT_SRC "src/debug.c" "src/time.c" "src/topology.c" "src/rbtree.c" + "src/spm.c" "src/version.c") ## Include paths diff --git a/include/hsakmt.h b/include/hsakmt.h index 237f80bbc7..4938b8a96e 100644 --- a/include/hsakmt.h +++ b/include/hsakmt.h @@ -1209,6 +1209,58 @@ hsaKmtSetMemoryUserData( void * UserData //IN ); +/** + Acquire request exclusive use of SPM +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMAcquire( + HSAuint32 PreferredNode //IN + ); + + +/** + Disable SPM Streamimg +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMRelease( + HSAuint32 PreferredNode //IN + ); + +/** + Set up the destination user mode buffer for stream performance + counter data. + + PreferredNode -- note Id + + SizeInBytes -- number of byte of Destination buffer for performance + counter data + + timeout -- wait to collect performance counter data + + DestMemoryAddress -- point to user mode buffer for stream performance + counter data + + SPMMemoryAddress -- user mode buffer that contains stream performance + counter data, it ponit to current or one of DestMemoryAddress that set + before. + + SizeCopied -- number of bytes of data copied from Stream Ring buffer. +*/ + +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMSetDestBuffer( + HSAuint32 PreferredNode, //IN + HSAuint64 SizeInBytes, //IN + HSAuint32 timeout, //IN + void* DestMemoryAddress, //IN + void ** SPMMemoryAddress, //OUT + HSAuint32 *SizeCopied //OUT + ); + + #ifdef __cplusplus } //extern "C" #endif diff --git a/include/linux/kfd_ioctl.h b/include/linux/kfd_ioctl.h index 6a7dd1f44a..96df15f3fc 100644 --- a/include/linux/kfd_ioctl.h +++ b/include/linux/kfd_ioctl.h @@ -628,6 +628,53 @@ struct kfd_ioctl_cross_memory_copy_args { __u64 bytes_copied; }; +/** + * kfd_ioctl_spm_op - SPM ioctl operations + * + * @KFD_IOCTL_SPM_OP_ACQUIRE: acquire exclusive access to SPM + * @KFD_IOCTL_SPM_OP_RELEASE: release exclusive access to SPM + * @KFD_IOCTL_SPM_OP_SET_DEST_BUF: set or unset destination buffer for SPM streaming + */ +enum kfd_ioctl_spm_op { + KFD_IOCTL_SPM_OP_ACQUIRE, + KFD_IOCTL_SPM_OP_RELEASE, + KFD_IOCTL_SPM_OP_SET_DEST_BUF +}; + + +/** + * kfd_ioctl_spm_args - Arguments for SPM ioctl + * + * @op: specifies the operation to perform + * @destptr:used for the address of the destination buffer in @KFD_IOCTL_SPM_SET_DEST_BUFFER + * @buf_size:size of the destination buffer in @KFD_IOCTL_SPM_SET_DEST_BUFFER + * @timeout: timeout to wait for the buffer to get filled + * @gpu_id: gpu ID + * @bytes_copied: bytes copied from streaming performance ring buffer + * + * If @ptr is NULL, the destination buffer address is unset and copying of counters + * is stopped. + * + * Returns negative error code on failure. On success, @KFD_IOCTL_SPM_OP_ACQUIRE and + * @KFD_IOCTL_SPM_OP_RELEASE return 0, @KFD_IOCTL_SPM_OP_SET_DEST_BUF returns the fill + * level of the previous buffer. + */ +struct kfd_ioctl_spm_args { + __u64 destptr; + __u64 spmtptr; + __u32 buf_size; + __u32 op; + __u32 timeout; + __u32 gpu_id; /* to KFD */ + /* from KFD: Total amount of bytes copied */ + __u64 bytes_copied; +}; + +struct kfd_spm_set_reg { + __u64 reg; + __u32 value; +}; + #define AMDKFD_IOCTL_BASE 'K' #define AMDKFD_IO(nr) _IO(AMDKFD_IOCTL_BASE, nr) #define AMDKFD_IOR(nr, type) _IOR(AMDKFD_IOCTL_BASE, nr, type) @@ -725,8 +772,12 @@ struct kfd_ioctl_cross_memory_copy_args { #define AMDKFD_IOC_ALLOC_QUEUE_GWS \ AMDKFD_IOWR(0x1E, struct kfd_ioctl_alloc_queue_gws_args) +#define AMDKFD_IOC_RLC_SPM \ + AMDKFD_IOWR(0x20, struct kfd_ioctl_spm_args) + + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x1F +#define AMDKFD_COMMAND_END 0x21 /* non-upstream ioctls */ #define AMDKFD_IOC_IPC_IMPORT_HANDLE \ diff --git a/src/libhsakmt.ver b/src/libhsakmt.ver index d47f68d2d0..97e2cf6beb 100644 --- a/src/libhsakmt.ver +++ b/src/libhsakmt.ver @@ -71,6 +71,9 @@ hsaKmtGetKernelDebugTrapVersionInfo; hsaKmtGetThunkDebugTrapVersionInfo; hsaKmtSetAddressWatch; hsaKmtClearAddressWatch; +hsaKmtSPMAcquire; +hsaKmtSPMRelease; +hsaKmtSPMSetDestBuffer; local: *; }; diff --git a/src/spm.c b/src/spm.c new file mode 100644 index 0000000000..33b2b0a843 --- /dev/null +++ b/src/spm.c @@ -0,0 +1,121 @@ +/* + * Copyright © 2014 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. + */ +#include "libhsakmt.h" +#include "linux/kfd_ioctl.h" +#include +#include + + +HSAKMT_STATUS HSAKMTAPI hsaKmtSPMAcquire(HSAuint32 PreferredNode) +{ + int ret; + struct kfd_ioctl_spm_args args = {0}; + uint32_t gpu_id; + + pr_debug("[%s]\n", __func__); + + ret = validate_nodeid(PreferredNode, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, PreferredNode); + return ret; + } + + ret = HSAKMT_STATUS_SUCCESS; + args.destptr = 0; + args.buf_size = 0; + args.op = KFD_IOCTL_SPM_OP_ACQUIRE; + args.gpu_id = gpu_id; + args.bytes_copied = 0; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + return ret; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtSPMSetDestBuffer(HSAuint32 PreferredNode, + HSAuint64 SizeInBytes, + HSAuint32 timeout, + void* DestMemoryAddress, + void **SPMMemoryAddress, + HSAuint32 *SizeCopied) +{ + int ret; + struct kfd_ioctl_spm_args args = {0}; + uint32_t gpu_id; + + ret = HSAKMT_STATUS_SUCCESS; + + pr_debug("[%s]\n", __func__); + ret = validate_nodeid(PreferredNode, &gpu_id); + + args.timeout = timeout; + args.destptr = (uint64_t)DestMemoryAddress; + + args.buf_size = SizeInBytes; + args.spmtptr = 0; + args.op = KFD_IOCTL_SPM_OP_SET_DEST_BUF; + args.gpu_id = gpu_id; + args.bytes_copied = 0; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + if (ret != HSAKMT_STATUS_SUCCESS) { + *SPMMemoryAddress = NULL; + *SizeCopied = 0; + return ret; + } + + *SPMMemoryAddress = (void *)args.spmtptr; + *SizeCopied = args.bytes_copied; + + return ret; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtSPMRelease(HSAuint32 PreferredNode) +{ + int ret = HSAKMT_STATUS_SUCCESS; + struct kfd_ioctl_spm_args args = {0}; + uint32_t gpu_id; + + pr_debug("[%s]\n", __func__); + + ret = validate_nodeid(PreferredNode, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, PreferredNode); + return ret; + } + + args.destptr = 0; + args.buf_size = 0; + args.op = KFD_IOCTL_SPM_OP_RELEASE; + args.gpu_id = gpu_id; + args.bytes_copied = 0; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + return ret; +} + +