blob: f2fd437e7e83dea804115f619d26296f5df64cf2 [file] [log] [blame]
/*
* 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(&gtSystemInfo, sizeof(gtSystemInfo));
eStatus = HWInfo_GetGfxInfo(pOsDriverContext->fd, pOsDriverContext->bufmgr, &platformInfo, &skuTable, &waTable, &gtSystemInfo);
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), &gtSystemInfo, 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);
}
}