Files
compute-runtime/shared/source/os_interface/linux/ioctl_helper_prelim.cpp
Filip Hazubski 7ea22d0369 feature: Add pat index programming to gem create ext call
When upstream ioctl helper is created it will try to create small
allocation, adding I915_GEM_CREATE_EXT_SET_PAT extension. If it
succeeds, for all resources with valid pat index value it will then
explicitly program pat index value with gem create ext call.

PrintBOCreateDestroyResult value can be used to:
- print whether the set pat extension is supported by the kernel, when
  ioctl helper is created
- print whether set pat extension was added for a given gem create ext
  call and what pat index value was programmed

Note: introduced changes are disabled by defualt.
Toggle DisableGemCreateExtSetPat can be used to enable new functionality.

Related-To: NEO-7896

Signed-off-by: Filip Hazubski <filip.hazubski@intel.com>
2023-07-31 09:00:04 +02:00

930 lines
36 KiB
C++

/*
* Copyright (C) 2021-2023 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/debug_settings/debug_settings_manager.h"
#include "shared/source/execution_environment/root_device_environment.h"
#include "shared/source/helpers/aligned_memory.h"
#include "shared/source/helpers/common_types.h"
#include "shared/source/helpers/constants.h"
#include "shared/source/helpers/debug_helpers.h"
#include "shared/source/helpers/gfx_core_helper.h"
#include "shared/source/helpers/hw_info.h"
#include "shared/source/helpers/ptr_math.h"
#include "shared/source/helpers/string.h"
#include "shared/source/os_interface/linux/cache_info.h"
#include "shared/source/os_interface/linux/drm_neo.h"
#include "shared/source/os_interface/linux/drm_wrappers.h"
#include "shared/source/os_interface/linux/engine_info.h"
#include "shared/source/os_interface/linux/i915_prelim.h"
#include "shared/source/os_interface/linux/ioctl_helper.h"
#include "shared/source/os_interface/linux/sys_calls.h"
#include "shared/source/os_interface/product_helper.h"
#include <algorithm>
#include <cerrno>
#include <cstring>
#include <fcntl.h>
#include <iostream>
#include <new>
#include <sys/ioctl.h>
namespace NEO {
IoctlHelperPrelim20::IoctlHelperPrelim20(Drm &drmArg) : IoctlHelper(drmArg) {
const auto &productHelper = this->drm.getRootDeviceEnvironment().getHelper<ProductHelper>();
handleExecBufferInNonBlockMode = productHelper.isNonBlockingGpuSubmissionSupported();
if (DebugManager.flags.ForceNonblockingExecbufferCalls.get() != -1) {
handleExecBufferInNonBlockMode = DebugManager.flags.ForceNonblockingExecbufferCalls.get();
}
if (handleExecBufferInNonBlockMode) {
auto fileDescriptor = this->drm.getFileDescriptor();
SysCalls::fcntl(fileDescriptor, F_SETFL, SysCalls::fcntl(fileDescriptor, F_GETFL) | O_NONBLOCK);
}
};
bool IoctlHelperPrelim20::isSetPairAvailable() {
int setPairSupported = 0;
GetParam getParam{};
getParam.param = PRELIM_I915_PARAM_HAS_SET_PAIR;
getParam.value = &setPairSupported;
int retVal = IoctlHelper::ioctl(DrmIoctl::Getparam, &getParam);
if (retVal) {
return false;
}
return setPairSupported;
}
bool IoctlHelperPrelim20::isChunkingAvailable() {
int chunkSupported = 0;
GetParam getParam{};
getParam.param = PRELIM_I915_PARAM_HAS_CHUNK_SIZE;
getParam.value = &chunkSupported;
int retVal = IoctlHelper::ioctl(DrmIoctl::Getparam, &getParam);
if (retVal) {
return false;
}
return chunkSupported;
}
bool IoctlHelperPrelim20::getTopologyDataAndMap(const HardwareInfo &hwInfo, DrmQueryTopologyData &topologyData, TopologyMap &topologyMap) {
auto request = this->getDrmParamValue(DrmParam::QueryComputeSlices);
auto engineInfo = drm.getEngineInfo();
auto nTiles = hwInfo.gtSystemInfo.MultiTileArchInfo.TileCount;
auto useNewQuery = DebugManager.flags.UseNewQueryTopoIoctl.get() &&
engineInfo &&
(nTiles > 0);
if (useNewQuery) {
bool success = true;
int sliceCount = 0;
int subSliceCount = 0;
int euCount = 0;
for (auto i = 0u; i < nTiles; i++) {
auto classInstance = engineInfo->getEngineInstance(i, hwInfo.capabilityTable.defaultEngineType);
UNRECOVERABLE_IF(!classInstance);
uint32_t flags = classInstance->engineClass;
flags |= (classInstance->engineInstance << 8);
auto dataQuery = drm.query(request, flags);
if (dataQuery.empty()) {
success = false;
break;
}
auto data = reinterpret_cast<QueryTopologyInfo *>(dataQuery.data());
DrmQueryTopologyData tileTopologyData = {};
TopologyMapping mapping;
if (!this->translateTopologyInfo(data, tileTopologyData, mapping)) {
success = false;
break;
}
// pick smallest config
sliceCount = (sliceCount == 0) ? tileTopologyData.sliceCount : std::min(sliceCount, tileTopologyData.sliceCount);
subSliceCount = (subSliceCount == 0) ? tileTopologyData.subSliceCount : std::min(subSliceCount, tileTopologyData.subSliceCount);
euCount = (euCount == 0) ? tileTopologyData.euCount : std::min(euCount, tileTopologyData.euCount);
topologyData.maxSliceCount = std::max(topologyData.maxSliceCount, tileTopologyData.maxSliceCount);
topologyData.maxSubSliceCount = std::max(topologyData.maxSubSliceCount, tileTopologyData.maxSubSliceCount);
topologyData.maxEuCount = std::max(topologyData.maxEuCount, static_cast<int>(data->maxEusPerSubslice));
topologyMap[i] = mapping;
}
if (success) {
topologyData.sliceCount = sliceCount;
topologyData.subSliceCount = subSliceCount;
topologyData.euCount = euCount;
return true;
}
}
// fallback to DRM_I915_QUERY_TOPOLOGY_INFO
return IoctlHelper::getTopologyDataAndMap(hwInfo, topologyData, topologyMap);
}
bool IoctlHelperPrelim20::isVmBindAvailable() {
int vmBindSupported = 0;
GetParam getParam{};
getParam.param = PRELIM_I915_PARAM_HAS_VM_BIND;
getParam.value = &vmBindSupported;
int retVal = IoctlHelper::ioctl(DrmIoctl::Getparam, &getParam);
if (retVal) {
return false;
}
return vmBindSupported;
}
int IoctlHelperPrelim20::createGemExt(const MemRegionsVec &memClassInstances, size_t allocSize, uint32_t &handle, uint64_t patIndex, std::optional<uint32_t> vmId, int32_t pairHandle, bool isChunked, uint32_t numOfChunks) {
uint32_t regionsSize = static_cast<uint32_t>(memClassInstances.size());
std::vector<prelim_drm_i915_gem_memory_class_instance> regions(regionsSize);
for (uint32_t i = 0; i < regionsSize; i++) {
regions[i].memory_class = memClassInstances[i].memoryClass;
regions[i].memory_instance = memClassInstances[i].memoryInstance;
}
prelim_drm_i915_gem_object_param regionParam{};
regionParam.size = regionsSize;
regionParam.data = reinterpret_cast<uintptr_t>(regions.data());
regionParam.param = PRELIM_I915_OBJECT_PARAM | PRELIM_I915_PARAM_MEMORY_REGIONS;
prelim_drm_i915_gem_create_ext_setparam setparamRegion{};
setparamRegion.base.name = PRELIM_I915_GEM_CREATE_EXT_SETPARAM;
setparamRegion.param = regionParam;
prelim_drm_i915_gem_create_ext_vm_private vmPrivate{};
prelim_drm_i915_gem_create_ext_setparam pairSetparamRegion{};
prelim_drm_i915_gem_create_ext_setparam chunkingParamRegion{};
if (vmId != std::nullopt) {
vmPrivate.base.name = PRELIM_I915_GEM_CREATE_EXT_VM_PRIVATE;
vmPrivate.vm_id = vmId.value();
}
if (pairHandle != -1) {
pairSetparamRegion.base.name = PRELIM_I915_GEM_CREATE_EXT_SETPARAM;
pairSetparamRegion.param.param = PRELIM_I915_OBJECT_PARAM | PRELIM_I915_PARAM_SET_PAIR;
pairSetparamRegion.param.data = pairHandle;
}
if (isChunked) {
size_t chunkingSize = allocSize / numOfChunks;
chunkingParamRegion.base.name = PRELIM_I915_GEM_CREATE_EXT_SETPARAM;
chunkingParamRegion.param.param = PRELIM_I915_OBJECT_PARAM | PRELIM_I915_PARAM_SET_CHUNK_SIZE;
UNRECOVERABLE_IF(chunkingSize & (MemoryConstants::pageSize64k - 1));
chunkingParamRegion.param.data = chunkingSize;
printDebugString(DebugManager.flags.PrintBOChunkingLogs.get(), stdout,
"GEM_CREATE_EXT with BOChunkingSize %d, chunkingParamRegion.param.data %d, numOfChunks %d\n",
chunkingSize,
chunkingParamRegion.param.data,
numOfChunks);
setparamRegion.base.next_extension = reinterpret_cast<uintptr_t>(&chunkingParamRegion);
} else {
if (vmId != std::nullopt) {
vmPrivate.base.next_extension = reinterpret_cast<uintptr_t>(&pairSetparamRegion);
setparamRegion.base.next_extension = reinterpret_cast<uintptr_t>(&vmPrivate);
} else if (pairHandle != -1) {
setparamRegion.base.next_extension = reinterpret_cast<uintptr_t>(&pairSetparamRegion);
}
}
prelim_drm_i915_gem_create_ext createExt{};
createExt.size = allocSize;
createExt.extensions = reinterpret_cast<uintptr_t>(&setparamRegion);
printDebugString(DebugManager.flags.PrintBOCreateDestroyResult.get(), stdout, "Performing GEM_CREATE_EXT with { size: %lu, param: 0x%llX",
allocSize, regionParam.param);
if (DebugManager.flags.PrintBOCreateDestroyResult.get()) {
for (uint32_t i = 0; i < regionsSize; i++) {
auto region = regions[i];
printDebugString(DebugManager.flags.PrintBOCreateDestroyResult.get(), stdout, ", memory class: %d, memory instance: %d",
region.memory_class, region.memory_instance);
}
printDebugString(DebugManager.flags.PrintBOCreateDestroyResult.get(), stdout, "%s", " }\n");
}
auto ret = IoctlHelper::ioctl(DrmIoctl::GemCreateExt, &createExt);
printDebugString(DebugManager.flags.PrintBOCreateDestroyResult.get(), stdout, "GEM_CREATE_EXT has returned: %d BO-%u with size: %lu\n", ret, createExt.handle, createExt.size);
handle = createExt.handle;
return ret;
}
CacheRegion IoctlHelperPrelim20::closAlloc() {
struct prelim_drm_i915_gem_clos_reserve clos = {};
int ret = IoctlHelper::ioctl(DrmIoctl::GemClosReserve, &clos);
if (ret != 0) {
int err = errno;
printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(I915_GEM_CLOS_RESERVE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
DEBUG_BREAK_IF(true);
return CacheRegion::None;
}
return static_cast<CacheRegion>(clos.clos_index);
}
uint16_t IoctlHelperPrelim20::closAllocWays(CacheRegion closIndex, uint16_t cacheLevel, uint16_t numWays) {
struct prelim_drm_i915_gem_cache_reserve cache = {};
cache.clos_index = static_cast<uint16_t>(closIndex);
cache.cache_level = cacheLevel;
cache.num_ways = numWays;
int ret = IoctlHelper::ioctl(DrmIoctl::GemCacheReserve, &cache);
if (ret != 0) {
int err = errno;
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(I915_GEM_CACHE_RESERVE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
return 0;
}
return cache.num_ways;
}
CacheRegion IoctlHelperPrelim20::closFree(CacheRegion closIndex) {
struct prelim_drm_i915_gem_clos_free clos = {};
clos.clos_index = static_cast<uint16_t>(closIndex);
int ret = IoctlHelper::ioctl(DrmIoctl::GemClosFree, &clos);
if (ret != 0) {
int err = errno;
printDebugString(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(I915_GEM_CLOS_FREE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
DEBUG_BREAK_IF(true);
return CacheRegion::None;
}
return closIndex;
}
int IoctlHelperPrelim20::waitUserFence(uint32_t ctxId, uint64_t address,
uint64_t value, uint32_t dataWidth, int64_t timeout, uint16_t flags) {
prelim_drm_i915_gem_wait_user_fence wait = {};
wait.ctx_id = ctxId;
wait.flags = flags;
switch (dataWidth) {
case 3u:
wait.mask = PRELIM_I915_UFENCE_WAIT_U64;
break;
case 2u:
wait.mask = PRELIM_I915_UFENCE_WAIT_U32;
break;
case 1u:
wait.mask = PRELIM_I915_UFENCE_WAIT_U16;
break;
default:
wait.mask = PRELIM_I915_UFENCE_WAIT_U8;
break;
}
wait.op = PRELIM_I915_UFENCE_WAIT_GTE;
wait.addr = address;
wait.value = value;
wait.timeout = timeout;
return IoctlHelper::ioctl(DrmIoctl::GemWaitUserFence, &wait);
}
uint32_t IoctlHelperPrelim20::getAtomicAdvise(bool isNonAtomic) {
return isNonAtomic ? PRELIM_I915_VM_ADVISE_ATOMIC_NONE : PRELIM_I915_VM_ADVISE_ATOMIC_SYSTEM;
}
uint32_t IoctlHelperPrelim20::getPreferredLocationAdvise() {
return PRELIM_I915_VM_ADVISE_PREFERRED_LOCATION;
}
std::optional<MemoryClassInstance> IoctlHelperPrelim20::getPreferredLocationRegion(PreferredLocation memoryLocation, uint32_t memoryInstance) {
MemoryClassInstance region{};
if (NEO::DebugManager.flags.SetVmAdvisePreferredLocation.get() != -1) {
memoryLocation = static_cast<PreferredLocation>(NEO::DebugManager.flags.SetVmAdvisePreferredLocation.get());
}
switch (memoryLocation) {
case PreferredLocation::Clear:
region.memoryClass = -1;
region.memoryInstance = 0;
break;
case PreferredLocation::System:
region.memoryClass = getDrmParamValue(DrmParam::MemoryClassSystem);
region.memoryInstance = 0;
break;
case PreferredLocation::Device:
default:
region.memoryClass = getDrmParamValue(DrmParam::MemoryClassDevice);
region.memoryInstance = memoryInstance;
break;
case PreferredLocation::None:
return std::nullopt;
}
return region;
}
bool IoctlHelperPrelim20::setVmBoAdviseForChunking(int32_t handle, uint64_t start, uint64_t length, uint32_t attribute, void *region) {
prelim_drm_i915_gem_vm_advise vmAdvise{};
vmAdvise.handle = handle;
vmAdvise.start = start;
vmAdvise.length = length;
vmAdvise.attribute = attribute;
UNRECOVERABLE_IF(region == nullptr);
vmAdvise.region = *reinterpret_cast<prelim_drm_i915_gem_memory_class_instance *>(region);
int ret = IoctlHelper::ioctl(DrmIoctl::GemVmAdvise, &vmAdvise);
if (ret != 0) {
int err = errno;
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(PRELIM_DRM_I915_GEM_VM_ADVISE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
DEBUG_BREAK_IF(true);
return false;
}
return true;
}
bool IoctlHelperPrelim20::setVmBoAdvise(int32_t handle, uint32_t attribute, void *region) {
prelim_drm_i915_gem_vm_advise vmAdvise{};
vmAdvise.handle = handle;
vmAdvise.attribute = attribute;
if (region != nullptr) {
vmAdvise.region = *reinterpret_cast<prelim_drm_i915_gem_memory_class_instance *>(region);
}
int ret = IoctlHelper::ioctl(DrmIoctl::GemVmAdvise, &vmAdvise);
if (ret != 0) {
int err = errno;
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(PRELIM_DRM_I915_GEM_VM_ADVISE) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
DEBUG_BREAK_IF(true);
return false;
}
return true;
}
bool IoctlHelperPrelim20::setVmPrefetch(uint64_t start, uint64_t length, uint32_t region, uint32_t vmId) {
prelim_drm_i915_gem_vm_prefetch vmPrefetch{};
vmPrefetch.length = length;
vmPrefetch.region = region;
vmPrefetch.start = start;
vmPrefetch.vm_id = vmId;
int ret = IoctlHelper::ioctl(DrmIoctl::GemVmPrefetch, &vmPrefetch);
if (ret != 0) {
int err = errno;
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "ioctl(PRELIM_DRM_I915_GEM_VM_PREFETCH) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
DEBUG_BREAK_IF(true);
return false;
}
return true;
}
uint32_t IoctlHelperPrelim20::getDirectSubmissionFlag() {
return PRELIM_I915_CONTEXT_CREATE_FLAGS_LONG_RUNNING;
}
uint16_t IoctlHelperPrelim20::getWaitUserFenceSoftFlag() {
return PRELIM_I915_UFENCE_WAIT_SOFT;
};
int IoctlHelperPrelim20::execBuffer(ExecBuffer *execBuffer, uint64_t completionGpuAddress, TaskCountType counterValue) {
prelim_drm_i915_gem_execbuffer_ext_user_fence fenceObject = {};
if (completionGpuAddress != 0) {
fenceObject.base.name = PRELIM_DRM_I915_GEM_EXECBUFFER_EXT_USER_FENCE;
fenceObject.addr = completionGpuAddress;
fenceObject.value = counterValue;
auto &drmExecBuffer = *reinterpret_cast<drm_i915_gem_execbuffer2 *>(execBuffer->data);
drmExecBuffer.flags |= I915_EXEC_USE_EXTENSIONS;
drmExecBuffer.num_cliprects = 0;
drmExecBuffer.cliprects_ptr = castToUint64(&fenceObject);
if (DebugManager.flags.PrintCompletionFenceUsage.get()) {
std::cout << "Completion fence submitted."
<< " GPU address: " << std::hex << completionGpuAddress << std::dec
<< ", value: " << counterValue << std::endl;
}
}
return IoctlHelper::ioctl(DrmIoctl::GemExecbuffer2, execBuffer);
}
bool IoctlHelperPrelim20::completionFenceExtensionSupported(const bool isVmBindAvailable) {
return isVmBindAvailable;
}
std::unique_ptr<uint8_t[]> IoctlHelperPrelim20::prepareVmBindExt(const StackVec<uint32_t, 2> &bindExtHandles) {
static_assert(std::is_trivially_destructible_v<prelim_drm_i915_vm_bind_ext_uuid>,
"Storage must be allowed to be reused without calling the destructor!");
static_assert(alignof(prelim_drm_i915_vm_bind_ext_uuid) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__,
"Alignment of a buffer returned via new[] operator must allow storing the required type!");
const auto bufferSize{sizeof(prelim_drm_i915_vm_bind_ext_uuid) * bindExtHandles.size()};
std::unique_ptr<uint8_t[]> extensionsBuffer{new uint8_t[bufferSize]};
auto extensions = new (extensionsBuffer.get()) prelim_drm_i915_vm_bind_ext_uuid[bindExtHandles.size()];
std::memset(extensionsBuffer.get(), 0, bufferSize);
extensions[0].uuid_handle = bindExtHandles[0];
extensions[0].base.name = PRELIM_I915_VM_BIND_EXT_UUID;
for (size_t i = 1; i < bindExtHandles.size(); i++) {
extensions[i - 1].base.next_extension = reinterpret_cast<uint64_t>(&extensions[i]);
extensions[i].uuid_handle = bindExtHandles[i];
extensions[i].base.name = PRELIM_I915_VM_BIND_EXT_UUID;
}
return extensionsBuffer;
}
uint64_t IoctlHelperPrelim20::getFlagsForVmBind(bool bindCapture, bool bindImmediate, bool bindMakeResident) {
uint64_t flags = 0u;
if (bindCapture) {
flags |= PRELIM_I915_GEM_VM_BIND_CAPTURE;
}
if (bindImmediate) {
flags |= PRELIM_I915_GEM_VM_BIND_IMMEDIATE;
}
if (bindMakeResident) {
flags |= PRELIM_I915_GEM_VM_BIND_MAKE_RESIDENT;
}
return flags;
}
prelim_drm_i915_query_distance_info translateToi915(const DistanceInfo &distanceInfo) {
prelim_drm_i915_query_distance_info dist{};
dist.engine.engine_class = distanceInfo.engine.engineClass;
dist.engine.engine_instance = distanceInfo.engine.engineInstance;
dist.region.memory_class = distanceInfo.region.memoryClass;
dist.region.memory_instance = distanceInfo.region.memoryInstance;
return dist;
}
int IoctlHelperPrelim20::queryDistances(std::vector<QueryItem> &queryItems, std::vector<DistanceInfo> &distanceInfos) {
std::vector<prelim_drm_i915_query_distance_info> i915Distances(distanceInfos.size());
std::transform(distanceInfos.begin(), distanceInfos.end(), i915Distances.begin(), translateToi915);
for (auto i = 0u; i < i915Distances.size(); i++) {
queryItems[i].queryId = PRELIM_DRM_I915_QUERY_DISTANCE_INFO;
queryItems[i].length = sizeof(prelim_drm_i915_query_distance_info);
queryItems[i].flags = 0u;
queryItems[i].dataPtr = reinterpret_cast<uint64_t>(&i915Distances[i]);
}
Query query{};
query.itemsPtr = reinterpret_cast<uint64_t>(queryItems.data());
query.numItems = static_cast<uint32_t>(queryItems.size());
auto ret = IoctlHelper::ioctl(DrmIoctl::Query, &query);
for (auto i = 0u; i < i915Distances.size(); i++) {
distanceInfos[i].distance = i915Distances[i].distance;
}
return ret;
}
std::optional<DrmParam> IoctlHelperPrelim20::getHasPageFaultParamId() {
return DrmParam::ParamHasPageFault;
};
bool IoctlHelperPrelim20::getEuStallProperties(std::array<uint64_t, 12u> &properties, uint64_t dssBufferSize, uint64_t samplingRate,
uint64_t pollPeriod, uint64_t engineInstance, uint64_t notifyNReports) {
properties[0] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_BUF_SZ;
properties[1] = dssBufferSize;
properties[2] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_SAMPLE_RATE;
properties[3] = samplingRate;
properties[4] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_POLL_PERIOD;
properties[5] = pollPeriod;
properties[6] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_ENGINE_CLASS;
properties[7] = prelim_drm_i915_gem_engine_class::PRELIM_I915_ENGINE_CLASS_COMPUTE;
properties[8] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_ENGINE_INSTANCE;
properties[9] = engineInstance;
properties[10] = prelim_drm_i915_eu_stall_property_id::PRELIM_DRM_I915_EU_STALL_PROP_EVENT_REPORT_COUNT;
properties[11] = notifyNReports;
return true;
}
uint32_t IoctlHelperPrelim20::getEuStallFdParameter() {
return PRELIM_I915_PERF_FLAG_FD_EU_STALL;
}
std::unique_ptr<uint8_t[]> IoctlHelperPrelim20::createVmControlExtRegion(const std::optional<MemoryClassInstance> &regionInstanceClass) {
if (regionInstanceClass) {
auto retVal = std::make_unique<uint8_t[]>(sizeof(prelim_drm_i915_gem_vm_region_ext));
auto regionExt = reinterpret_cast<prelim_drm_i915_gem_vm_region_ext *>(retVal.get());
*regionExt = {};
regionExt->base.name = PRELIM_I915_GEM_VM_CONTROL_EXT_REGION;
regionExt->region.memory_class = regionInstanceClass.value().memoryClass;
regionExt->region.memory_instance = regionInstanceClass.value().memoryInstance;
return retVal;
}
return {};
}
uint32_t IoctlHelperPrelim20::getFlagsForVmCreate(bool disableScratch, bool enablePageFault, bool useVmBind) {
uint32_t flags = 0u;
if (disableScratch) {
flags |= PRELIM_I915_VM_CREATE_FLAGS_DISABLE_SCRATCH;
}
if (enablePageFault) {
flags |= PRELIM_I915_VM_CREATE_FLAGS_ENABLE_PAGE_FAULT;
}
if (useVmBind) {
flags |= PRELIM_I915_VM_CREATE_FLAGS_USE_VM_BIND;
}
return flags;
}
uint32_t gemCreateContextExt(IoctlHelper &ioctlHelper, GemContextCreateExt &gcc, GemContextCreateExtSetParam &extSetparam) {
gcc.flags |= I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS;
extSetparam.base.nextExtension = gcc.extensions;
gcc.extensions = reinterpret_cast<uint64_t>(&extSetparam);
auto ioctlResult = ioctlHelper.ioctl(DrmIoctl::GemContextCreateExt, &gcc);
UNRECOVERABLE_IF(ioctlResult != 0);
return gcc.contextId;
}
uint32_t gemCreateContextAcc(IoctlHelper &ioctlHelper, GemContextCreateExt &gcc, uint16_t trigger, uint8_t granularity) {
prelim_drm_i915_gem_context_param_acc paramAcc = {};
paramAcc.trigger = trigger;
paramAcc.notify = 1;
paramAcc.granularity = granularity;
DrmUserExtension userExt{};
userExt.name = I915_CONTEXT_CREATE_EXT_SETPARAM;
GemContextParam ctxParam = {};
ctxParam.param = PRELIM_I915_CONTEXT_PARAM_ACC;
ctxParam.contextId = 0;
ctxParam.size = sizeof(paramAcc);
ctxParam.value = reinterpret_cast<uint64_t>(&paramAcc);
GemContextCreateExtSetParam extSetparam{};
extSetparam.base = userExt;
extSetparam.param = ctxParam;
return gemCreateContextExt(ioctlHelper, gcc, extSetparam);
}
uint32_t IoctlHelperPrelim20::createContextWithAccessCounters(GemContextCreateExt &gcc) {
uint16_t trigger = 0;
if (DebugManager.flags.AccessCountersTrigger.get() != -1) {
trigger = static_cast<uint16_t>(DebugManager.flags.AccessCountersTrigger.get());
}
uint8_t granularity = PRELIM_I915_CONTEXT_ACG_2M;
if (DebugManager.flags.AccessCountersGranularity.get() != -1) {
granularity = static_cast<uint8_t>(DebugManager.flags.AccessCountersGranularity.get());
}
return gemCreateContextAcc(*this, gcc, trigger, granularity);
}
uint32_t IoctlHelperPrelim20::createCooperativeContext(GemContextCreateExt &gcc) {
GemContextCreateExtSetParam extSetparam{};
extSetparam.base.name = I915_CONTEXT_CREATE_EXT_SETPARAM;
extSetparam.param.param = PRELIM_I915_CONTEXT_PARAM_RUNALONE;
return gemCreateContextExt(*this, gcc, extSetparam);
}
static_assert(sizeof(VmBindExtSetPatT) == sizeof(prelim_drm_i915_vm_bind_ext_set_pat), "Invalid size for VmBindExtSetPat");
void IoctlHelperPrelim20::fillVmBindExtSetPat(VmBindExtSetPatT &vmBindExtSetPat, uint64_t patIndex, uint64_t nextExtension) {
auto prelimVmBindExtSetPat = reinterpret_cast<prelim_drm_i915_vm_bind_ext_set_pat *>(vmBindExtSetPat);
UNRECOVERABLE_IF(!prelimVmBindExtSetPat);
prelimVmBindExtSetPat->base.name = PRELIM_I915_VM_BIND_EXT_SET_PAT;
prelimVmBindExtSetPat->pat_index = patIndex;
prelimVmBindExtSetPat->base.next_extension = nextExtension;
}
static_assert(sizeof(VmBindExtUserFenceT) == sizeof(prelim_drm_i915_vm_bind_ext_user_fence), "Invalid size for VmBindExtUserFence");
void IoctlHelperPrelim20::fillVmBindExtUserFence(VmBindExtUserFenceT &vmBindExtUserFence, uint64_t fenceAddress, uint64_t fenceValue, uint64_t nextExtension) {
auto prelimVmBindExtUserFence = reinterpret_cast<prelim_drm_i915_vm_bind_ext_user_fence *>(vmBindExtUserFence);
UNRECOVERABLE_IF(!prelimVmBindExtUserFence);
prelimVmBindExtUserFence->base.name = PRELIM_I915_VM_BIND_EXT_USER_FENCE;
prelimVmBindExtUserFence->base.next_extension = nextExtension;
prelimVmBindExtUserFence->addr = fenceAddress;
prelimVmBindExtUserFence->val = fenceValue;
}
std::optional<uint64_t> IoctlHelperPrelim20::getCopyClassSaturatePCIECapability() {
return PRELIM_I915_COPY_CLASS_CAP_SATURATE_PCIE;
}
std::optional<uint64_t> IoctlHelperPrelim20::getCopyClassSaturateLinkCapability() {
return PRELIM_I915_COPY_CLASS_CAP_SATURATE_LINK;
}
uint32_t IoctlHelperPrelim20::getVmAdviseAtomicAttribute() {
switch (NEO::DebugManager.flags.SetVmAdviseAtomicAttribute.get()) {
case 0:
return PRELIM_I915_VM_ADVISE_ATOMIC_NONE;
case 1:
return PRELIM_I915_VM_ADVISE_ATOMIC_DEVICE;
default:
return PRELIM_I915_VM_ADVISE_ATOMIC_SYSTEM;
}
}
prelim_drm_i915_gem_vm_bind translateVmBindParamsToPrelimStruct(const VmBindParams &vmBindParams) {
prelim_drm_i915_gem_vm_bind vmBind{};
vmBind.vm_id = vmBindParams.vmId;
vmBind.handle = vmBindParams.handle;
vmBind.start = vmBindParams.start;
vmBind.offset = vmBindParams.offset;
vmBind.length = vmBindParams.length;
vmBind.flags = vmBindParams.flags;
vmBind.extensions = vmBindParams.extensions;
return vmBind;
}
int IoctlHelperPrelim20::vmBind(const VmBindParams &vmBindParams) {
auto prelimVmBind = translateVmBindParamsToPrelimStruct(vmBindParams);
return IoctlHelper::ioctl(DrmIoctl::GemVmBind, &prelimVmBind);
}
int IoctlHelperPrelim20::vmUnbind(const VmBindParams &vmBindParams) {
auto prelimVmBind = translateVmBindParamsToPrelimStruct(vmBindParams);
return IoctlHelper::ioctl(DrmIoctl::GemVmUnbind, &prelimVmBind);
}
UuidRegisterResult IoctlHelperPrelim20::registerUuid(const std::string &uuid, uint32_t uuidClass, uint64_t ptr, uint64_t size) {
prelim_drm_i915_uuid_control uuidControl = {};
memcpy_s(uuidControl.uuid, sizeof(uuidControl.uuid), uuid.c_str(), uuid.size());
uuidControl.uuid_class = uuidClass;
uuidControl.ptr = ptr;
uuidControl.size = size;
const auto retVal = IoctlHelper::ioctl(DrmIoctl::UuidRegister, &uuidControl);
return {
retVal,
uuidControl.handle,
};
}
UuidRegisterResult IoctlHelperPrelim20::registerStringClassUuid(const std::string &uuid, uint64_t ptr, uint64_t size) {
return registerUuid(uuid, PRELIM_I915_UUID_CLASS_STRING, ptr, size);
}
int IoctlHelperPrelim20::unregisterUuid(uint32_t handle) {
prelim_drm_i915_uuid_control uuidControl = {};
uuidControl.handle = handle;
return IoctlHelper::ioctl(DrmIoctl::UuidUnregister, &uuidControl);
}
bool IoctlHelperPrelim20::isContextDebugSupported() {
drm_i915_gem_context_param ctxParam = {};
ctxParam.size = 0;
ctxParam.param = PRELIM_I915_CONTEXT_PARAM_DEBUG_FLAGS;
ctxParam.ctx_id = 0;
ctxParam.value = 0;
const auto retVal = IoctlHelper::ioctl(DrmIoctl::GemContextGetparam, &ctxParam);
return retVal == 0 && ctxParam.value == (PRELIM_I915_CONTEXT_PARAM_DEBUG_FLAG_SIP << 32);
}
int IoctlHelperPrelim20::setContextDebugFlag(uint32_t drmContextId) {
drm_i915_gem_context_param ctxParam = {};
ctxParam.size = 0;
ctxParam.param = PRELIM_I915_CONTEXT_PARAM_DEBUG_FLAGS;
ctxParam.ctx_id = drmContextId;
ctxParam.value = PRELIM_I915_CONTEXT_PARAM_DEBUG_FLAG_SIP << 32 | PRELIM_I915_CONTEXT_PARAM_DEBUG_FLAG_SIP;
return IoctlHelper::ioctl(DrmIoctl::GemContextSetparam, &ctxParam);
}
bool IoctlHelperPrelim20::isDebugAttachAvailable() {
return true;
}
unsigned int IoctlHelperPrelim20::getIoctlRequestValue(DrmIoctl ioctlRequest) const {
switch (ioctlRequest) {
case DrmIoctl::GemVmBind:
return PRELIM_DRM_IOCTL_I915_GEM_VM_BIND;
case DrmIoctl::GemVmUnbind:
return PRELIM_DRM_IOCTL_I915_GEM_VM_UNBIND;
case DrmIoctl::GemWaitUserFence:
return PRELIM_DRM_IOCTL_I915_GEM_WAIT_USER_FENCE;
case DrmIoctl::GemCreateExt:
return PRELIM_DRM_IOCTL_I915_GEM_CREATE_EXT;
case DrmIoctl::GemVmAdvise:
return PRELIM_DRM_IOCTL_I915_GEM_VM_ADVISE;
case DrmIoctl::GemVmPrefetch:
return PRELIM_DRM_IOCTL_I915_GEM_VM_PREFETCH;
case DrmIoctl::UuidRegister:
return PRELIM_DRM_IOCTL_I915_UUID_REGISTER;
case DrmIoctl::UuidUnregister:
return PRELIM_DRM_IOCTL_I915_UUID_UNREGISTER;
case DrmIoctl::DebuggerOpen:
return PRELIM_DRM_IOCTL_I915_DEBUGGER_OPEN;
case DrmIoctl::GemClosReserve:
return PRELIM_DRM_IOCTL_I915_GEM_CLOS_RESERVE;
case DrmIoctl::GemClosFree:
return PRELIM_DRM_IOCTL_I915_GEM_CLOS_FREE;
case DrmIoctl::GemCacheReserve:
return PRELIM_DRM_IOCTL_I915_GEM_CACHE_RESERVE;
default:
return getIoctlRequestValueBase(ioctlRequest);
}
}
int IoctlHelperPrelim20::getDrmParamValue(DrmParam drmParam) const {
switch (drmParam) {
case DrmParam::EngineClassCompute:
return prelim_drm_i915_gem_engine_class::PRELIM_I915_ENGINE_CLASS_COMPUTE;
case DrmParam::ParamHasVmBind:
return PRELIM_I915_PARAM_HAS_VM_BIND;
case DrmParam::ParamHasPageFault:
return PRELIM_I915_PARAM_HAS_PAGE_FAULT;
case DrmParam::QueryHwconfigTable:
return PRELIM_DRM_I915_QUERY_HWCONFIG_TABLE;
case DrmParam::QueryComputeSlices:
return PRELIM_DRM_I915_QUERY_COMPUTE_SUBSLICES;
default:
return getDrmParamValueBase(drmParam);
}
}
std::string IoctlHelperPrelim20::getDrmParamString(DrmParam drmParam) const {
switch (drmParam) {
case DrmParam::ParamHasVmBind:
return "PRELIM_I915_PARAM_HAS_VM_BIND";
case DrmParam::ParamHasPageFault:
return "PRELIM_I915_PARAM_HAS_PAGE_FAULT";
default:
return getDrmParamStringBase(drmParam);
}
}
std::string IoctlHelperPrelim20::getIoctlString(DrmIoctl ioctlRequest) const {
switch (ioctlRequest) {
case DrmIoctl::GemVmBind:
return "PRELIM_DRM_IOCTL_I915_GEM_VM_BIND";
case DrmIoctl::GemVmUnbind:
return "PRELIM_DRM_IOCTL_I915_GEM_VM_UNBIND";
case DrmIoctl::GemWaitUserFence:
return "PRELIM_DRM_IOCTL_I915_GEM_WAIT_USER_FENCE";
case DrmIoctl::GemCreateExt:
return "PRELIM_DRM_IOCTL_I915_GEM_CREATE_EXT";
case DrmIoctl::GemVmAdvise:
return "PRELIM_DRM_IOCTL_I915_GEM_VM_ADVISE";
case DrmIoctl::GemVmPrefetch:
return "PRELIM_DRM_IOCTL_I915_GEM_VM_PREFETCH";
case DrmIoctl::UuidRegister:
return "PRELIM_DRM_IOCTL_I915_UUID_REGISTER";
case DrmIoctl::UuidUnregister:
return "PRELIM_DRM_IOCTL_I915_UUID_UNREGISTER";
case DrmIoctl::DebuggerOpen:
return "PRELIM_DRM_IOCTL_I915_DEBUGGER_OPEN";
case DrmIoctl::GemClosReserve:
return "PRELIM_DRM_IOCTL_I915_GEM_CLOS_RESERVE";
case DrmIoctl::GemClosFree:
return "PRELIM_DRM_IOCTL_I915_GEM_CLOS_FREE";
case DrmIoctl::GemCacheReserve:
return "PRELIM_DRM_IOCTL_I915_GEM_CACHE_RESERVE";
default:
return getIoctlStringBase(ioctlRequest);
}
}
bool IoctlHelperPrelim20::checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest) const {
switch (ioctlRequest) {
case DrmIoctl::DebuggerOpen:
return (error == EINTR || error == EAGAIN);
case DrmIoctl::GemExecbuffer2:
if (handleExecBufferInNonBlockMode) {
return (error == EINTR || error == EBUSY || error == -EBUSY);
} else {
return IoctlHelper::checkIfIoctlReinvokeRequired(error, ioctlRequest);
}
default:
break;
}
return IoctlHelper::checkIfIoctlReinvokeRequired(error, ioctlRequest);
}
bool IoctlHelperPrelim20::getFabricLatency(uint32_t fabricId, uint32_t &latency, uint32_t &bandwidth) {
Query query = {};
QueryItem queryItem = {};
PrelimI915::prelim_drm_i915_query_fabric_info info = {};
info.fabric_id = fabricId;
queryItem.queryId = PRELIM_DRM_I915_QUERY_FABRIC_INFO;
queryItem.length = static_cast<int32_t>(sizeof(info));
queryItem.dataPtr = reinterpret_cast<uint64_t>(&info);
queryItem.flags = 0;
query.itemsPtr = reinterpret_cast<uint64_t>(&queryItem);
query.numItems = 1;
auto ret = IoctlHelper::ioctl(DrmIoctl::Query, &query);
if (ret != 0) {
return false;
}
if (info.latency < 10 || info.bandwidth == 0) {
return false;
}
// Latency is in tenths of path length. 10 == 1 fabric link between src and dst
// 1 link = zero hops
latency = (info.latency / 10) - 1;
bandwidth = info.bandwidth;
return true;
}
bool IoctlHelperPrelim20::isWaitBeforeBindRequired(bool bind) const {
return bind;
}
void *IoctlHelperPrelim20::pciBarrierMmap() {
static constexpr uint64_t pciBarrierMmapOffset = 0x50 << 12;
return SysCalls::mmap(NULL, MemoryConstants::pageSize, PROT_WRITE, MAP_SHARED, drm.getFileDescriptor(), pciBarrierMmapOffset);
}
bool IoctlHelperPrelim20::queryHwIpVersion(EngineClassInstance &engineInfo, HardwareIpVersion &ipVersion, int &ret) {
QueryItem queryItem{};
queryItem.queryId = PRELIM_DRM_I915_QUERY_HW_IP_VERSION;
Query query{};
query.itemsPtr = reinterpret_cast<uint64_t>(&queryItem);
query.numItems = 1u;
ret = ioctl(DrmIoctl::Query, &query);
if (ret != 0) {
return false;
}
if (queryItem.length != sizeof(prelim_drm_i915_query_hw_ip_version)) {
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n",
"Size got from PRELIM_DRM_I915_QUERY_HW_IP_VERSION query does not match PrelimI915::prelim_drm_i915_query_hw_ip_version size");
return false;
}
prelim_drm_i915_query_hw_ip_version queryHwIpVersion{};
queryHwIpVersion.engine.engine_class = engineInfo.engineClass;
queryHwIpVersion.engine.engine_instance = engineInfo.engineInstance;
queryItem.dataPtr = reinterpret_cast<uint64_t>(&queryHwIpVersion);
ret = ioctl(DrmIoctl::Query, &query);
if (ret != 0) {
return false;
}
ipVersion.architecture = queryHwIpVersion.arch;
ipVersion.release = queryHwIpVersion.release;
ipVersion.revision = queryHwIpVersion.stepping;
return true;
}
bool IoctlHelperPrelim20::initialize() {
return true;
}
void IoctlHelperPrelim20::setupIpVersion() {
auto &rootDeviceEnvironment = drm.getRootDeviceEnvironment();
auto hwInfo = rootDeviceEnvironment.getMutableHardwareInfo();
auto &productHelper = drm.getRootDeviceEnvironment().getHelper<ProductHelper>();
EngineClassInstance engineInfo = {static_cast<uint16_t>(getDrmParamValue(DrmParam::EngineClassRender)), 0};
int ret = 0;
auto isPlatformQuerySupported = productHelper.isPlatformQuerySupported();
bool result = false;
if (isPlatformQuerySupported) {
result = queryHwIpVersion(engineInfo, hwInfo->ipVersion, ret);
if (result == false && ret != 0) {
int err = drm.getErrno();
PRINT_DEBUG_STRING(DebugManager.flags.PrintDebugMessages.get(), stderr,
"ioctl(PRELIM_DRM_I915_QUERY_HW_IP_VERSION) failed with %d. errno=%d(%s)\n", ret, err, strerror(err));
}
}
if (result == false) {
IoctlHelper::setupIpVersion();
}
}
static_assert(sizeof(MemoryClassInstance) == sizeof(prelim_drm_i915_gem_memory_class_instance));
static_assert(offsetof(MemoryClassInstance, memoryClass) == offsetof(prelim_drm_i915_gem_memory_class_instance, memory_class));
static_assert(offsetof(MemoryClassInstance, memoryInstance) == offsetof(prelim_drm_i915_gem_memory_class_instance, memory_instance));
} // namespace NEO