Skip to content

Commit 4cbc765

Browse files
authored
fix: Handle when no L0 drivers init the global ddis (#451)
* Added handling for when a driver does not init the global ddi and leaves behind an empty ddi. * Add Unit Tests * Check ddiInit before reading init drivers * Check for pfnInit null due to zesInit possible empty ze ddi --------- Signed-off-by: Neil R. Spruit <neil.r.spruit@intel.com>
1 parent 32168a0 commit 4cbc765

5 files changed

Lines changed: 201 additions & 7 deletions

File tree

scripts/templates/ldrddi.cpp.mako

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,28 @@ namespace loader
106106
%endif
107107
if (!drv.handle || !drv.ddiInitialized) {
108108
auto res = loader::context->init_driver( drv, flags, nullptr );
109-
if (res != ZE_RESULT_SUCCESS) {
109+
%if re.match(r"Init", obj['name']) and namespace == "zes":
110+
if (res != ZE_RESULT_SUCCESS || drv.zesddiInitResult != ZE_RESULT_SUCCESS) {
111+
drv.ddiInitialized = false;
110112
continue;
111113
}
114+
%else:
115+
if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
116+
drv.ddiInitialized = false;
117+
continue;
118+
}
119+
%endif
112120
}
113121
%if re.match(r"Init", obj['name']) and namespace == "zes":
114122
if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) {
115123
drv.initSysManStatus = ZE_RESULT_ERROR_UNINITIALIZED;
116124
continue;
117125
}
126+
%else:
127+
if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) {
128+
drv.initStatus = ZE_RESULT_ERROR_UNINITIALIZED;
129+
continue;
130+
}
118131
%endif
119132
%if re.match(r"Init", obj['name']) and namespace == "zes":
120133
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
138151
%if re.match(r"\w+InitDrivers$", th.make_func_name(n, tags, obj)):
139152
for( auto& drv : loader::context->zeDrivers ) {
140153
if (!drv.handle || !drv.ddiInitialized) {
141-
loader::context->init_driver( drv, 0, desc);
154+
auto res = loader::context->init_driver( drv, 0, desc);
155+
if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
156+
drv.ddiInitialized = false;
157+
continue;
158+
}
142159
}
143160
}
144161
%endif
@@ -180,7 +197,7 @@ namespace loader
180197
if(drv.initStatus != ZE_RESULT_SUCCESS || drv.initSysManStatus != ZE_RESULT_SUCCESS || !drv.ddiInitialized)
181198
continue;
182199
%else:
183-
if (!drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) {
200+
if (!drv.ddiInitialized || !drv.dditable.${n}.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)}) {
184201
%if re.match(r"\w+InitDrivers$", th.make_func_name(n, tags, obj)):
185202
drv.initDriversStatus = ${X}_RESULT_ERROR_UNINITIALIZED;
186203
result = ${X}_RESULT_ERROR_UNINITIALIZED;

source/loader/ze_ldrddi.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,15 @@ namespace loader
164164
continue;
165165
if (!drv.handle || !drv.ddiInitialized) {
166166
auto res = loader::context->init_driver( drv, flags, nullptr );
167-
if (res != ZE_RESULT_SUCCESS) {
167+
if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
168+
drv.ddiInitialized = false;
168169
continue;
169170
}
170171
}
172+
if (!drv.dditable.ze.Global.pfnInit) {
173+
drv.initStatus = ZE_RESULT_ERROR_UNINITIALIZED;
174+
continue;
175+
}
171176
drv.initStatus = drv.dditable.ze.Global.pfnInit( flags );
172177
if(drv.initStatus == ZE_RESULT_SUCCESS)
173178
atLeastOneDriverValid = true;
@@ -352,7 +357,11 @@ namespace loader
352357
uint32_t total_driver_handle_count = 0;
353358
for( auto& drv : loader::context->zeDrivers ) {
354359
if (!drv.handle || !drv.ddiInitialized) {
355-
loader::context->init_driver( drv, 0, desc);
360+
auto res = loader::context->init_driver( drv, 0, desc);
361+
if (res != ZE_RESULT_SUCCESS || drv.zeddiInitResult != ZE_RESULT_SUCCESS) {
362+
drv.ddiInitialized = false;
363+
continue;
364+
}
356365
}
357366
}
358367

@@ -369,7 +378,7 @@ namespace loader
369378

370379
for( auto& drv : loader::context->zeDrivers )
371380
{
372-
if (!drv.dditable.ze.Global.pfnInitDrivers) {
381+
if (!drv.ddiInitialized || !drv.dditable.ze.Global.pfnInitDrivers) {
373382
drv.initDriversStatus = ZE_RESULT_ERROR_UNINITIALIZED;
374383
result = ZE_RESULT_ERROR_UNINITIALIZED;
375384
continue;

source/loader/ze_loader.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,15 @@ namespace loader
565565
} else {
566566
driver.zerddiInitResult = ZE_RESULT_SUCCESS;
567567
}
568+
569+
if (driver.zeddiInitResult != ZE_RESULT_SUCCESS && driver.zesddiInitResult != ZE_RESULT_SUCCESS) {
570+
if (debugTraceEnabled) {
571+
std::string message = "init driver " + driver.name + " failed to initialize both core and sysman DDIs, skipping driver.";
572+
debug_trace_message(message, "");
573+
}
574+
return ZE_RESULT_ERROR_UNINITIALIZED;
575+
}
576+
568577
driver.ddiInitialized = true;
569578
}
570579

source/loader/zes_ldrddi.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ namespace loader
146146
continue;
147147
if (!drv.handle || !drv.ddiInitialized) {
148148
auto res = loader::context->init_driver( drv, flags, nullptr );
149-
if (res != ZE_RESULT_SUCCESS) {
149+
if (res != ZE_RESULT_SUCCESS || drv.zesddiInitResult != ZE_RESULT_SUCCESS) {
150+
drv.ddiInitialized = false;
150151
continue;
151152
}
152153
}

test/init_driver_unit_tests.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,161 @@ TEST_F(InitDriverUnitTest, InitWithUnsupportedNullDriverType) {
134134
EXPECT_NE(result, ZE_RESULT_SUCCESS);
135135
EXPECT_FALSE(otherDriver.ddiInitialized);
136136
}
137+
138+
// ---------------------------------------------------------------------------
139+
// Tests: no DDI tables initialized — zeInit context (flags, no desc)
140+
// ---------------------------------------------------------------------------
141+
142+
// Simulates zeInit(ZE_INIT_FLAG_GPU_ONLY) when only an NPU driver is present.
143+
// The type mismatch means init_driver never loads the library, so every DDI
144+
// init-result field must remain at its initial ZE_RESULT_ERROR_UNINITIALIZED.
145+
TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenGPUFlagOnlyAndNPUDriver) {
146+
loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU);
147+
ze_result_t result = loader::context->init_driver(npuDriver, ZE_INIT_FLAG_GPU_ONLY, nullptr);
148+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
149+
EXPECT_FALSE(npuDriver.ddiInitialized);
150+
EXPECT_EQ(npuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
151+
EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
152+
EXPECT_EQ(npuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
153+
EXPECT_EQ(npuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
154+
}
155+
156+
// Simulates zeInit(ZE_INIT_FLAG_VPU_ONLY) when only a GPU driver is present.
157+
TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenVPUFlagOnlyAndGPUDriver) {
158+
loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU);
159+
ze_result_t result = loader::context->init_driver(gpuDriver, ZE_INIT_FLAG_VPU_ONLY, nullptr);
160+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
161+
EXPECT_FALSE(gpuDriver.ddiInitialized);
162+
EXPECT_EQ(gpuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
163+
EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
164+
EXPECT_EQ(gpuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
165+
EXPECT_EQ(gpuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
166+
}
167+
168+
// Simulates zeInit(0) (all-types) when only an OTHER-type driver is present;
169+
// OTHER is not matched by the default flags path, so DDI tables stay empty.
170+
TEST_F(InitDriverUnitTest, zeInit_NoDDITablesInitialized_WhenAllFlagsAndOtherTypeDriver) {
171+
loader::driver_t otherDriver = createNullDriver("ze_fake_other", loader::ZEL_DRIVER_TYPE_OTHER);
172+
ze_result_t result = loader::context->init_driver(otherDriver, 0, nullptr);
173+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
174+
EXPECT_FALSE(otherDriver.ddiInitialized);
175+
EXPECT_EQ(otherDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
176+
EXPECT_EQ(otherDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
177+
EXPECT_EQ(otherDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
178+
EXPECT_EQ(otherDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
179+
}
180+
181+
// Multiple drivers all fail type matching under a zeInit(GPU-only) call.
182+
TEST_F(InitDriverUnitTest, zeInit_AllDDITablesUninitialized_WhenNoDriverTypeMatchesGPUFlag) {
183+
std::vector<loader::driver_t> drivers = {
184+
createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU),
185+
createNullDriver("ze_fake_npu2", loader::ZEL_DRIVER_TYPE_NPU),
186+
};
187+
for (auto& driver : drivers) {
188+
ze_result_t result = loader::context->init_driver(driver, ZE_INIT_FLAG_GPU_ONLY, nullptr);
189+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
190+
EXPECT_FALSE(driver.ddiInitialized);
191+
EXPECT_EQ(driver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
192+
EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
193+
EXPECT_EQ(driver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
194+
EXPECT_EQ(driver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
195+
}
196+
}
197+
198+
// ---------------------------------------------------------------------------
199+
// Tests: no DDI tables initialized — zeInitDrivers context (desc, no flags)
200+
// ---------------------------------------------------------------------------
201+
202+
// Simulates zeInitDrivers(GPU) when only an NPU driver is present.
203+
TEST_F(InitDriverUnitTest, zeInitDrivers_NoDDITablesInitialized_WhenGPUDescAndNPUDriver) {
204+
loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU);
205+
ze_init_driver_type_desc_t desc = {};
206+
desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;
207+
ze_result_t result = loader::context->init_driver(npuDriver, 0, &desc);
208+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
209+
EXPECT_FALSE(npuDriver.ddiInitialized);
210+
EXPECT_EQ(npuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
211+
EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
212+
EXPECT_EQ(npuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
213+
EXPECT_EQ(npuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
214+
}
215+
216+
// Simulates zeInitDrivers(NPU) when only a discrete GPU driver is present.
217+
TEST_F(InitDriverUnitTest, zeInitDrivers_NoDDITablesInitialized_WhenNPUDescAndGPUDriver) {
218+
loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU);
219+
ze_init_driver_type_desc_t desc = {};
220+
desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU;
221+
ze_result_t result = loader::context->init_driver(gpuDriver, 0, &desc);
222+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
223+
EXPECT_FALSE(gpuDriver.ddiInitialized);
224+
EXPECT_EQ(gpuDriver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
225+
EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
226+
EXPECT_EQ(gpuDriver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
227+
EXPECT_EQ(gpuDriver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
228+
}
229+
230+
// Multiple GPU and NPU drivers all fail when the desc requests the opposite type.
231+
TEST_F(InitDriverUnitTest, zeInitDrivers_AllDDITablesUninitialized_WhenNoDriverTypeMatchesDesc) {
232+
std::vector<loader::driver_t> drivers = {
233+
createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU),
234+
createNullDriver("ze_fake_igpu", loader::ZEL_DRIVER_TYPE_INTEGRATED_GPU),
235+
};
236+
ze_init_driver_type_desc_t desc = {};
237+
desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU; // No GPU drivers should match
238+
for (auto& driver : drivers) {
239+
ze_result_t result = loader::context->init_driver(driver, 0, &desc);
240+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
241+
EXPECT_FALSE(driver.ddiInitialized);
242+
EXPECT_EQ(driver.zeddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
243+
EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
244+
EXPECT_EQ(driver.zetddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
245+
EXPECT_EQ(driver.zerddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
246+
}
247+
}
248+
249+
// ---------------------------------------------------------------------------
250+
// Tests: no DDI tables initialized — zesInit context (sysman DDI status)
251+
// ---------------------------------------------------------------------------
252+
253+
// Simulates the zesInit path: a driver whose type does not match the requested
254+
// flags never has its sysman DDI table populated. zesddiInitResult must stay
255+
// at ZE_RESULT_ERROR_UNINITIALIZED and ddiInitialized must remain false so
256+
// that the zesInit intercept correctly skips the driver.
257+
TEST_F(InitDriverUnitTest, zesInit_SysmanDDINotInitialized_WhenDriverTypeDoesNotMatchFlags) {
258+
loader::driver_t gpuDriver = createNullDriver("ze_fake_gpu", loader::ZEL_DRIVER_TYPE_DISCRETE_GPU);
259+
ze_init_driver_type_desc_t desc = {};
260+
desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_NPU; // GPU driver will not match
261+
ze_result_t result = loader::context->init_driver(gpuDriver, 0, &desc);
262+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
263+
// ddiInitialized == false causes the zesInit intercept to skip this driver
264+
EXPECT_FALSE(gpuDriver.ddiInitialized);
265+
// The sysman DDI result must be untouched since the library was never loaded
266+
EXPECT_EQ(gpuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
267+
}
268+
269+
// Same check for NPU driver when only GPU is requested (covers the symmetric case).
270+
TEST_F(InitDriverUnitTest, zesInit_SysmanDDINotInitialized_WhenNPUDriverAndGPUFlagOnly) {
271+
loader::driver_t npuDriver = createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU);
272+
ze_result_t result = loader::context->init_driver(npuDriver, ZE_INIT_FLAG_GPU_ONLY, nullptr);
273+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
274+
EXPECT_FALSE(npuDriver.ddiInitialized);
275+
EXPECT_EQ(npuDriver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
276+
}
277+
278+
// All drivers in a mixed pool leave zesddiInitResult unset when none of them
279+
// match the zeInitDrivers(GPU) descriptor, confirming the zesInit intercept
280+
// would find no usable sysman DDI tables.
281+
TEST_F(InitDriverUnitTest, zesInit_AllSysmanDDITablesUninitialized_WhenNoDriverMatchesDesc) {
282+
std::vector<loader::driver_t> drivers = {
283+
createNullDriver("ze_fake_npu", loader::ZEL_DRIVER_TYPE_NPU),
284+
createNullDriver("ze_fake_npu2", loader::ZEL_DRIVER_TYPE_NPU),
285+
};
286+
ze_init_driver_type_desc_t desc = {};
287+
desc.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;
288+
for (auto& driver : drivers) {
289+
ze_result_t result = loader::context->init_driver(driver, 0, &desc);
290+
EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED);
291+
EXPECT_FALSE(driver.ddiInitialized);
292+
EXPECT_EQ(driver.zesddiInitResult, ZE_RESULT_ERROR_UNINITIALIZED);
293+
}
294+
}

0 commit comments

Comments
 (0)