/* * Copyright (C) 2018-2023 Intel Corporation * * SPDX-License-Identifier: MIT * */ #pragma once #include "shared/source/helpers/gfx_core_helper.h" #include "shared/source/helpers/string.h" #include "shared/source/os_interface/linux/drm_neo.h" #include "shared/test/common/helpers/default_hw_info.h" #include "shared/test/common/mocks/linux/mock_drm_wrappers.h" #include "shared/test/common/os_interface/linux/device_command_stream_fixture.h" #include #include #include #include #include #include using namespace NEO; class DrmMock : public Drm { public: using Drm::adapterBDF; using Drm::bindAvailable; using Drm::cacheInfo; using Drm::checkQueueSliceSupport; using Drm::chunkingAvailable; using Drm::chunkingMode; using Drm::classHandles; using Drm::completionFenceSupported; using Drm::contextDebugSupported; using Drm::engineInfo; using Drm::fenceVal; using Drm::generateElfUUID; using Drm::generateUUID; using Drm::getQueueSliceCount; using Drm::ioctlHelper; using Drm::memoryInfo; using Drm::minimalChunkingSize; using Drm::nonPersistentContextsSupported; using Drm::pageFaultSupported; using Drm::pagingFence; using Drm::preemptionSupported; using Drm::query; using Drm::queryAndSetVmBindPatIndexProgrammingSupport; using Drm::queryDeviceIdAndRevision; using Drm::requirePerContextVM; using Drm::setPairAvailable; using Drm::setupIoctlHelper; using Drm::sliceCountChangeSupported; using Drm::systemInfo; using Drm::virtualMemoryIds; DrmMock(int fd, RootDeviceEnvironment &rootDeviceEnvironment); DrmMock(RootDeviceEnvironment &rootDeviceEnvironment) : DrmMock(mockFd, rootDeviceEnvironment) {} ~DrmMock() override; int ioctl(DrmIoctl request, void *arg) override; int getErrno() override { if (baseErrno) { return Drm::getErrno(); } return errnoRetVal; } int waitUserFence(uint32_t ctxId, uint64_t address, uint64_t value, ValueWidth dataWidth, int64_t timeout, uint16_t flags) override; void writeConfigFile(const char *name, int deviceID) { std::ofstream tempfile(name, std::ios::binary); if (tempfile.is_open()) { PCIConfig config; config.deviceID = deviceID; tempfile.write(reinterpret_cast(&config), sizeof(config)); tempfile.close(); } } void deleteConfigFile(const char *name) { std::ofstream tempfile(name); if (tempfile.is_open()) { tempfile.close(); remove(name); } } void setFileDescriptor(int fd) { hwDeviceId = std::make_unique(fd, ""); } void setPciPath(const char *pciPath) { hwDeviceId = std::make_unique(getFileDescriptor(), pciPath); } void setBindAvailable() { this->bindAvailable = true; } void setContextDebugFlag(uint32_t drmContextId) override { passedContextDebugId = drmContextId; return Drm::setContextDebugFlag(drmContextId); } bool isDebugAttachAvailable() override { if (allowDebugAttachCallBase) { return Drm::isDebugAttachAvailable(); } return allowDebugAttach; } void queryPageFaultSupport() override { Drm::queryPageFaultSupport(); queryPageFaultSupportCalled = true; } int createDrmContext(uint32_t drmVmId, bool isDirectSubmissionRequested, bool isCooperativeContextRequested) override { capturedCooperativeContextRequest = isCooperativeContextRequested; if (callBaseCreateDrmContext) { return Drm::createDrmContext(drmVmId, isDirectSubmissionRequested, isCooperativeContextRequested); } return 0; } int createDrmVirtualMemory(uint32_t &drmVmId) override { createDrmVmCalled++; return Drm::createDrmVirtualMemory(drmVmId); } bool isVmBindAvailable() override { if (callBaseIsVmBindAvailable) { return Drm::isVmBindAvailable(); } return bindAvailable; } bool isSetPairAvailable() override { if (callBaseIsSetPairAvailable) { return Drm::isSetPairAvailable(); } return setPairAvailable; } bool isChunkingAvailable() override { if (callBaseIsChunkingAvailable) { return Drm::isChunkingAvailable(); } return chunkingAvailable; } uint32_t getChunkingMode() override { if (callBaseChunkingMode) { return Drm::isChunkingAvailable(); } return chunkingMode; } bool getSetPairAvailable() override { if (callBaseGetSetPairAvailable) { return Drm::getSetPairAvailable(); } return setPairAvailable; } uint32_t getBaseIoctlCalls() { return static_cast(virtualMemoryIds.size()); } bool useVMBindImmediate() const override { if (isVMBindImmediateSupported.has_value()) return *isVMBindImmediateSupported; else return Drm::useVMBindImmediate(); } int queryGttSize(uint64_t >tSizeOutput) override { gttSizeOutput = storedGTTSize; return storedRetValForGetGttSize; } static const int mockFd = 33; bool failRetTopology = false; bool baseErrno = true; int errnoRetVal = 0; int storedEUVal = 8; int storedSSVal = 2; int storedSVal = 1; int storedDeviceID = 1; int storedDeviceRevID = 1; int storedHasPooledEU = 1; int storedMinEUinPool = 1; int storedPersistentContextsSupport = 1; int storedRetVal = 0; int storedRetValForGetGttSize = 0; int storedRetValForGetSSEU = 0; int storedRetValForSetSSEU = 0; int storedRetValForDeviceID = 0; int storedRetValForEUVal = 0; int storedRetValForSSVal = 0; int storedRetValForDeviceRevID = 0; int storedRetValForPooledEU = 0; int storedRetValForMinEUinPool = 0; int storedRetValForPersistant = 0; int storedRetValForVmCreate = 0; int storedPreemptionSupport = 0; int storedExecSoftPin = 0; int storedRetValForVmId = 1; int storedCsTimestampFrequency = 1000; int storedOaTimestampFrequency = 123456; bool disableSomeTopology = false; bool allowDebugAttach = false; bool allowDebugAttachCallBase = false; bool callBaseCreateDrmContext = true; bool callBaseIsVmBindAvailable = false; bool callBaseIsSetPairAvailable = false; bool callBaseIsChunkingAvailable = false; bool callBaseGetChunkingMode = false; bool callBaseChunkingMode = false; bool callBaseGetSetPairAvailable = false; bool unrecoverableContextSet = false; bool failRetHwIpVersion = false; bool returnInvalidHwIpVersionLength = false; bool capturedCooperativeContextRequest = false; bool incrementVmId = false; std::optional isVMBindImmediateSupported{}; uint32_t passedContextDebugId = std::numeric_limits::max(); std::vector resetStatsToReturn{}; GemContextCreateExtSetParam receivedContextCreateSetParam = {}; uint32_t receivedContextCreateFlags = 0; uint32_t receivedDestroyContextId = 0; uint32_t ioctlCallsCount = 0; uint32_t receivedContextParamRequestCount = 0; GemContextParam receivedContextParamRequest = {}; uint64_t receivedRecoverableContextValue = std::numeric_limits::max(); uint64_t requestSetVmId = std::numeric_limits::max(); int createDrmVmCalled = 0; bool queryPageFaultSupportCalled = false; // DRM_IOCTL_I915_GEM_EXECBUFFER2 std::vector execBuffers{}; std::vector receivedBos{}; int execBufferResult = 0; // DRM_IOCTL_I915_GEM_CREATE uint64_t createParamsSize = 0; uint32_t createParamsHandle = 0; // DRM_IOCTL_I915_GEM_SET_TILING uint32_t setTilingMode = 0; uint32_t setTilingHandle = 0; uint32_t setTilingStride = 0; // DRM_IOCTL_PRIME_FD_TO_HANDLE uint32_t outputHandle = 0; int32_t inputFd = 0; int fdToHandleRetVal = 0; // DRM_IOCTL_HANDLE_TO_FD int32_t outputFd = 0; bool incrementOutputFdAfterCall = false; // DRM_IOCTL_I915_GEM_USERPTR uint32_t returnHandle = 0; uint64_t gpuMemSize = 3u * MemoryConstants::gigaByte; // DRM_IOCTL_I915_QUERY QueryItem storedQueryItem = {}; // DRM_IOCTL_I915_GEM_WAIT GemWait receivedGemWait = {}; // DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT uint32_t storedDrmContextId{}; // DRM_IOCTL_GEM_CLOSE int storedRetValForGemClose = 0; GemVmControl receivedGemVmControl{}; uint32_t latestCreatedVmId = 0u; uint64_t storedGTTSize = 1ull << 47; uint64_t storedParamSseu = ULONG_MAX; Ioctls ioctlCount{}; Ioctls ioctlTearDownExpected{}; bool ioctlTearDownExpects = false; bool expectIoctlCallsOnDestruction = false; uint32_t expectedIoctlCallsOnDestruction = 0u; virtual int handleRemainingRequests(DrmIoctl request, void *arg); struct WaitUserFenceParams { uint32_t ctxId; uint64_t address; uint64_t value; ValueWidth dataWidth; int64_t timeout; uint16_t flags; }; StackVec waitUserFenceParams; bool storedGetDeviceMemoryMaxClockRateInMhzStatus = true; bool useBaseGetDeviceMemoryMaxClockRateInMhz = true; bool getDeviceMemoryMaxClockRateInMhz(uint32_t tileId, uint32_t &clkRate) override { if (useBaseGetDeviceMemoryMaxClockRateInMhz == true) { return Drm::getDeviceMemoryMaxClockRateInMhz(tileId, clkRate); } if (storedGetDeviceMemoryMaxClockRateInMhzStatus == true) { clkRate = 800; } return storedGetDeviceMemoryMaxClockRateInMhzStatus; } bool storedGetDeviceMemoryPhysicalSizeInBytesStatus = true; bool useBaseGetDeviceMemoryPhysicalSizeInBytes = true; bool getDeviceMemoryPhysicalSizeInBytes(uint32_t tileId, uint64_t &physicalSize) override { if (useBaseGetDeviceMemoryPhysicalSizeInBytes == true) { return Drm::getDeviceMemoryPhysicalSizeInBytes(tileId, physicalSize); } if (storedGetDeviceMemoryPhysicalSizeInBytesStatus == true) { physicalSize = 1024; } return storedGetDeviceMemoryPhysicalSizeInBytesStatus; } }; class DrmMockNonFailing : public DrmMock { public: using DrmMock::DrmMock; int handleRemainingRequests(DrmIoctl request, void *arg) override { return 0; } }; class DrmMockReturnErrorNotSupported : public DrmMock { public: using DrmMock::DrmMock; int ioctl(DrmIoctl request, void *arg) override { if (request == DrmIoctl::GemExecbuffer2) { return -1; } return 0; } int getErrno() override { return EOPNOTSUPP; } }; class DrmMockEngine : public DrmMock { public: uint32_t i915QuerySuccessCount = std::numeric_limits::max(); uint32_t queryEngineInfoSuccessCount = std::numeric_limits::max(); DrmMockEngine(RootDeviceEnvironment &rootDeviceEnvironment); int handleRemainingRequests(DrmIoctl request, void *arg) override; void handleQueryItem(QueryItem *queryItem); bool failQueryDeviceBlob = false; }; class DrmMockResources : public DrmMock { public: DrmMockResources(RootDeviceEnvironment &rootDeviceEnvironment) : DrmMock(mockFd, rootDeviceEnvironment) { setBindAvailable(); callBaseIsVmBindAvailable = true; } bool registerResourceClasses() override { registerClassesCalled = true; return true; } uint32_t registerResource(DrmResourceClass classType, const void *data, size_t size) override { registeredClass = classType; memcpy_s(registeredData, sizeof(registeredData), data, size); registeredDataSize = size; return registerResourceReturnHandle; } void unregisterResource(uint32_t handle) override { unregisterCalledCount++; unregisteredHandle = handle; } uint32_t registerIsaCookie(uint32_t isaHanlde) override { return currentCookie++; } bool isVmBindAvailable() override { return bindAvailable; } uint32_t notifyFirstCommandQueueCreated(const void *data, size_t size) override { ioctlCallsCount++; capturedCmdQData = std::make_unique((size + sizeof(uint64_t) - 1) / sizeof(uint64_t)); capturedCmdQSize = size; memcpy(capturedCmdQData.get(), data, size); return 4; } void notifyLastCommandQueueDestroyed(uint32_t handle) override { unregisterResource(handle); } static const uint32_t registerResourceReturnHandle; uint32_t unregisteredHandle = 0; uint32_t unregisterCalledCount = 0; DrmResourceClass registeredClass = DrmResourceClass::MaxSize; bool registerClassesCalled = false; uint64_t registeredData[128]; size_t registeredDataSize; uint32_t currentCookie = 2; std::unique_ptr capturedCmdQData = nullptr; size_t capturedCmdQSize = 0; };