diff --git a/projects/rocr-runtime/CMakeLists.txt b/projects/rocr-runtime/CMakeLists.txt index 26c8528016..bd6dbbfa82 100644 --- a/projects/rocr-runtime/CMakeLists.txt +++ b/projects/rocr-runtime/CMakeLists.txt @@ -130,7 +130,8 @@ set ( HSAKMT_SRC "src/debug.c" "src/topology.c" "src/rbtree.c" "src/spm.c" - "src/version.c") + "src/version.c" + "src/svm.c") ## Declare the library target name add_library ( ${HSAKMT_TARGET} "") diff --git a/projects/rocr-runtime/src/libhsakmt.h b/projects/rocr-runtime/src/libhsakmt.h index 9c7047caa2..6be639261b 100644 --- a/projects/rocr-runtime/src/libhsakmt.h +++ b/projects/rocr-runtime/src/libhsakmt.h @@ -26,6 +26,7 @@ #ifndef LIBHSAKMT_H_INCLUDED #define LIBHSAKMT_H_INCLUDED +#include "linux/kfd_ioctl.h" #include "hsakmt.h" #include "pci_ids.h" #include diff --git a/projects/rocr-runtime/src/libhsakmt.ver b/projects/rocr-runtime/src/libhsakmt.ver index 4383695e98..3992e6535a 100644 --- a/projects/rocr-runtime/src/libhsakmt.ver +++ b/projects/rocr-runtime/src/libhsakmt.ver @@ -75,6 +75,8 @@ hsaKmtClearAddressWatch; hsaKmtSPMAcquire; hsaKmtSPMRelease; hsaKmtSPMSetDestBuffer; +hsaKmtSVMSetAttr; +hsaKmtSVMGetAttr; local: *; }; diff --git a/projects/rocr-runtime/src/svm.c b/projects/rocr-runtime/src/svm.c new file mode 100644 index 0000000000..8f20fc0378 --- /dev/null +++ b/projects/rocr-runtime/src/svm.c @@ -0,0 +1,187 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Helper functions for calling KFD SVM ioctl */ + +HSAKMT_STATUS HSAKMTAPI +hsaKmtSVMSetAttr(void *start_addr, HSAuint64 size, unsigned int nattr, + HSA_SVM_ATTRIBUTE *attrs) +{ + struct kfd_ioctl_svm_args *args; + HSAuint64 s_attr; + HSAKMT_STATUS r; + HSAuint32 i; + + CHECK_KFD_OPEN(); + CHECK_KFD_MINOR_VERSION(5); + + pr_debug("%s: address 0x%p size 0x%lx\n", __func__, start_addr, size); + + if (!start_addr || !size) + return HSAKMT_STATUS_INVALID_PARAMETER; + if ((uint64_t)start_addr & (PAGE_SIZE - 1)) + return HSAKMT_STATUS_INVALID_PARAMETER; + if (size & (PAGE_SIZE - 1)) + return HSAKMT_STATUS_INVALID_PARAMETER; + + s_attr = sizeof(*attrs) * nattr; + args = alloca(sizeof(*args) + s_attr); + + args->start_addr = (uint64_t)start_addr; + args->size = size; + args->op = KFD_IOCTL_SVM_OP_SET_ATTR; + args->nattr = nattr; + memcpy(args->attrs, attrs, s_attr); + + for (i = 0; i < nattr; i++) { + if (attrs[i].type != KFD_IOCTL_SVM_ATTR_PREFERRED_LOC && + attrs[i].type != KFD_IOCTL_SVM_ATTR_PREFETCH_LOC && + attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS && + attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE && + attrs[i].type != KFD_IOCTL_SVM_ATTR_NO_ACCESS) + continue; + + if (attrs[i].type == KFD_IOCTL_SVM_ATTR_PREFERRED_LOC && + attrs[i].value == INVALID_NODEID) { + args->attrs[i].value = KFD_IOCTL_SVM_LOCATION_UNDEFINED; + continue; + } + + r = validate_nodeid(attrs[i].value, &args->attrs[i].value); + if (r != HSAKMT_STATUS_SUCCESS) { + pr_debug("invalid node ID: %d\n", attrs[i].value); + return r; + } else if (!args->attrs[i].value && + (attrs[i].type == KFD_IOCTL_SVM_ATTR_ACCESS || + attrs[i].type == KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE || + attrs[i].type == KFD_IOCTL_SVM_ATTR_NO_ACCESS)) { + pr_debug("CPU node invalid for access attribute\n"); + return HSAKMT_STATUS_INVALID_NODE_UNIT; + } + } + + /* Driver does one copy_from_user, with extra attrs size */ + r = kmtIoctl(kfd_fd, AMDKFD_IOC_SVM + (s_attr << _IOC_SIZESHIFT), args); + if (r) { + pr_debug("op set range attrs failed %s\n", strerror(errno)); + return HSAKMT_STATUS_ERROR; + } + + return HSAKMT_STATUS_SUCCESS; +} + +HSAKMT_STATUS HSAKMTAPI +hsaKmtSVMGetAttr(void *start_addr, HSAuint64 size, unsigned int nattr, + HSA_SVM_ATTRIBUTE *attrs) +{ + struct kfd_ioctl_svm_args *args; + HSAuint64 s_attr; + HSAKMT_STATUS r; + HSAuint32 i; + + CHECK_KFD_OPEN(); + CHECK_KFD_MINOR_VERSION(5); + + pr_debug("%s: address 0x%p size 0x%lx\n", __func__, start_addr, size); + + if (!start_addr || !size) + return HSAKMT_STATUS_INVALID_PARAMETER; + if ((uint64_t)start_addr & (PAGE_SIZE - 1)) + return HSAKMT_STATUS_INVALID_PARAMETER; + if (size & (PAGE_SIZE - 1)) + return HSAKMT_STATUS_INVALID_PARAMETER; + + s_attr = sizeof(*attrs) * nattr; + args = alloca(sizeof(*args) + s_attr); + + args->start_addr = (uint64_t)start_addr; + args->size = size; + args->op = KFD_IOCTL_SVM_OP_GET_ATTR; + args->nattr = nattr; + memcpy(args->attrs, attrs, s_attr); + + for (i = 0; i < nattr; i++) { + if (attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS && + attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE && + attrs[i].type != KFD_IOCTL_SVM_ATTR_NO_ACCESS) + continue; + + r = validate_nodeid(attrs[i].value, &args->attrs[i].value); + if (r != HSAKMT_STATUS_SUCCESS) { + pr_debug("invalid node ID: %d\n", attrs[i].value); + return r; + } else if (!args->attrs[i].value) { + pr_debug("CPU node invalid for access attribute\n"); + return HSAKMT_STATUS_INVALID_NODE_UNIT; + } + } + + /* Driver does one copy_from_user, with extra attrs size */ + r = kmtIoctl(kfd_fd, AMDKFD_IOC_SVM + (s_attr << _IOC_SIZESHIFT), args); + if (r) { + pr_debug("op get range attrs failed %s\n", strerror(errno)); + return HSAKMT_STATUS_ERROR; + } + + memcpy(attrs, args->attrs, s_attr); + + for (i = 0; i < nattr; i++) { + if (attrs[i].type != KFD_IOCTL_SVM_ATTR_PREFERRED_LOC && + attrs[i].type != KFD_IOCTL_SVM_ATTR_PREFETCH_LOC && + attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS && + attrs[i].type != KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE && + attrs[i].type != KFD_IOCTL_SVM_ATTR_NO_ACCESS) + continue; + + switch (attrs[i].value) { + case KFD_IOCTL_SVM_LOCATION_SYSMEM: + attrs[i].value = 0; + break; + case KFD_IOCTL_SVM_LOCATION_UNDEFINED: + attrs[i].value = INVALID_NODEID; + break; + default: + r = gpuid_to_nodeid(attrs[i].value, &attrs[i].value); + if (r != HSAKMT_STATUS_SUCCESS) { + pr_debug("invalid GPU ID: %d\n", + attrs[i].value); + return r; + } + } + } + + return HSAKMT_STATUS_SUCCESS; +}