/* * 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 hsaKmtDbgRegister( HSAuint32 NodeId //IN ) { HSAKMT_STATUS result; uint32_t gpu_id; struct kfd_ioctl_dbg_register_args args; long err; CHECK_KFD_OPEN(); result = validate_nodeid(NodeId, &gpu_id); if (result != HSAKMT_STATUS_SUCCESS) return result; memset(&args, 0, sizeof(args)); args.gpu_id = gpu_id; err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_REGISTER, &args); if (err == 0) result = HSAKMT_STATUS_SUCCESS; else result = HSAKMT_STATUS_ERROR; return (result); } HSAKMT_STATUS HSAKMTAPI hsaKmtDbgUnregister( HSAuint32 NodeId //IN ) { HSAKMT_STATUS result; uint32_t gpu_id; struct kfd_ioctl_dbg_unregister_args args; long err; CHECK_KFD_OPEN(); result = validate_nodeid(NodeId, &gpu_id); if (result != HSAKMT_STATUS_SUCCESS) return result; memset(&args, 0, sizeof(args)); args.gpu_id = gpu_id; err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_UNREGISTER, &args); if (err == 0) result = HSAKMT_STATUS_SUCCESS; else result = HSAKMT_STATUS_ERROR; return (result); } HSAKMT_STATUS HSAKMTAPI hsaKmtDbgWavefrontControl( HSAuint32 NodeId, //IN HSA_DBG_WAVEOP Operand, //IN HSA_DBG_WAVEMODE Mode, //IN HSAuint32 TrapId, //IN HsaDbgWaveMessage* DbgWaveMsgRing //IN (? - see thunk API doc!) ) { HSAKMT_STATUS result; uint32_t gpu_id; uint32_t buff_size; unsigned char *run_ptr; long err; struct kfd_ioctl_dbg_wave_control_args *args; CHECK_KFD_OPEN(); result = validate_nodeid(NodeId, &gpu_id); if (result != HSAKMT_STATUS_SUCCESS) return result; /* Determine Size of the ioctl buffer */ buff_size = sizeof(Operand) + sizeof(Mode) + sizeof(TrapId) + sizeof(DbgWaveMsgRing->DbgWaveMsg) + sizeof(DbgWaveMsgRing->MemoryVA) + sizeof(*args); args = (struct kfd_ioctl_dbg_wave_control_args*) malloc(buff_size); if (args == NULL) return HSAKMT_STATUS_ERROR; memset(args, 0, buff_size); args->gpu_id = gpu_id; args->buf_size_in_bytes = buff_size; /* increment pointer to the start of the non fixed part */ run_ptr = (unsigned char*)args + sizeof(*args); /* save variable content pointer for kfd */ args->content_ptr = (uint64_t) run_ptr; /* insert items, and increment pointer accordingly */ *((HSA_DBG_WAVEOP*)run_ptr) = Operand; run_ptr += sizeof(Operand); *((HSA_DBG_WAVEMODE*)run_ptr) = Mode; run_ptr += sizeof(Mode); *((HSAuint32*)run_ptr) = TrapId; run_ptr += sizeof(TrapId); *((HsaDbgWaveMessageAMD*)run_ptr) = DbgWaveMsgRing->DbgWaveMsg; run_ptr += sizeof(DbgWaveMsgRing->DbgWaveMsg); *((void**)run_ptr) = DbgWaveMsgRing->MemoryVA; run_ptr += sizeof(DbgWaveMsgRing->MemoryVA); /* send to kernel */ err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_WAVE_CONTROL, args); free (args); if (err == 0) return HSAKMT_STATUS_SUCCESS; else return HSAKMT_STATUS_ERROR; } HSAKMT_STATUS HSAKMTAPI hsaKmtDbgAddressWatch( HSAuint32 NodeId, //IN HSAuint32 NumWatchPoints, //IN HSA_DBG_WATCH_MODE WatchMode[], //IN void* WatchAddress[], //IN HSAuint64 WatchMask[], //IN, optional HsaEvent* WatchEvent[] //IN, optional ) { HSAKMT_STATUS result; uint32_t gpu_id; struct kfd_ioctl_dbg_address_watch_args *args; uint32_t buff_size; uint32_t watch_mask_items, watch_event_items; HSAuint32 i; unsigned char *run_ptr; long err; /* * Determine the size of the watch mask and event buffers * the value is NULL if and only if no vector data should be attached */ watch_mask_items = WatchMask[0] > 0 ? NumWatchPoints : 1; watch_event_items = WatchEvent != NULL ? NumWatchPoints : 0; CHECK_KFD_OPEN(); result = validate_nodeid(NodeId, &gpu_id); if (result != HSAKMT_STATUS_SUCCESS) return result; if (NumWatchPoints > MAX_ALLOWED_NUM_POINTS) return HSAKMT_STATUS_INVALID_PARAMETER; /* * Size and structure of the ioctl buffer is dynamic in this case * Here we calculate the buff size. */ buff_size = sizeof(NumWatchPoints) + (sizeof(WatchMode[0]) + sizeof(WatchAddress[0])) * NumWatchPoints + watch_mask_items * sizeof(HSAuint64) + watch_event_items * sizeof(HsaEvent*)+ sizeof(*args); args = (struct kfd_ioctl_dbg_address_watch_args*) malloc(buff_size); if (args == NULL) return HSAKMT_STATUS_ERROR; memset(args, 0, buff_size); args->gpu_id = gpu_id; args->buf_size_in_bytes = buff_size; /* increment pointer to the start of the non fixed part */ run_ptr = (unsigned char*)args + sizeof(*args); /* save variable content pointer for kfd */ args->content_ptr = (uint64_t) run_ptr; /* insert items, and increment pointer accordingly */ *((HSAuint32*)run_ptr) = NumWatchPoints; run_ptr += sizeof(NumWatchPoints); for (i = 0 ; i < NumWatchPoints ; i++) { *((HSA_DBG_WATCH_MODE*)run_ptr) = WatchMode[i]; run_ptr += sizeof(WatchMode[i]); } for (i = 0 ; i < NumWatchPoints ; i++) { *((void**)run_ptr) = WatchAddress[i]; run_ptr += sizeof(WatchAddress[i]); } for (i = 0 ; i < watch_mask_items ; i++) { *((HSAuint64*)run_ptr) = WatchMask[i]; run_ptr += sizeof(WatchMask[i]); } for (i = 0 ; i < watch_event_items ; i++) { *((HsaEvent**)run_ptr) = WatchEvent[i]; run_ptr += sizeof(WatchEvent[i]); } /* send to kernel */ err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_ADDRESS_WATCH, args); free (args); if (err != 0) return HSAKMT_STATUS_ERROR; return HSAKMT_STATUS_SUCCESS; }