diff --git a/scripts/templates/ldrddi.cpp.mako b/scripts/templates/ldrddi.cpp.mako index 96597b34..1d64f345 100644 --- a/scripts/templates/ldrddi.cpp.mako +++ b/scripts/templates/ldrddi.cpp.mako @@ -106,15 +106,28 @@ namespace loader %endif if (!drv.handle || !drv.ddiInitialized) { auto res = loader::context->init_driver( drv, flags, nullptr ); - if (res != ZE_RESULT_SUCCESS) { + %if re.match(r"Init", obj['name']) and namespace == "zes": + if (res != ZE_RESULT_SUCCESS || drv.zesddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; continue; } + %else: + if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; + continue; + } + %endif } %if re.match(r"Init", obj['name']) and namespace == "zes": if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) { drv.initSysManStatus = ZE_RESULT_ERROR_UNINITIALIZED; continue; } + %else: + if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) { + drv.initStatus = ZE_RESULT_ERROR_UNINITIALIZED; + continue; + } %endif %if re.match(r"Init", obj['name']) and namespace == "zes": drv.initSysManStatus = drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}( ${", ".join(th.make_param_lines(n, tags, obj, format=["name"]))} ); @@ -138,7 +151,11 @@ namespace loader %if re.match(r"\w+InitDrivers$", th.make_func_name(n, tags, obj)): for( auto& drv : loader::context->zeDrivers ) { if (!drv.handle || !drv.ddiInitialized) { - loader::context->init_driver( drv, 0, desc); + auto res = loader::context->init_driver( drv, 0, desc); + if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; + continue; + } } } %endif @@ -180,7 +197,7 @@ namespace loader if(drv.initStatus != ZE_RESULT_SUCCESS || drv.initSysManStatus != ZE_RESULT_SUCCESS || !drv.ddiInitialized) continue; %else: - if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) { + if (!drv.ddiInitialized || !drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) { %if re.match(r"\w+InitDrivers$", th.make_func_name(n, tags, obj)): drv.initDriversStatus = ${X}_RESULT_ERROR_UNINITIALIZED; result = ${X}_RESULT_ERROR_UNINITIALIZED; diff --git a/source/loader/ze_ldrddi.cpp b/source/loader/ze_ldrddi.cpp index 3f5b0d84..e3959a9c 100644 --- a/source/loader/ze_ldrddi.cpp +++ b/source/loader/ze_ldrddi.cpp @@ -164,10 +164,15 @@ namespace loader continue; if (!drv.handle || !drv.ddiInitialized) { auto res = loader::context->init_driver( drv, flags, nullptr ); - if (res != ZE_RESULT_SUCCESS) { + if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; continue; } } + if (!drv.dditable.ze.Global.pfnInit) { + drv.initStatus = ZE_RESULT_ERROR_UNINITIALIZED; + continue; + } drv.initStatus = drv.dditable.ze.Global.pfnInit( flags ); if(drv.initStatus == ZE_RESULT_SUCCESS) atLeastOneDriverValid = true; @@ -352,7 +357,11 @@ namespace loader uint32_t total_driver_handle_count = 0; for( auto& drv : loader::context->zeDrivers ) { if (!drv.handle || !drv.ddiInitialized) { - loader::context->init_driver( drv, 0, desc); + auto res = loader::context->init_driver( drv, 0, desc); + if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; + continue; + } } } @@ -369,7 +378,7 @@ namespace loader for( auto& drv : loader::context->zeDrivers ) { - if (!drv.dditable.ze.Global.pfnInitDrivers) { + if (!drv.ddiInitialized || !drv.dditable.ze.Global.pfnInitDrivers) { drv.initDriversStatus = ZE_RESULT_ERROR_UNINITIALIZED; result = ZE_RESULT_ERROR_UNINITIALIZED; continue; diff --git a/source/loader/ze_loader.cpp b/source/loader/ze_loader.cpp index b1d221b3..f57becd0 100644 --- a/source/loader/ze_loader.cpp +++ b/source/loader/ze_loader.cpp @@ -565,6 +565,15 @@ namespace loader } else { driver.zerddiInitResult = ZE_RESULT_SUCCESS; } + + if (driver.zeddiInitResult != ZE_RESULT_SUCCESS && driver.zesddiInitResult != ZE_RESULT_SUCCESS) { + if (debugTraceEnabled) { + std::string message = "init driver " + driver.name + " failed to initialize both core and sysman DDIs, skipping driver."; + debug_trace_message(message, ""); + } + return ZE_RESULT_ERROR_UNINITIALIZED; + } + driver.ddiInitialized = true; } diff --git a/source/loader/zes_ldrddi.cpp b/source/loader/zes_ldrddi.cpp index 29707f9b..2c2c1ef1 100644 --- a/source/loader/zes_ldrddi.cpp +++ b/source/loader/zes_ldrddi.cpp @@ -146,7 +146,8 @@ namespace loader continue; if (!drv.handle || !drv.ddiInitialized) { auto res = loader::context->init_driver( drv, flags, nullptr ); - if (res != ZE_RESULT_SUCCESS) { + if (res != ZE_RESULT_SUCCESS || drv.zesddiInitResult != ZE_RESULT_SUCCESS) { + drv.ddiInitialized = false; continue; } } diff --git a/test/init_driver_unit_tests.cpp b/test/init_driver_unit_tests.cpp index cbe76d37..93dc767d 100644 --- a/test/init_driver_unit_tests.cpp +++ b/test/init_driver_unit_tests.cpp @@ -134,3 +134,161 @@ TEST_F(InitDriverUnitTest, InitWithUnsupportedNullDriverType) { EXPECT_NE(result, ZE_RESULT_SUCCESS); EXPECT_FALSE(otherDriver.ddiInitialized); } + +// --------------------------------------------------------------------------- +// Tests: no DDI tables initialized — zeInit context (flags, no desc) +// --------------------------------------------------------------------------- + +// Simulates zeInit(ZE_INIT_FLAG_GPU_ONLY) when only an NPU driver is present. +// The type mismatch means init_driver never loads the library, so every DDI +// init-result field must remain at its initial ZE_RESULT_ERROR_UNINITIALIZED. +TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenGPUFlagOnlyAndNPUDriver) { + loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU); + ze_result_t result = loader::context->init_driver(npuDriver, ZE_INIT_FLAG_GPU_ONLY, nullptr); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(npuDriver.ddiInitialized); + EXPECT_EQ(npuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Simulates zeInit(ZE_INIT_FLAG_VPU_ONLY) when only a GPU driver is present. +TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenVPUFlagOnlyAndGPUDriver) { + loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU); + ze_result_t result = loader::context->init_driver(gpuDriver, ZE_INIT_FLAG_VPU_ONLY, nullptr); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(gpuDriver.ddiInitialized); + EXPECT_EQ(gpuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Simulates zeInit(0) (all-types) when only an OTHER-type driver is present; +// OTHER is not matched by the default flags path, so DDI tables stay empty. +TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenAllFlagsAndOtherTypeDriver) { + loader::driver_t otherDriver = createNullDriver("ze_fake_other", loader::ZEL_DRIVER_TYPE_OTHER); + ze_result_t result = loader::context->init_driver(otherDriver, 0, nullptr); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(otherDriver.ddiInitialized); + EXPECT_EQ(otherDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(otherDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(otherDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(otherDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Multiple drivers all fail type matching under a zeInit(GPU-only) call. +TEST_F(InitDriverUnitTest, zeInit_AllDDITablesUninitialized_WhenNoDriverTypeMatchesGPUFlag) { + std::vector drivers = { + createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU), + createNullDriver("ze_fake_npu2", loader::ZEL_DRIVER_TYPE_NPU), + }; + for (auto& driver : drivers) { + ze_result_t result = loader::context->init_driver(driver, ZE_INIT_FLAG_GPU_ONLY, nullptr); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(driver.ddiInitialized); + EXPECT_EQ(driver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + } +} + +// --------------------------------------------------------------------------- +// Tests: no DDI tables initialized — zeInitDrivers context (desc, no flags) +// --------------------------------------------------------------------------- + +// Simulates zeInitDrivers(GPU) when only an NPU driver is present. +TEST_F(InitDriverUnitTest, zeInitDrivers_NoDDITablesInitialized_WhenGPUDescAndNPUDriver) { + loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU); + ze_init_driver_type_desc_t desc = {}; + desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU; + ze_result_t result = loader::context->init_driver(npuDriver, 0, &desc); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(npuDriver.ddiInitialized); + EXPECT_EQ(npuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(npuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Simulates zeInitDrivers(NPU) when only a discrete GPU driver is present. +TEST_F(InitDriverUnitTest, zeInitDrivers_NoDDITablesInitialized_WhenNPUDescAndGPUDriver) { + loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU); + ze_init_driver_type_desc_t desc = {}; + desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU; + ze_result_t result = loader::context->init_driver(gpuDriver, 0, &desc); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(gpuDriver.ddiInitialized); + EXPECT_EQ(gpuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(gpuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Multiple GPU and NPU drivers all fail when the desc requests the opposite type. +TEST_F(InitDriverUnitTest, zeInitDrivers_AllDDITablesUninitialized_WhenNoDriverTypeMatchesDesc) { + std::vector drivers = { + createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU), + createNullDriver("ze_fake_igpu", loader::ZEL_DRIVER_TYPE_INTEGRATED_GPU), + }; + ze_init_driver_type_desc_t desc = {}; + desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU; // No GPU drivers should match + for (auto& driver : drivers) { + ze_result_t result = loader::context->init_driver(driver, 0, &desc); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(driver.ddiInitialized); + EXPECT_EQ(driver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_EQ(driver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + } +} + +// --------------------------------------------------------------------------- +// Tests: no DDI tables initialized — zesInit context (sysman DDI status) +// --------------------------------------------------------------------------- + +// Simulates the zesInit path: a driver whose type does not match the requested +// flags never has its sysman DDI table populated. zesddiInitResult must stay +// at ZE_RESULT_ERROR_UNINITIALIZED and ddiInitialized must remain false so +// that the zesInit intercept correctly skips the driver. +TEST_F(InitDriverUnitTest, zesInit_SysmanDDINotInitialized_WhenDriverTypeDoesNotMatchFlags) { + loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU); + ze_init_driver_type_desc_t desc = {}; + desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU; // GPU driver will not match + ze_result_t result = loader::context->init_driver(gpuDriver, 0, &desc); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + // ddiInitialized == false causes the zesInit intercept to skip this driver + EXPECT_FALSE(gpuDriver.ddiInitialized); + // The sysman DDI result must be untouched since the library was never loaded + EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// Same check for NPU driver when only GPU is requested (covers the symmetric case). +TEST_F(InitDriverUnitTest, zesInit_SysmanDDINotInitialized_WhenNPUDriverAndGPUFlagOnly) { + loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU); + ze_result_t result = loader::context->init_driver(npuDriver, ZE_INIT_FLAG_GPU_ONLY, nullptr); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(npuDriver.ddiInitialized); + EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); +} + +// All drivers in a mixed pool leave zesddiInitResult unset when none of them +// match the zeInitDrivers(GPU) descriptor, confirming the zesInit intercept +// would find no usable sysman DDI tables. +TEST_F(InitDriverUnitTest, zesInit_AllSysmanDDITablesUninitialized_WhenNoDriverMatchesDesc) { + std::vector drivers = { + createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU), + createNullDriver("ze_fake_npu2", loader::ZEL_DRIVER_TYPE_NPU), + }; + ze_init_driver_type_desc_t desc = {}; + desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU; + for (auto& driver : drivers) { + ze_result_t result = loader::context->init_driver(driver, 0, &desc); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); + EXPECT_FALSE(driver.ddiInitialized); + EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED); + } +}