Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions scripts/templates/ldrddi.cpp.mako
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,17 @@ 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)}) {
Expand Down Expand Up @@ -138,7 +146,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
Expand Down Expand Up @@ -180,7 +192,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;
Expand Down
11 changes: 8 additions & 3 deletions source/loader/ze_ldrddi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,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.zeddiInitResult != ZE_RESULT_SUCCESS) {
drv.ddiInitialized = false;
continue;
}
}
Expand Down Expand Up @@ -352,7 +353,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;
}
}
}

Expand All @@ -369,7 +374,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;
Expand Down
9 changes: 9 additions & 0 deletions source/loader/ze_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion source/loader/zes_ldrddi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
158 changes: 158 additions & 0 deletions test/init_driver_unit_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<loader::driver_t> 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<loader::driver_t> 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<loader::driver_t> 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);
}
}
Loading