/* * Copyright (C) 2019-2023 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/test/common/libult/linux/drm_mock.h" #include "shared/source/execution_environment/execution_environment.h" #include "shared/source/execution_environment/root_device_environment.h" #include "shared/source/helpers/hw_info.h" #include "shared/source/os_interface/linux/i915.h" #include "gtest/gtest.h" #include #include const int DrmMock::mockFd; const uint32_t DrmMockResources::registerResourceReturnHandle = 3; DrmMock::DrmMock(int fd, RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique(fd, ""), rootDeviceEnvironment) { sliceCountChangeSupported = true; if (rootDeviceEnvironment.executionEnvironment.isDebuggingEnabled()) { if (rootDeviceEnvironment.executionEnvironment.getDebuggingMode() == DebuggingMode::Offline) { setPerContextVMRequired(false); } else { setPerContextVMRequired(true); } } setupIoctlHelper(rootDeviceEnvironment.getHardwareInfo()->platform.eProductFamily); if (!isPerContextVMRequired()) { createVirtualMemoryAddressSpace(GfxCoreHelper::getSubDevicesCount(rootDeviceEnvironment.getHardwareInfo())); } storedPreemptionSupport = I915_SCHEDULER_CAP_ENABLED | I915_SCHEDULER_CAP_PRIORITY | I915_SCHEDULER_CAP_PREEMPTION; } int DrmMock::handleRemainingRequests(DrmIoctl request, void *arg) { ioctlCallsCount--; return -1; }; int DrmMock::ioctl(DrmIoctl request, void *arg) { ioctlCallsCount++; ioctlCount.total++; if ((request == DrmIoctl::Getparam) && (arg != nullptr)) { ioctlCount.contextGetParam++; auto gp = static_cast(arg); if (gp->param == I915_PARAM_EU_TOTAL) { if (0 == this->storedRetValForEUVal) { *gp->value = this->storedEUVal; } return this->storedRetValForEUVal; } if (gp->param == I915_PARAM_SUBSLICE_TOTAL) { if (0 == this->storedRetValForSSVal) { *gp->value = this->storedSSVal; } return this->storedRetValForSSVal; } if (gp->param == I915_PARAM_CHIPSET_ID) { if (0 == this->storedRetValForDeviceID) { *gp->value = this->storedDeviceID; } return this->storedRetValForDeviceID; } if (gp->param == I915_PARAM_REVISION) { if (0 == this->storedRetValForDeviceRevID) { *gp->value = this->storedDeviceRevID; } return this->storedRetValForDeviceRevID; } if (gp->param == I915_PARAM_HAS_POOLED_EU) { if (0 == this->storedRetValForPooledEU) { *gp->value = this->storedHasPooledEU; } return this->storedRetValForPooledEU; } if (gp->param == I915_PARAM_MIN_EU_IN_POOL) { if (0 == this->storedRetValForMinEUinPool) { *gp->value = this->storedMinEUinPool; } return this->storedRetValForMinEUinPool; } if (gp->param == I915_PARAM_HAS_SCHEDULER) { *gp->value = this->storedPreemptionSupport; return this->storedRetVal; } if (gp->param == I915_PARAM_HAS_EXEC_SOFTPIN) { *gp->value = this->storedExecSoftPin; return this->storedRetVal; } if (gp->param == I915_PARAM_CS_TIMESTAMP_FREQUENCY) { *gp->value = this->storedCsTimestampFrequency; return this->storedRetVal; } if (gp->param == I915_PARAM_OA_TIMESTAMP_FREQUENCY) { *gp->value = this->storedOaTimestampFrequency; return this->storedRetVal; } } if ((request == DrmIoctl::GemContextCreateExt) && (arg != nullptr)) { ioctlCount.contextCreate++; auto create = static_cast(arg); create->contextId = this->storedDrmContextId; this->receivedContextCreateFlags = create->flags; if (create->extensions == 0) { return this->storedRetVal; } receivedContextCreateSetParam = *reinterpret_cast(create->extensions); if (receivedContextCreateSetParam.base.name == I915_CONTEXT_CREATE_EXT_SETPARAM) { receivedContextParamRequestCount++; receivedContextParamRequest = *reinterpret_cast(&receivedContextCreateSetParam.param); if (receivedContextCreateSetParam.param.param == I915_CONTEXT_PARAM_VM) { this->requestSetVmId = receivedContextParamRequest.value; return this->storedRetVal; } } } if ((request == DrmIoctl::GemVmCreate) && (arg != nullptr)) { ioctlCount.gemVmCreate++; auto gemVmControl = static_cast(arg); receivedGemVmControl = *gemVmControl; gemVmControl->vmId = ++latestCreatedVmId; return storedRetValForVmCreate; } if ((request == DrmIoctl::GemVmDestroy) && (arg != nullptr)) { ioctlCount.gemVmDestroy++; return 0; } if ((request == DrmIoctl::GemContextDestroy) && (arg != nullptr)) { ioctlCount.contextDestroy++; auto destroy = static_cast(arg); this->receivedDestroyContextId = destroy->contextId; return this->storedRetVal; } if ((request == DrmIoctl::GemContextSetparam) && (arg != nullptr)) { ioctlCount.contextSetParam++; receivedContextParamRequestCount++; receivedContextParamRequest = *static_cast(arg); if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_PRIORITY) { return this->storedRetVal; } if ((receivedContextParamRequest.param == contextPrivateParamBoost) && (receivedContextParamRequest.value == 1)) { return this->storedRetVal; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_SSEU) { if (storedRetValForSetSSEU == 0) { storedParamSseu = (*static_cast(reinterpret_cast(receivedContextParamRequest.value))).sliceMask; } return this->storedRetValForSetSSEU; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_PERSISTENCE) { return this->storedRetValForPersistant; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_VM) { this->requestSetVmId = receivedContextParamRequest.value; return this->storedRetVal; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_RECOVERABLE) { receivedRecoverableContextValue = receivedContextParamRequest.value; unrecoverableContextSet = true; return this->storedRetVal; } } if ((request == DrmIoctl::GemContextGetparam) && (arg != nullptr)) { ioctlCount.contextGetParam++; receivedContextParamRequestCount++; receivedContextParamRequest = *static_cast(arg); if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_GTT_SIZE) { static_cast(arg)->value = this->storedGTTSize; return this->storedRetValForGetGttSize; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_SSEU) { if (storedRetValForGetSSEU == 0) { (*static_cast(reinterpret_cast(receivedContextParamRequest.value))).sliceMask = storedParamSseu; } return this->storedRetValForGetSSEU; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_PERSISTENCE) { static_cast(arg)->value = this->storedPersistentContextsSupport; return this->storedRetValForPersistant; } if (receivedContextParamRequest.param == I915_CONTEXT_PARAM_VM) { static_cast(arg)->value = this->storedRetValForVmId; if (incrementVmId) { this->storedRetValForVmId++; } return 0u; } } if (request == DrmIoctl::GemExecbuffer2) { ioctlCount.execbuffer2++; auto execbuf = static_cast(arg); auto execObjects = reinterpret_cast(execbuf->getBuffersPtr()); this->execBuffers.push_back(*execbuf); for (uint32_t i = 0; i < execbuf->getBufferCount(); i++) { this->receivedBos.push_back(execObjects[i]); } return execBufferResult; } if (request == DrmIoctl::GemUserptr) { ioctlCount.gemUserptr++; auto userPtrParams = static_cast(arg); userPtrParams->handle = returnHandle; returnHandle++; return 0; } if (request == DrmIoctl::GemCreate) { ioctlCount.gemCreate++; auto createParams = static_cast(arg); this->createParamsSize = createParams->size; this->createParamsHandle = createParams->handle = 1u; if (0 == this->createParamsSize) { return EINVAL; } return 0; } if (request == DrmIoctl::GemSetTiling) { ioctlCount.gemSetTiling++; auto setTilingParams = static_cast(arg); setTilingMode = setTilingParams->tilingMode; setTilingHandle = setTilingParams->handle; setTilingStride = setTilingParams->stride; return 0; } if (request == DrmIoctl::PrimeFdToHandle) { ioctlCount.primeFdToHandle++; auto primeToHandleParams = static_cast(arg); // return BO primeToHandleParams->handle = outputHandle; inputFd = primeToHandleParams->fileDescriptor; return fdToHandleRetVal; } if (request == DrmIoctl::PrimeHandleToFd) { ioctlCount.handleToPrimeFd++; auto primeToFdParams = static_cast(arg); primeToFdParams->fileDescriptor = outputFd; return 0; } if (request == DrmIoctl::GemWait) { ioctlCount.gemWait++; receivedGemWait = *static_cast(arg); return 0; } if (request == DrmIoctl::GemClose) { ioctlCount.gemClose++; return storedRetValForGemClose; } if (request == DrmIoctl::GetResetStats && arg != nullptr) { ioctlCount.gemResetStats++; auto outResetStats = static_cast(arg); for (const auto &resetStats : resetStatsToReturn) { if (resetStats.contextId == outResetStats->contextId) { *outResetStats = resetStats; return 0; } } return -1; } if (request == DrmIoctl::Query && arg != nullptr) { ioctlCount.query++; auto queryArg = static_cast(arg); auto queryItemArg = reinterpret_cast(queryArg->itemsPtr); storedQueryItem = *queryItemArg; auto realEuCount = std::max(rootDeviceEnvironment.getHardwareInfo()->gtSystemInfo.EUCount, static_cast(this->storedEUVal)); auto dataSize = static_cast(std::ceil(realEuCount / 8.0)); if (queryItemArg->length == 0) { if (queryItemArg->queryId == DRM_I915_QUERY_TOPOLOGY_INFO) { queryItemArg->length = static_cast(sizeof(QueryTopologyInfo) + dataSize); return 0; } } else { if (queryItemArg->queryId == DRM_I915_QUERY_TOPOLOGY_INFO) { auto topologyArg = reinterpret_cast(queryItemArg->dataPtr); if (this->failRetTopology) { return -1; } topologyArg->maxSlices = this->storedSVal; topologyArg->maxSubslices = this->storedSVal ? (this->storedSSVal / this->storedSVal) : 0; topologyArg->maxEusPerSubslice = this->storedSSVal ? (this->storedEUVal / this->storedSSVal) : 0; if (this->disableSomeTopology) { memset(topologyArg->data, 0xCA, dataSize); } else { memset(topologyArg->data, 0xFF, dataSize); } return 0; } } } return handleRemainingRequests(request, arg); } int DrmMock::waitUserFence(uint32_t ctxIdx, uint64_t address, uint64_t value, ValueWidth dataWidth, int64_t timeout, uint16_t flags) { waitUserFenceParams.push_back({ctxIdx, address, value, dataWidth, timeout, flags}); return Drm::waitUserFence(ctxIdx, address, value, dataWidth, timeout, flags); } int DrmMockEngine::handleRemainingRequests(DrmIoctl request, void *arg) { if ((request == DrmIoctl::Query) && (arg != nullptr)) { if (i915QuerySuccessCount == 0) { return EINVAL; } i915QuerySuccessCount--; auto query = static_cast(arg); if (query->itemsPtr == 0) { return EINVAL; } for (auto i = 0u; i < query->numItems; i++) { handleQueryItem(reinterpret_cast(query->itemsPtr) + i); } return 0; } return -1; } DrmMock::~DrmMock() { if (expectIoctlCallsOnDestruction) { EXPECT_EQ(expectedIoctlCallsOnDestruction, ioctlCallsCount); } }