| /* |
| * Copyright (c) 2017-2018, Intel Corporation |
| * |
| * 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 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. |
| */ |
| //! |
| //! \file mos_context_specific.cpp |
| //! \brief Container for Linux/Android specific parameters shared across different GPU contexts of the same device instance |
| //! |
| |
| #include "mos_os.h" |
| #include "mos_util_debug.h" |
| #include "mos_resource_defs.h" |
| #include <unistd.h> |
| #include <dlfcn.h> |
| #include "hwinfo_linux.h" |
| #include <stdlib.h> |
| |
| #ifndef ANDROID |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| #include <sys/sem.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #endif |
| |
| #if MOS_MEDIASOLO_SUPPORTED |
| #include "mos_os_solo.h" |
| #endif // MOS_MEDIASOLO_SUPPORTED |
| #include "mos_solo_generic.h" |
| |
| #include "mos_context_specific.h" |
| #include "mos_gpucontextmgr.h" |
| #include "mos_cmdbufmgr.h" |
| |
| OsContextSpecific::OsContextSpecific() |
| { |
| for (int i = 0; i < MOS_GPU_CONTEXT_MAX; i++) |
| { |
| m_GpuContextHandle[i] = MOS_GPU_CONTEXT_INVALID_HANDLE; |
| } |
| |
| MOS_OS_FUNCTION_ENTER; |
| } |
| |
| OsContextSpecific::~OsContextSpecific() |
| { |
| MOS_OS_FUNCTION_ENTER; |
| } |
| |
| #ifndef ANDROID |
| MOS_STATUS OsContextSpecific::LockSemaphore(int32_t semid) |
| { |
| struct sembuf op[2]; |
| op[0].sem_num = 0; // wait for [0] to be 0 |
| op[0].sem_op = 0; |
| op[0].sem_flg = 0; |
| op[1].sem_num = 0; |
| op[1].sem_op = 1; // increment |
| op[1].sem_flg = SEM_UNDO; |
| |
| if (semid < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (semop(semid, op, 2) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS OsContextSpecific::UnLockSemaphore(int32_t semid) |
| { |
| struct sembuf op; |
| op.sem_num = 0; |
| op.sem_op = -1; // decrement back to 0 |
| op.sem_flg = SEM_UNDO; |
| |
| if (semid < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (semop(semid, &op, 1) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| int16_t OsContextSpecific::ShmAttachedNumber(unsigned int shmid) |
| { |
| struct shmid_ds buf; |
| MOS_ZeroMemory(&buf, sizeof(buf)); |
| |
| if (shmctl(shmid, IPC_STAT, &buf) < 0) |
| { |
| return -1; |
| } |
| |
| return buf.shm_nattch; |
| } |
| |
| MOS_STATUS OsContextSpecific::DestroySemaphore(unsigned int semid) |
| { |
| int32_t nwait = 0; |
| |
| if (semid < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| nwait = semctl(semid, 0, GETZCNT, 0); |
| |
| if (nwait > 0) |
| { |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| if (semctl(semid, 0, IPC_RMID, nullptr) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS OsContextSpecific::ConnectCreateShm(long key, uint32_t size, int32_t *pShmid, void* *ppShm) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| MOS_OS_CHK_NULL_RETURN(pShmid); |
| MOS_OS_CHK_NULL_RETURN(ppShm); |
| |
| struct shmid_ds buf; |
| int32_t shmid = 0; |
| key_t key_value = (key_t)key; |
| void *shmptr = nullptr; |
| MOS_ZeroMemory(&buf, sizeof(buf)); |
| |
| shmid = shmget(key_value, size, IPC_CREAT | 0666); |
| if (shmid < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| shmptr = shmat(shmid, 0, 0); |
| if (shmptr == MOS_LINUX_SHM_INVALID) |
| { |
| DetachDestroyShm(shmid, shmptr); |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (shmctl(shmid, IPC_STAT, &buf) < 0) |
| { |
| // can't get any status info |
| DetachDestroyShm(shmid, shmptr); |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| *ppShm = shmptr; |
| *pShmid = shmid; |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS OsContextSpecific::DetachDestroyShm(int32_t shmid, void *pShm) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| MOS_OS_CHK_NULL_RETURN(pShm); |
| |
| struct shmid_ds buf; |
| MOS_ZeroMemory(&buf, sizeof(buf)); |
| |
| if (shmid < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (pShm != MOS_LINUX_SHM_INVALID && shmdt(pShm) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (shmctl(shmid, IPC_STAT, &buf) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| if (buf.shm_nattch == 0) |
| { |
| if (shmctl(shmid, IPC_RMID, nullptr) < 0) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| } |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS OsContextSpecific::ConnectCreateSemaphore(long key, int32_t *pSemid) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| MOS_OS_CHK_NULL_RETURN(pSemid); |
| |
| int32_t semid = 0; |
| struct sembuf sop; |
| struct semid_ds buf; |
| key_t key_value = (key_t)key; |
| int32_t val = 0; |
| |
| MOS_ZeroMemory(&sop, sizeof(sop)); |
| MOS_ZeroMemory(&buf, sizeof(buf)); |
| |
| semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666); |
| |
| if (semid != MOS_LINUX_IPC_INVALID_ID) |
| { |
| // initialize it to 0 |
| if (semctl(semid, 0, SETVAL, val) == -1) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| // Perform a "no-op" semaphore operation - changes sem_otime |
| // so other processes can see we've initialized the set. |
| sop.sem_num = 0; |
| sop.sem_op = 0; //Wait for value to equal 0 |
| sop.sem_flg = 0; |
| if (semop(semid, &sop, 1) == -1) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| } |
| else |
| { |
| // errno EEXIST |
| semid = semget(key, 1, 0666); |
| if (semid == MOS_LINUX_IPC_INVALID_ID) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| } |
| |
| *pSemid = semid; |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS OsContextSpecific::CreateIPC() |
| { |
| MOS_STATUS eStatus; |
| |
| m_semId = MOS_LINUX_IPC_INVALID_ID; |
| m_shmId = MOS_LINUX_IPC_INVALID_ID; |
| m_shm = MOS_LINUX_SHM_INVALID; |
| |
| struct semid_ds buf; |
| MOS_ZeroMemory(&buf, sizeof(buf)); |
| //wait and retry till to get a valid semphore |
| for(int i = 0; i < MOS_LINUX_SEM_MAX_TRIES; i++) |
| { |
| ConnectCreateSemaphore(m_dualVdboxKey, &m_semId); |
| |
| if (m_semId == MOS_LINUX_IPC_INVALID_ID) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| //check wether the semid is initialized or not |
| if (semctl(m_semId, 0, IPC_STAT, &buf) == -1) |
| { |
| return MOS_STATUS_UNKNOWN; |
| } |
| if (buf.sem_otime != 0) |
| { |
| break; |
| } |
| |
| MOS_Sleep(1); //wait and retry |
| } |
| |
| LockSemaphore(m_semId); |
| eStatus = ConnectCreateShm(m_dualVdboxKey, sizeof(VDBOX_WORKLOAD), &(m_shmId), &(m_shm)); |
| UnLockSemaphore(m_semId); |
| MOS_CHK_STATUS_SAFE(eStatus); |
| |
| finish: |
| return eStatus; |
| } |
| |
| void OsContextSpecific::DestroyIPC() |
| { |
| if (MOS_LINUX_IPC_INVALID_ID != m_semId) |
| { |
| int16_t iAttachedNum = 0; |
| |
| if (MOS_LINUX_IPC_INVALID_ID != m_shmId) |
| { |
| LockSemaphore(m_semId); |
| iAttachedNum = ShmAttachedNumber(m_shmId); |
| |
| DetachDestroyShm(m_shmId, m_shm); |
| m_shmId = MOS_LINUX_IPC_INVALID_ID; |
| m_shm = MOS_LINUX_SHM_INVALID; |
| |
| if (iAttachedNum) |
| { |
| --iAttachedNum; |
| } |
| UnLockSemaphore(m_semId); |
| } |
| } |
| } |
| |
| MOS_STATUS OsContextSpecific::CreateSSEUIPC() |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| |
| m_sseuSemId = MOS_LINUX_IPC_INVALID_ID; |
| m_sseuShmId = MOS_LINUX_IPC_INVALID_ID; |
| m_sseuShm = MOS_LINUX_SHM_INVALID; |
| |
| return eStatus; |
| } |
| |
| void OsContextSpecific::DestroySSEUIPC() |
| { |
| if (MOS_LINUX_IPC_INVALID_ID != m_sseuSemId) |
| { |
| short iAttachedNum = 0; |
| |
| if (MOS_LINUX_IPC_INVALID_ID != m_sseuShmId) |
| { |
| LockSemaphore(m_sseuSemId); |
| iAttachedNum = ShmAttachedNumber(m_sseuShmId); |
| |
| DetachDestroyShm(m_sseuShmId, m_sseuShm); |
| m_sseuShmId = MOS_LINUX_IPC_INVALID_ID; |
| m_sseuShm = MOS_LINUX_SHM_INVALID; |
| |
| if (iAttachedNum) |
| { |
| --iAttachedNum; |
| } |
| UnLockSemaphore(m_sseuSemId); |
| } |
| } |
| } |
| |
| void OsContextSpecific::SetSliceCount(uint32_t *pSliceCount) |
| { |
| if (pSliceCount == nullptr) |
| MOS_OS_ASSERTMESSAGE("pSliceCount is NULL."); |
| } |
| |
| #endif //#ifndef ANDROID |
| |
| void OsContextSpecific::GetGpuPriority(int32_t* pPriority) |
| { |
| uint64_t priority = 0; |
| mos_get_context_param(m_intelContext, 0, I915_CONTEXT_PARAM_PRIORITY, &priority); |
| *pPriority = (int32_t)priority; |
| } |
| |
| void OsContextSpecific::SetGpuPriority(int32_t priority) |
| { |
| int ret = 0; |
| ret = mos_set_context_param(m_intelContext, 0, I915_CONTEXT_PARAM_PRIORITY,(uint64_t)priority); |
| if (ret != 0) |
| { |
| MOS_OS_NORMALMESSAGE("Warning: failed to set the gpu priority, errno is %d", ret); |
| } |
| } |
| |
| MOS_STATUS OsContextSpecific::Init(PMOS_CONTEXT pOsDriverContext) |
| { |
| uint32_t iDeviceId = 0; |
| MOS_STATUS eStatus; |
| uint32_t i = 0; |
| |
| MOS_OS_FUNCTION_ENTER; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| if (GetOsContextValid() == false) |
| { |
| if( nullptr == pOsDriverContext || |
| nullptr == pOsDriverContext->bufmgr || |
| 0 >= pOsDriverContext->fd ) |
| { |
| MOS_OS_ASSERT(false); |
| return MOS_STATUS_INVALID_HANDLE; |
| } |
| m_apoMosEnabled = pOsDriverContext->m_apoMosEnabled; |
| m_bufmgr = pOsDriverContext->bufmgr; |
| m_gpuContextMgr = static_cast<GpuContextMgr *>(pOsDriverContext->m_gpuContextMgr); |
| m_cmdBufMgr = static_cast<CmdBufMgr *>(pOsDriverContext->m_cmdBufMgr); |
| m_fd = pOsDriverContext->fd; |
| MOS_SecureMemcpy(&m_perfData, sizeof(PERF_DATA), pOsDriverContext->pPerfData, sizeof(PERF_DATA)); |
| mos_bufmgr_gem_enable_reuse(pOsDriverContext->bufmgr); |
| m_pGmmClientContext = pOsDriverContext->pGmmClientContext; |
| m_auxTableMgr = pOsDriverContext->m_auxTableMgr; |
| |
| // DDI layer can pass over the DeviceID. |
| iDeviceId = pOsDriverContext->iDeviceId; |
| if (0 == iDeviceId) |
| { |
| PLATFORM platformInfo; |
| MEDIA_FEATURE_TABLE skuTable; |
| MEDIA_WA_TABLE waTable; |
| MEDIA_SYSTEM_INFO gtSystemInfo; |
| |
| MOS_ZeroMemory(&platformInfo, sizeof(platformInfo)); |
| MOS_ZeroMemory(&skuTable, sizeof(skuTable)); |
| MOS_ZeroMemory(&waTable, sizeof(waTable)); |
| MOS_ZeroMemory(>SystemInfo, sizeof(gtSystemInfo)); |
| eStatus = HWInfo_GetGfxInfo(pOsDriverContext->fd, pOsDriverContext->bufmgr, &platformInfo, &skuTable, &waTable, >SystemInfo); |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| MOS_OS_ASSERTMESSAGE("Fatal error - unsuccesfull Sku/Wa/GtSystemInfo initialization"); |
| return eStatus; |
| } |
| |
| MOS_SecureMemcpy(&m_platformInfo, sizeof(PLATFORM), &platformInfo, sizeof(PLATFORM)); |
| MOS_SecureMemcpy(&m_gtSystemInfo, sizeof(MEDIA_SYSTEM_INFO), >SystemInfo, sizeof(MEDIA_SYSTEM_INFO)); |
| |
| pOsDriverContext->iDeviceId = platformInfo.usDeviceID; |
| m_skuTable = skuTable; |
| m_waTable = waTable; |
| |
| pOsDriverContext->SkuTable = skuTable; |
| pOsDriverContext->WaTable = waTable; |
| pOsDriverContext->gtSystemInfo = gtSystemInfo; |
| pOsDriverContext->platform = platformInfo; |
| |
| MOS_OS_NORMALMESSAGE("DeviceID was created DeviceID = %d, platform product %d", iDeviceId, platformInfo.eProductFamily); |
| } |
| else |
| { |
| // pOsDriverContext's parameters were passed by CmCreateDevice. |
| // Get SkuTable/WaTable/systemInfo/platform from OSDriver directly. |
| MOS_SecureMemcpy(&m_platformInfo, sizeof(PLATFORM), &(pOsDriverContext->platform), sizeof(PLATFORM)); |
| MOS_SecureMemcpy(&m_gtSystemInfo, sizeof(MEDIA_SYSTEM_INFO), &(pOsDriverContext->gtSystemInfo), sizeof(MEDIA_SYSTEM_INFO)); |
| |
| m_skuTable = pOsDriverContext->SkuTable; |
| m_waTable = pOsDriverContext->WaTable; |
| } |
| |
| m_use64BitRelocs = true; |
| m_useSwSwizzling = pOsDriverContext->bSimIsActive || MEDIA_IS_SKU(&m_skuTable, FtrUseSwSwizzling); |
| m_tileYFlag = MEDIA_IS_SKU(&m_skuTable, FtrTileY); |
| |
| MOS_TraceEventExt(EVENT_GPU_CONTEXT_CREATE, EVENT_TYPE_START, |
| &eStatus, sizeof(eStatus), nullptr, 0); |
| if (!Mos_Solo_IsEnabled(nullptr) && MEDIA_IS_SKU(&m_skuTable,FtrContextBasedScheduling)) |
| { |
| m_intelContext = mos_gem_context_create_ext(pOsDriverContext->bufmgr,0); |
| if (m_intelContext) |
| { |
| m_intelContext->vm = mos_gem_vm_create(pOsDriverContext->bufmgr); |
| if (m_intelContext->vm == nullptr) |
| { |
| MOS_OS_ASSERTMESSAGE("Failed to create vm.\n"); |
| return MOS_STATUS_UNKNOWN; |
| } |
| } |
| } |
| else //use legacy context create ioctl for pre-gen11 platforms |
| { |
| m_intelContext = mos_gem_context_create(pOsDriverContext->bufmgr); |
| if (m_intelContext) |
| { |
| m_intelContext->vm = nullptr; |
| } |
| } |
| MOS_TraceEventExt(EVENT_GPU_CONTEXT_CREATE, EVENT_TYPE_END, |
| &m_intelContext, sizeof(void *), |
| &eStatus, sizeof(eStatus)); |
| |
| if (m_intelContext == nullptr) |
| { |
| MOS_OS_ASSERTMESSAGE("Failed to create drm intel context"); |
| return MOS_STATUS_UNKNOWN; |
| } |
| |
| m_isAtomSOC = IS_ATOMSOC(iDeviceId); |
| |
| #ifndef ANDROID |
| |
| if ((m_gtSystemInfo.VDBoxInfo.IsValid) && (m_gtSystemInfo.VDBoxInfo.NumberOfVDBoxEnabled > 1)) |
| { |
| m_kmdHasVCS2 = true; |
| } |
| else |
| { |
| m_kmdHasVCS2 = false; |
| } |
| |
| if (m_kmdHasVCS2) |
| { |
| eStatus = CreateIPC(); |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| MOS_OS_ASSERTMESSAGE("Fatal error - create IPC failed"); |
| return eStatus; |
| } |
| } |
| |
| eStatus = CreateSSEUIPC(); |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| MOS_OS_ASSERTMESSAGE("Fatal error - Failed to create shared memory for SSEU configuration."); |
| return eStatus; |
| } |
| #endif |
| |
| m_transcryptedKernels = nullptr; |
| m_transcryptedKernelsSize = 0; |
| |
| // For Media Memory compression |
| m_mediaMemDecompState = pOsDriverContext->ppMediaMemDecompState; |
| m_memoryDecompress = pOsDriverContext->pfnMemoryDecompress; |
| m_mediaMemCopy = pOsDriverContext->pfnMediaMemoryCopy; |
| m_mediaMemCopy2D = pOsDriverContext->pfnMediaMemoryCopy2D; |
| m_mosContext = pOsDriverContext; |
| |
| m_noParsingAssistanceInKmd = true; |
| m_numNalUnitBytesIncluded = MOS_NAL_UNIT_LENGTH - MOS_NAL_UNIT_STARTCODE_LENGTH; |
| |
| // Init reset count for the context |
| uint32_t dwResetCount = 0; |
| mos_get_reset_stats(m_intelContext, &dwResetCount, nullptr, nullptr); |
| m_gpuResetCount = dwResetCount; |
| m_gpuActiveBatch = 0; |
| m_gpuPendingBatch = 0; |
| |
| m_usesPatchList = true; |
| m_usesGfxAddress = false; |
| |
| m_inlineCodecStatusUpdate = true; |
| |
| #if MOS_COMMAND_BUFFER_DUMP_SUPPORTED |
| CommandBufferDumpInit(pOsDriverContext); |
| #endif |
| |
| SetOsContextValid(true); |
| } |
| return eStatus; |
| } |
| |
| void OsContextSpecific::Destroy() |
| { |
| MOS_OS_FUNCTION_ENTER; |
| |
| if (GetOsContextValid() == true) |
| { |
| // APO MOS will destory each stream's GPU context at different place |
| if (!m_apoMosEnabled) |
| { |
| for (auto i = 0; i < MOS_GPU_CONTEXT_MAX; i++) |
| { |
| if (m_GpuContextHandle[i] != MOS_GPU_CONTEXT_INVALID_HANDLE) |
| { |
| if (m_gpuContextMgr == nullptr) |
| { |
| MOS_OS_ASSERTMESSAGE("GpuContextMgr is null when destroy GpuContext"); |
| break; |
| } |
| auto gpuContext = m_gpuContextMgr->GetGpuContext(m_GpuContextHandle[i]); |
| if (gpuContext == nullptr) |
| { |
| MOS_OS_ASSERTMESSAGE("cannot find the gpuContext corresponding to the active gpuContextHandle"); |
| continue; |
| } |
| m_gpuContextMgr->DestroyGpuContext(gpuContext); |
| } |
| } |
| } |
| |
| #ifndef ANDROID |
| if (m_kmdHasVCS2) |
| { |
| DestroyIPC(); |
| } |
| DestroySSEUIPC(); |
| #endif |
| m_skuTable.reset(); |
| m_waTable.reset(); |
| MOS_TraceEventExt(EVENT_GPU_CONTEXT_DESTROY, EVENT_TYPE_START, |
| &m_intelContext, sizeof(void *), nullptr, 0); |
| if (m_intelContext && m_intelContext->vm) |
| { |
| mos_gem_vm_destroy(m_intelContext->bufmgr, m_intelContext->vm); |
| } |
| if (m_intelContext) |
| { |
| mos_gem_context_destroy(m_intelContext); |
| } |
| MOS_TraceEventExt(EVENT_GPU_CONTEXT_DESTROY, EVENT_TYPE_END, |
| nullptr, 0, nullptr, 0); |
| SetOsContextValid(false); |
| } |
| } |
| |