diff --git a/shared/source/os_interface/linux/drm_neo.cpp b/shared/source/os_interface/linux/drm_neo.cpp index bda12f228a..539a3ee4f6 100644 --- a/shared/source/os_interface/linux/drm_neo.cpp +++ b/shared/source/os_interface/linux/drm_neo.cpp @@ -60,7 +60,7 @@ void Drm::queryAndSetVmBindPatIndexProgrammingSupport() { int Drm::ioctl(DrmIoctl request, void *arg) { auto requestValue = getIoctlRequestValue(request, ioctlHelper.get()); int ret; - int returnedErrno; + int returnedErrno = 0; SYSTEM_ENTER(); do { auto measureTime = DebugManager.flags.PrintIoctlTimes.get(); @@ -78,7 +78,9 @@ int Drm::ioctl(DrmIoctl request, void *arg) { } ret = SysCalls::ioctl(getFileDescriptor(), requestValue, arg); - returnedErrno = errno; + if (ret != 0) { + returnedErrno = getErrno(); + } if (measureTime) { end = std::chrono::steady_clock::now(); @@ -108,7 +110,7 @@ int Drm::ioctl(DrmIoctl request, void *arg) { } } - } while (ret == -1 && (returnedErrno == EINTR || returnedErrno == EAGAIN || returnedErrno == EBUSY || returnedErrno == -EBUSY)); + } while (ret == -1 && checkIfIoctlReinvokeRequired(returnedErrno, request, ioctlHelper.get())); SYSTEM_LEAVE(request); return ret; } diff --git a/shared/source/os_interface/linux/drm_wrappers.cpp b/shared/source/os_interface/linux/drm_wrappers.cpp index 07c668ba24..4e18f1490b 100644 --- a/shared/source/os_interface/linux/drm_wrappers.cpp +++ b/shared/source/os_interface/linux/drm_wrappers.cpp @@ -29,6 +29,13 @@ unsigned int getIoctlRequestValue(DrmIoctl ioctlRequest, IoctlHelper *ioctlHelpe } } +bool checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest, IoctlHelper *ioctlHelper) { + if (ioctlHelper) { + return ioctlHelper->checkIfIoctlReinvokeRequired(error, ioctlRequest); + } + return (error == EINTR || error == EAGAIN || error == EBUSY || error == -EBUSY); +} + int getDrmParamValue(DrmParam drmParam, IoctlHelper *ioctlHelper) { if (ioctlHelper) { return ioctlHelper->getDrmParamValue(drmParam); diff --git a/shared/source/os_interface/linux/drm_wrappers.h b/shared/source/os_interface/linux/drm_wrappers.h index 7459b2b366..2ccfc930c1 100644 --- a/shared/source/os_interface/linux/drm_wrappers.h +++ b/shared/source/os_interface/linux/drm_wrappers.h @@ -207,6 +207,14 @@ struct DrmVersion { char *desc; }; +struct DrmDebuggerOpen { + uint64_t pid; + uint32_t flags; + uint32_t version; + uint64_t events; + uint64_t extensions; +}; + enum class DrmIoctl { GemExecbuffer2, GemWait, @@ -299,5 +307,6 @@ unsigned int getIoctlRequestValue(DrmIoctl ioctlRequest, IoctlHelper *ioctlHelpe int getDrmParamValue(DrmParam drmParam, IoctlHelper *ioctlHelper); std::string getDrmParamString(DrmParam param, IoctlHelper *ioctlHelper); std::string getIoctlString(DrmIoctl ioctlRequest, IoctlHelper *ioctlHelper); +bool checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest, IoctlHelper *ioctlHelper); } // namespace NEO diff --git a/shared/source/os_interface/linux/ioctl_helper.cpp b/shared/source/os_interface/linux/ioctl_helper.cpp index 3f02558806..3201a751a7 100644 --- a/shared/source/os_interface/linux/ioctl_helper.cpp +++ b/shared/source/os_interface/linux/ioctl_helper.cpp @@ -369,4 +369,7 @@ std::string IoctlHelper::getFileForMaxMemoryFrequencyOfSubDevice(int subDeviceId return "/gt/gt" + std::to_string(subDeviceId) + "/mem_RP0_freq_mhz"; } +bool IoctlHelper::checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest) const { + return (error == EINTR || error == EAGAIN || error == EBUSY || error == -EBUSY); +} } // namespace NEO diff --git a/shared/source/os_interface/linux/ioctl_helper.h b/shared/source/os_interface/linux/ioctl_helper.h index 8f61d5fd03..bd8df3bc9c 100644 --- a/shared/source/os_interface/linux/ioctl_helper.h +++ b/shared/source/os_interface/linux/ioctl_helper.h @@ -114,6 +114,7 @@ class IoctlHelper { virtual std::string getDrmParamString(DrmParam param) const = 0; virtual std::string getIoctlString(DrmIoctl ioctlRequest) const = 0; + virtual bool checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest) const; virtual std::vector translateToMemoryRegions(const std::vector ®ionInfo); virtual uint32_t createDrmContext(Drm &drm, OsContextLinux &osContext, uint32_t drmVmId, uint32_t deviceIndex); @@ -254,6 +255,7 @@ class IoctlHelperPrelim20 : public IoctlHelper { int getDrmParamValue(DrmParam drmParam) const override; std::string getDrmParamString(DrmParam param) const override; std::string getIoctlString(DrmIoctl ioctlRequest) const override; + bool checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest) const override; }; } // namespace NEO diff --git a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp index c4587e613d..1d942594be 100644 --- a/shared/source/os_interface/linux/ioctl_helper_prelim.cpp +++ b/shared/source/os_interface/linux/ioctl_helper_prelim.cpp @@ -645,6 +645,16 @@ std::string IoctlHelperPrelim20::getIoctlString(DrmIoctl ioctlRequest) const { } } +bool IoctlHelperPrelim20::checkIfIoctlReinvokeRequired(int error, DrmIoctl ioctlRequest) const { + switch (ioctlRequest) { + case DrmIoctl::DebuggerOpen: + return (error == EINTR || error == EAGAIN); + default: + break; + } + return IoctlHelper::checkIfIoctlReinvokeRequired(error, ioctlRequest); +} + 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)); diff --git a/shared/test/unit_test/os_interface/linux/drm_query_prelim_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_query_prelim_tests.cpp index 3f7810ee3d..9de5cb5880 100644 --- a/shared/test/unit_test/os_interface/linux/drm_query_prelim_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_query_prelim_tests.cpp @@ -206,6 +206,68 @@ TEST(DrmQueryTest, WhenCallingIsDebugAttachAvailableThenReturnValueIsTrue) { EXPECT_TRUE(drm.isDebugAttachAvailable()); } +TEST(DrmPrelimTest, GivenDebuggerOpenIoctlWhenErrorEbusyReturnedThenErrorIsReturnedWithoutReinvokingIoctl) { + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.allowDebugAttachCallBase = true; + + VariableBackup mockIoctl(&SysCalls::sysCallsIoctl, [](int fileDescriptor, unsigned long int request, void *arg) -> int { + return -1; + }); + DrmDebuggerOpen open = {}; + open.pid = 1; + open.events = 0; + drm.context.debuggerOpenRetval = -1; + drm.errnoRetVal = EBUSY; + + auto ret = drm.Drm::ioctl(DrmIoctl::DebuggerOpen, &open); + EXPECT_EQ(-1, ret); +} + +TEST(DrmPrelimTest, GivenDebuggerOpenIoctlWhenErrorEAgainOrEIntrReturnedThenIoctlIsCalledAgain) { + auto executionEnvironment = std::make_unique(); + DrmQueryMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + drm.allowDebugAttachCallBase = true; + drm.baseErrno = false; + + DrmDebuggerOpen open = {}; + open.pid = 1; + open.events = 0; + + { + VariableBackup mockIoctl(&SysCalls::sysCallsIoctl, [](int fileDescriptor, unsigned long int request, void *arg) -> int { + static int callCount = 3; + if (callCount > 0) { + callCount--; + return -1; + } + return 0; + }); + + drm.errnoRetVal = EAGAIN; + + auto ret = drm.Drm::ioctl(DrmIoctl::DebuggerOpen, &open); + EXPECT_EQ(0, ret); + } + + { + VariableBackup mockIoctl(&SysCalls::sysCallsIoctl, [](int fileDescriptor, unsigned long int request, void *arg) -> int { + static int callCount = 3; + if (callCount > 0) { + callCount--; + return -1; + } + return 0; + }); + + drm.ioctlCallsCount = 0; + drm.errnoRetVal = EINTR; + + auto ret = drm.Drm::ioctl(DrmIoctl::DebuggerOpen, &open); + EXPECT_EQ(0, ret); + } +} + struct BufferObjectMock : public BufferObject { using BufferObject::BufferObject; using BufferObject::fillExecObject; diff --git a/shared/test/unit_test/os_interface/linux/drm_tests.cpp b/shared/test/unit_test/os_interface/linux/drm_tests.cpp index 20af5d1245..87fb7d05b9 100644 --- a/shared/test/unit_test/os_interface/linux/drm_tests.cpp +++ b/shared/test/unit_test/os_interface/linux/drm_tests.cpp @@ -1404,6 +1404,36 @@ TEST(DrmWrapperTest, WhenGettingDrmParamValueStringThenProperStringIsReturned) { EXPECT_THROW(getDrmParamString(DrmParam::EngineClassRender, &ioctlHelper), std::runtime_error); } +TEST(DrmWrapperTest, givenEAgainOrEIntrOrEBusyWhenCheckingIfReinvokeRequiredThenTrueIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + + MockIoctlHelper ioctlHelper{drm}; + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EAGAIN, DrmIoctl::Getparam, &ioctlHelper)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EINTR, DrmIoctl::Getparam, &ioctlHelper)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EBUSY, DrmIoctl::Getparam, &ioctlHelper)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(-EBUSY, DrmIoctl::Getparam, &ioctlHelper)); +} + +TEST(DrmWrapperTest, givenNoIoctlHelperAndEAgainOrEIntrOrEBusyWhenCheckingIfReinvokeRequiredThenTrueIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EAGAIN, DrmIoctl::Getparam, nullptr)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EINTR, DrmIoctl::Getparam, nullptr)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(EBUSY, DrmIoctl::Getparam, nullptr)); + EXPECT_TRUE(checkIfIoctlReinvokeRequired(-EBUSY, DrmIoctl::Getparam, nullptr)); +} + +TEST(DrmWrapperTest, givenErrorWhenCheckingIfReinvokeRequiredThenFalseIsReturned) { + auto executionEnvironment = std::make_unique(); + DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]}; + + MockIoctlHelper ioctlHelper{drm}; + EXPECT_FALSE(checkIfIoctlReinvokeRequired(ENOENT, DrmIoctl::Getparam, &ioctlHelper)); + EXPECT_FALSE(checkIfIoctlReinvokeRequired(ENOENT, DrmIoctl::Getparam, nullptr)); +} + TEST(IoctlHelperTest, whenGettingDrmParamValueThenProperValueIsReturned) { auto executionEnvironment = std::make_unique(); DrmMock drm{*executionEnvironment->rootDeviceEnvironments[0]};