From 8b0a42bff44fab0baa2479abc4ff25a302e5247f Mon Sep 17 00:00:00 2001 From: John Falkowski Date: Wed, 10 Dec 2025 21:45:41 +0000 Subject: [PATCH] fix: Modify VM_UNBIND to support EU debugger for shared system USM Resolves: NEO-16798 Signed-off-by: John Falkowski --- .../os_interface/linux/xe/ioctl_helper_xe.cpp | 68 ++++++-- .../linux/xe/ioctl_helper_xe_tests.cpp | 146 ++++++++++++++++++ 2 files changed, 198 insertions(+), 16 deletions(-) diff --git a/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp b/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp index a8343b6218..d9423c14ea 100644 --- a/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp +++ b/shared/source/os_interface/linux/xe/ioctl_helper_xe.cpp @@ -106,6 +106,14 @@ std::string IoctlHelperXe::xeGetBindFlagNames(int bindFlags) { bindFlags &= ~DRM_XE_VM_BIND_FLAG_DUMPABLE; flags += "DUMPABLE "; } + if (bindFlags & DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR) { + bindFlags &= ~DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR; + flags += "CPU_ADDR_MIRROR "; + } + if (bindFlags & DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET) { + bindFlags &= ~DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET; + flags += "MADVISE_AUTORESET "; + } if (bindFlags != 0) { flags += "Unknown flag "; @@ -1585,6 +1593,7 @@ int IoctlHelperXe::xeVmBind(const VmBindParams &vmBindParams, bool isBind) { } drm_xe_vm_bind bind = {}; + drm_xe_vm_bind_op bindOps[2] = {}; bind.vm_id = vmBindParams.vmId; bind.num_binds = 1; @@ -1627,10 +1636,15 @@ int IoctlHelperXe::xeVmBind(const VmBindParams &vmBindParams, bool isBind) { bind.bind.obj_offset = userptr; } } else { - if (vmBindParams.sharedSystemUsmEnabled) { + if ((vmBindParams.sharedSystemUsmEnabled) && ((bind.bind.addr + bind.bind.range) <= drm.getSharedSystemAllocAddressRange())) { // Use of MAP on unbind required for restoring the address space to the system allocator - bind.bind.op = DRM_XE_VM_BIND_OP_MAP; - bind.bind.flags |= DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR; + memcpy(&bindOps[0], &bind.bind, sizeof(drm_xe_vm_bind_op)); + memcpy(&bindOps[1], &bind.bind, sizeof(drm_xe_vm_bind_op)); + bindOps[0].op = DRM_XE_VM_BIND_OP_UNMAP; + bindOps[1].op = DRM_XE_VM_BIND_OP_MAP; + bindOps[1].flags |= DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR; + bind.num_binds = 2; + bind.vector_of_binds = (uintptr_t)bindOps; } else { bind.bind.op = DRM_XE_VM_BIND_OP_UNMAP; if (userptr) { @@ -1642,19 +1656,41 @@ int IoctlHelperXe::xeVmBind(const VmBindParams &vmBindParams, bool isBind) { ret = IoctlHelper::ioctl(DrmIoctl::gemVmBind, &bind); - XELOG(" vm=%d obj=0x%x off=0x%llx range=0x%llx addr=0x%llx operation=%d(%s) flags=%d(%s) nsy=%d pat=%hu ret=%d\n", - bind.vm_id, - bind.bind.obj, - bind.bind.obj_offset, - bind.bind.range, - bind.bind.addr, - bind.bind.op, - xeGetBindOperationName(bind.bind.op), - bind.bind.flags, - xeGetBindFlagNames(bind.bind.flags).c_str(), - bind.num_syncs, - bind.bind.pat_index, - ret); + if (bind.num_binds == 1) { + XELOG(" vm=%d obj=0x%x off=0x%llx range=0x%llx addr=0x%llx operation=%d(%s) flags=%d(%s) nsy=%d num_bind=%d pat=%hu ret=%d\n", + bind.vm_id, + bind.bind.obj, + bind.bind.obj_offset, + bind.bind.range, + bind.bind.addr, + bind.bind.op, + xeGetBindOperationName(bind.bind.op), + bind.bind.flags, + xeGetBindFlagNames(bind.bind.flags).c_str(), + bind.num_syncs, + bind.num_binds, + bind.bind.pat_index, + ret); + } else if (bind.num_binds == 2) { + XELOG(" vm=%d obj=0x%x off=0x%llx range=0x%llx addr=0x%llx operation[0]=%d(%s) flags[0]=%d(%s) operation[1]=%d(%s) flags[1]=%d(%s) nsy=%d num_bind=%d pat=%hu ret=%d\n", + bind.vm_id, + bind.bind.obj, + bind.bind.obj_offset, + bind.bind.range, + bind.bind.addr, + bindOps[0].op, + xeGetBindOperationName(bindOps[0].op), + bindOps[0].flags, + xeGetBindFlagNames(bindOps[0].flags).c_str(), + bindOps[1].op, + xeGetBindOperationName(bindOps[1].op), + bindOps[1].flags, + xeGetBindFlagNames(bindOps[1].flags).c_str(), + bind.num_syncs, + bind.num_binds, + bind.bind.pat_index, + ret); + } if (ret != 0) { XELOG("error: %s\n", operation); diff --git a/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp b/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp index c4b72075d8..ee16ec5447 100644 --- a/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/xe/ioctl_helper_xe_tests.cpp @@ -2257,6 +2257,152 @@ TEST_F(IoctlHelperXeTest, whenCallingVmUnbindThenPatIndexIsSetToDefault) { EXPECT_EQ(drm->vmBindInputs[0].bind.pat_index, defaultPatIndex); } +TEST_F(IoctlHelperXeTest, whenCallingVmUnbindAndSharedSystemUsmDisabledThenOneBindOps) { + DebugManagerStateRestore restorer; + auto executionEnvironment = std::make_unique(); + auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]); + auto xeIoctlHelper = static_cast(drm->getIoctlHelper()); + + uint64_t fenceAddress = 0x4321; + uint64_t fenceValue = 0x789; + + VmBindExtUserFenceT vmBindExtUserFence{}; + + xeIoctlHelper->fillVmBindExtUserFence(vmBindExtUserFence, fenceAddress, fenceValue, 0u); + + VmBindParams vmBindParams{}; + vmBindParams.handle = 0x1234; + vmBindParams.start = 0x0; + vmBindParams.length = 0x0; + vmBindParams.sharedSystemUsmEnabled = false; + xeIoctlHelper->setVmBindUserFence(vmBindParams, vmBindExtUserFence); + + drm->vmBindInputs.clear(); + drm->syncInputs.clear(); + drm->waitUserFenceInputs.clear(); + + StreamCapture capture; + capture.captureStderr(); + + debugManager.flags.PrintXeLogs.set(true); + ASSERT_EQ(0, xeIoctlHelper->vmUnbind(vmBindParams)); + debugManager.flags.PrintXeLogs.set(false); + std::string output = capture.getCapturedStderr(); + std::string expectedOutput = "vm=0 obj=0x0 off=0x0 range=0x0 addr=0x0 operation=1(UNMAP) flags=0() nsy=1 num_bind=1"; + EXPECT_NE(std::string::npos, output.find(expectedOutput)); + EXPECT_EQ(drm->vmBindInputs[0].num_binds, 1u); + EXPECT_EQ(drm->vmBindInputs[0].vector_of_binds, 0u); +} + +TEST_F(IoctlHelperXeTest, whenCallingVmUnbindAndSharedSystemAddressRangeExceededThenOneBindOps) { + DebugManagerStateRestore restorer; + auto executionEnvironment = std::make_unique(); + auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]); + auto xeIoctlHelper = static_cast(drm->getIoctlHelper()); + + uint64_t fenceAddress = 0x4321; + uint64_t fenceValue = 0x789; + + VmBindExtUserFenceT vmBindExtUserFence{}; + + xeIoctlHelper->fillVmBindExtUserFence(vmBindExtUserFence, fenceAddress, fenceValue, 0u); + + VmBindParams vmBindParams{}; + vmBindParams.handle = 0x1234; + vmBindParams.sharedSystemUsmEnabled = true; + vmBindParams.start = 0x1000; + vmBindParams.length = 0x1000; + xeIoctlHelper->setVmBindUserFence(vmBindParams, vmBindExtUserFence); + + drm->vmBindInputs.clear(); + drm->syncInputs.clear(); + drm->waitUserFenceInputs.clear(); + + StreamCapture capture; + capture.captureStderr(); + + debugManager.flags.PrintXeLogs.set(true); + ASSERT_EQ(0, xeIoctlHelper->vmUnbind(vmBindParams)); + debugManager.flags.PrintXeLogs.set(false); + std::string output = capture.getCapturedStderr(); + std::string expectedOutput = "vm=0 obj=0x0 off=0x0 range=0x1000 addr=0x1000 operation=1(UNMAP) flags=0() nsy=1 num_bind=1"; + EXPECT_NE(std::string::npos, output.find(expectedOutput)); + EXPECT_EQ(drm->vmBindInputs[0].num_binds, 1u); + EXPECT_EQ(drm->vmBindInputs[0].vector_of_binds, 0u); +} + +TEST_F(IoctlHelperXeTest, whenCallingVmUnbindAndSharedSystemUsmEnabledThenTwoBindOps) { + DebugManagerStateRestore restorer; + auto executionEnvironment = std::make_unique(); + auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]); + auto xeIoctlHelper = static_cast(drm->getIoctlHelper()); + + uint64_t fenceAddress = 0x4321; + uint64_t fenceValue = 0x789; + + VmBindExtUserFenceT vmBindExtUserFence{}; + + xeIoctlHelper->fillVmBindExtUserFence(vmBindExtUserFence, fenceAddress, fenceValue, 0u); + + VmBindParams vmBindParams{}; + vmBindParams.handle = 0x1234; + vmBindParams.sharedSystemUsmEnabled = true; + vmBindParams.start = 0x0; + vmBindParams.length = 0x0; + xeIoctlHelper->setVmBindUserFence(vmBindParams, vmBindExtUserFence); + + drm->vmBindInputs.clear(); + drm->syncInputs.clear(); + drm->waitUserFenceInputs.clear(); + + StreamCapture capture; + capture.captureStderr(); + + debugManager.flags.PrintXeLogs.set(true); + ASSERT_EQ(0, xeIoctlHelper->vmUnbind(vmBindParams)); + debugManager.flags.PrintXeLogs.set(false); + std::string output = capture.getCapturedStderr(); + std::string expectedOutput = "vm=0 obj=0x0 off=0x0 range=0x0 addr=0x0 operation[0]=1(UNMAP) flags[0]=0() operation[1]=0(MAP) flags[1]=32(CPU_ADDR_MIRROR) nsy=1 num_bind=2"; + EXPECT_NE(std::string::npos, output.find(expectedOutput)); + EXPECT_EQ(drm->vmBindInputs[0].num_binds, 2u); + EXPECT_NE(drm->vmBindInputs[0].vector_of_binds, 0u); +} + +TEST_F(IoctlHelperXeTest, whenCallingVmbBindWithMadviseAutoResetFlagThenVerifyXeLog) { + DebugManagerStateRestore restorer; + auto executionEnvironment = std::make_unique(); + auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]); + auto xeIoctlHelper = static_cast(drm->getIoctlHelper()); + + uint64_t fenceAddress = 0x4321; + uint64_t fenceValue = 0x789; + + VmBindExtUserFenceT vmBindExtUserFence{}; + + xeIoctlHelper->fillVmBindExtUserFence(vmBindExtUserFence, fenceAddress, fenceValue, 0u); + + VmBindParams vmBindParams{}; + vmBindParams.flags = DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR | DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET; + vmBindParams.handle = 0x1234; + xeIoctlHelper->setVmBindUserFence(vmBindParams, vmBindExtUserFence); + + drm->vmBindInputs.clear(); + drm->syncInputs.clear(); + drm->waitUserFenceInputs.clear(); + + StreamCapture capture; + capture.captureStderr(); + + debugManager.flags.PrintXeLogs.set(true); + ASSERT_EQ(0, xeIoctlHelper->vmBind(vmBindParams)); + debugManager.flags.PrintXeLogs.set(false); + std::string output = capture.getCapturedStderr(); + std::string expectedOutput = "vm=0 obj=0x1234 off=0x0 range=0x0 addr=0x0 operation=0(MAP) flags=96(CPU_ADDR_MIRROR MADVISE_AUTORESET) nsy=1 num_bind=1"; + EXPECT_NE(std::string::npos, output.find(expectedOutput)); + EXPECT_EQ(drm->vmBindInputs[0].num_binds, 1u); + EXPECT_EQ(drm->vmBindInputs[0].vector_of_binds, 0u); +} + TEST_F(IoctlHelperXeTest, whenBindingDrmContextWithoutVirtualEnginesThenProperEnginesAreSelected) { auto executionEnvironment = std::make_unique(); auto drm = DrmMockXe::create(*executionEnvironment->rootDeviceEnvironments[0]);