diff --git a/projects/rocr-runtime/CMakeLists.txt b/projects/rocr-runtime/CMakeLists.txt index 684dabe59d..01b02dbf8d 100644 --- a/projects/rocr-runtime/CMakeLists.txt +++ b/projects/rocr-runtime/CMakeLists.txt @@ -111,6 +111,7 @@ set ( HSAKMT_SRC "src/debug.c" "src/time.c" "src/topology.c" "src/rbtree.c" + "src/spm.c" "src/version.c") ## Declare the library target name diff --git a/projects/rocr-runtime/include/hsakmt.h b/projects/rocr-runtime/include/hsakmt.h index 237f80bbc7..83f41cac90 100644 --- a/projects/rocr-runtime/include/hsakmt.h +++ b/projects/rocr-runtime/include/hsakmt.h @@ -1209,6 +1209,41 @@ hsaKmtSetMemoryUserData( void * UserData //IN ); +/** + Acquire request exclusive use of SPM +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMAcquire( + HSAuint32 PreferredNode //IN + ); + + +/** + Release exclusive use of SPM +*/ +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMRelease( + HSAuint32 PreferredNode //IN + ); + +/** + Set up the destination user mode buffer for stream performance + counter data. +*/ + +HSAKMT_STATUS +HSAKMTAPI +hsaKmtSPMSetDestBuffer( + HSAuint32 PreferredNode, //IN + HSAuint32 SizeInBytes, //IN + HSAuint32 * timeout, //IN/OUT + HSAuint32 * SizeCopied, //OUT + void *DestMemoryAddress, //IN + bool *isSPMDataLoss //OUT + ); + #ifdef __cplusplus } //extern "C" #endif diff --git a/projects/rocr-runtime/include/linux/kfd_ioctl.h b/projects/rocr-runtime/include/linux/kfd_ioctl.h index 6a7dd1f44a..62a84e4e7e 100644 --- a/projects/rocr-runtime/include/linux/kfd_ioctl.h +++ b/projects/rocr-runtime/include/linux/kfd_ioctl.h @@ -574,6 +574,99 @@ struct kfd_ioctl_import_dmabuf_args { __u32 dmabuf_fd; /* to KFD */ }; +/* + * KFD SMI(System Management Interface) events + */ +enum kfd_smi_event { + KFD_SMI_EVENT_NONE = 0, /* not used */ + KFD_SMI_EVENT_VMFAULT = 1, /* event start counting at 1 */ + KFD_SMI_EVENT_THERMAL_THROTTLE = 2, + KFD_SMI_EVENT_GPU_PRE_RESET = 3, + KFD_SMI_EVENT_GPU_POST_RESET = 4, +}; + +#define KFD_SMI_EVENT_MASK_FROM_INDEX(i) (1ULL << ((i) - 1)) + +struct kfd_ioctl_smi_events_args { + __u32 gpuid; /* to KFD */ + __u32 anon_fd; /* from KFD */ +}; + +/** + * 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[in]: specifies the operation to perform + * @gpu_id[in]: GPU ID of the GPU to profile + * @dst_buf[in]: used for the address of the destination buffer + * in @KFD_IOCTL_SPM_SET_DEST_BUFFER + * @buf_size[in]: size of the destination buffer + * @timeout[in/out]: [in]: timeout in milliseconds, [out]: amount of time left + * `in the timeout window + * @bytes_copied[out]: amount of data that was copied to the previous dest_buf + * @has_data_loss: boolean indicating whether data was lost + * (e.g. due to a ring-buffer overflow) + * + * This ioctl performs different functions depending on the @op parameter. + * + * KFD_IOCTL_SPM_OP_ACQUIRE + * ------------------------ + * + * Acquires exclusive access of SPM on the specified @gpu_id for the calling process. + * This must be called before using KFD_IOCTL_SPM_OP_SET_DEST_BUF. + * + * KFD_IOCTL_SPM_OP_RELEASE + * ------------------------ + * + * Releases exclusive access of SPM on the specified @gpu_id for the calling process, + * which allows another process to acquire it in the future. + * + * KFD_IOCTL_SPM_OP_SET_DEST_BUF + * ----------------------------- + * + * If @dst_buf is NULL, the destination buffer address is unset and copying of counters + * is stopped. + * + * If @dst_buf is not NULL, it specifies the pointer to a new destination buffer. + * @buf_size specifies the size of the buffer. + * + * If @timeout is non-0, the call will wait for up to @timeout ms for the previous + * buffer to be filled. If previous buffer to be filled before timeout, the @timeout + * will be updated value with the time remaining. If the timeout is exceeded, the function + * copies any partial data available into the previous user buffer and returns success. + * The amount of valid data in the previous user buffer is indicated by @bytes_copied. + * + * If @timeout is 0, the function immediately replaces the previous destination buffer + * without waiting for the previous buffer to be filled. That means the previous buffer + * may only be partially filled, and @bytes_copied will indicate how much data has been + * copied to it. + * + * If data was lost, e.g. due to a ring buffer overflow, @has_data_loss will be non-0. + * + * Returns negative error code on failure, 0 on success. + */ +struct kfd_ioctl_spm_args { + __u64 dest_buf; + __u32 buf_size; + __u32 op; + __u32 timeout; + __u32 gpu_id; + __u32 bytes_copied; + __u32 has_data_loss; +}; + /* Register offset inside the remapped mmio page */ enum kfd_mmio_remap { @@ -741,7 +834,12 @@ struct kfd_ioctl_cross_memory_copy_args { #define AMDKFD_IOC_CROSS_MEMORY_COPY \ AMDKFD_IOWR(0x83, struct kfd_ioctl_cross_memory_copy_args) +#define AMDKFD_IOC_RLC_SPM \ + AMDKFD_IOWR(0x84, struct kfd_ioctl_spm_args) + + + #define AMDKFD_COMMAND_START_2 0x80 -#define AMDKFD_COMMAND_END_2 0x84 +#define AMDKFD_COMMAND_END_2 0x85 #endif diff --git a/projects/rocr-runtime/src/libhsakmt.ver b/projects/rocr-runtime/src/libhsakmt.ver index d47f68d2d0..97e2cf6beb 100644 --- a/projects/rocr-runtime/src/libhsakmt.ver +++ b/projects/rocr-runtime/src/libhsakmt.ver @@ -71,6 +71,9 @@ hsaKmtGetKernelDebugTrapVersionInfo; hsaKmtGetThunkDebugTrapVersionInfo; hsaKmtSetAddressWatch; hsaKmtClearAddressWatch; +hsaKmtSPMAcquire; +hsaKmtSPMRelease; +hsaKmtSPMSetDestBuffer; local: *; }; diff --git a/projects/rocr-runtime/src/spm.c b/projects/rocr-runtime/src/spm.c new file mode 100644 index 0000000000..c4eb33e5b1 --- /dev/null +++ b/projects/rocr-runtime/src/spm.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2020 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; + + 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.op = KFD_IOCTL_SPM_OP_ACQUIRE; + args.gpu_id = gpu_id; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + return ret; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtSPMSetDestBuffer(HSAuint32 PreferredNode, + HSAuint32 SizeInBytes, + HSAuint32 * timeout, + HSAuint32 * SizeCopied, + void *DestMemoryAddress, + bool *isSPMDataLoss) +{ + int ret; + struct kfd_ioctl_spm_args args = {0}; + uint32_t gpu_id; + + ret = HSAKMT_STATUS_SUCCESS; + + ret = validate_nodeid(PreferredNode, &gpu_id); + + args.timeout = *timeout; + args.dest_buf = (uint64_t)DestMemoryAddress; + args.buf_size = SizeInBytes; + args.op = KFD_IOCTL_SPM_OP_SET_DEST_BUF; + args.gpu_id = gpu_id; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + *SizeCopied = args.bytes_copied; + *isSPMDataLoss = args.has_data_loss; + *timeout = args.timeout; + + return ret; +} + +HSAKMT_STATUS HSAKMTAPI hsaKmtSPMRelease(HSAuint32 PreferredNode) +{ + int ret = HSAKMT_STATUS_SUCCESS; + struct kfd_ioctl_spm_args args = {0}; + uint32_t gpu_id; + + ret = validate_nodeid(PreferredNode, &gpu_id); + if (ret != HSAKMT_STATUS_SUCCESS) { + pr_err("[%s] invalid node ID: %d\n", __func__, PreferredNode); + return ret; + } + + args.op = KFD_IOCTL_SPM_OP_RELEASE; + args.gpu_id = gpu_id; + + ret = kmtIoctl(kfd_fd, AMDKFD_IOC_RLC_SPM, &args); + + return ret; +} + +