Skip to content

Commit 4bfbfe1

Browse files
committed
Arm backend: implement EthosUBackend::is_available() hardware check
is_available() returned 1 unconditionally. The consequence differs by platform: - Cortex-M: if ethosu_init() was never called, execute() blocks silently inside ethosu_reserve_driver() with no error or log. - Cortex-A: if /dev/ethosu0 is absent, execute() logs a driver error but does not clearly indicate the device is unavailable. Changes: - Cortex-M: ethosu_driver_is_registered() checks registered_drivers and guarantees semaphore count is > 0, so ethosu_reserve_driver() will not block. - Cortex-A: constructs EthosU::Device to probe the default device path, which throws if the device is absent/unopenable. - ethosu_driver_is_registered() is added to the driver via patch. A weak symbol fallback covers any remaining build paths in case the patch is not applied Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
1 parent 3f0e901 commit 4bfbfe1

7 files changed

Lines changed: 111 additions & 2 deletions

File tree

backends/arm/runtime/EthosUBackend.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ class EthosUBackend final : public ::executorch::runtime::BackendInterface {
7676
~EthosUBackend() = default;
7777

7878
virtual bool is_available() const override {
79-
// TODO: revise to use a register check/init function
80-
return 1;
79+
return platform_is_available();
8180
}
8281

8382
Result<DelegateHandle*> init(

backends/arm/runtime/EthosUBackend_Cortex_A.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,23 @@ Error invoke_linux_driver(
323323
}
324324
} // namespace
325325

326+
bool platform_is_available() {
327+
// Open the NPU device driver; thrown if it is absent or unopenable.
328+
const LinuxDriverOptions defaults;
329+
try {
330+
EthosU::Device device(defaults.device_path.c_str());
331+
(void)device;
332+
return true;
333+
} catch (const std::exception& e) {
334+
ET_LOG(
335+
Info,
336+
"Ethos-U device %s not available: %s",
337+
defaults.device_path.c_str(),
338+
e.what());
339+
return false;
340+
}
341+
}
342+
326343
PlatformState* platform_init(
327344
ArrayRef<CompileSpec> specs,
328345
MemoryAllocator* allocator) {

backends/arm/runtime/EthosUBackend_Cortex_M.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ namespace arm {
5454

5555
struct PlatformState {};
5656

57+
// Weak fallback in case the patch to ethosu_driver_is_registered() is not
58+
// applied
59+
extern "C" __attribute__((weak)) bool ethosu_driver_is_registered(void) {
60+
return true;
61+
}
62+
63+
bool platform_is_available() {
64+
// Check whether ethosu_init() was called before ExecuTorch runs.
65+
// TODO: Upstream ethosu_driver_is_registered() into the core driver and
66+
// remove the weak fallback.
67+
return ethosu_driver_is_registered();
68+
}
69+
5770
PlatformState* platform_init(
5871
executorch::runtime::ArrayRef<executorch::runtime::CompileSpec> /*specs*/,
5972
executorch::runtime::MemoryAllocator* /*allocator*/) {

backends/arm/runtime/EthosUBackend_Internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ extern unsigned char* ethosu_fast_scratch;
7777
extern size_t ethosu_fast_scratch_size;
7878
}
7979

80+
// Returns whether the Ethos-U device driver is available
81+
bool platform_is_available();
82+
8083
PlatformState* platform_init(
8184
executorch::runtime::ArrayRef<executorch::runtime::CompileSpec> specs,
8285
executorch::runtime::MemoryAllocator* allocator);

backends/arm/scripts/corstone_utils.cmake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ function(fetch_ethos_u_content ETHOS_SDK_PATH ET_DIR_PATH)
5353
"source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_software ${core_software_base_rev} ${patch_dir}"
5454
WORKING_DIRECTORY ${ET_DIR_PATH}
5555
)
56+
# Patch the Ethos-U core driver.
57+
set(core_driver_base_rev "26.02")
58+
execute_process(
59+
COMMAND
60+
bash -c
61+
"source backends/arm/scripts/utils.sh && patch_repo ${ETHOS_SDK_PATH}/core_software/core_driver ${core_driver_base_rev} ${patch_dir}"
62+
WORKING_DIRECTORY ${ET_DIR_PATH}
63+
)
5664
# Always patch the core_platform repo since this is fast enough. TODO:
5765
# examples/arm/ethos-u-setup/core_platform/0002-*.patch and 0003-*.patch are
5866
# transient bridges that guard Armv8-M-only MPU init and the Armv7-M-and-newer
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
From 08111f0f4f5034237181b8ac4b50ccdc84575fb9 Mon Sep 17 00:00:00 2001
2+
From: Youngsik Yang <vacu9708@gmail.com>
3+
Date: Thu, 4 Jun 2026 18:09:17 +0900
4+
Subject: [PATCH] Add ethosu_driver_is_registered() non-blocking availability
5+
check
6+
7+
Expose whether ethosu_init() has been called by reading registered_drivers
8+
under the mutex. This allows callers to check driver availability without
9+
blocking, unlike ethosu_reserve_driver() which waits indefinitely.
10+
11+
Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
12+
---
13+
include/ethosu_driver.h | 8 ++++++++
14+
src/ethosu_driver.c | 8 ++++++++
15+
2 files changed, 16 insertions(+)
16+
17+
diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h
18+
index 1d7a573..9f609c3 100644
19+
--- a/include/ethosu_driver.h
20+
+++ b/include/ethosu_driver.h
21+
@@ -370,6 +370,14 @@ struct ethosu_driver *ethosu_reserve_driver(void);
22+
*/
23+
void ethosu_release_driver(struct ethosu_driver *drv);
24+
25+
+/**
26+
+ * Returns true if at least one driver has been registered via ethosu_init().
27+
+ * Non-blocking; safe to call before reserving a driver.
28+
+ *
29+
+ * @return true if a driver is registered, false otherwise.
30+
+ */
31+
+bool ethosu_driver_is_registered(void);
32+
+
33+
/**
34+
* Static inline for backwards-compatibility.
35+
*
36+
diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c
37+
index 8f39a4b..1e1caaf 100644
38+
--- a/src/ethosu_driver.c
39+
+++ b/src/ethosu_driver.c
40+
@@ -797,3 +797,11 @@ void ethosu_release_driver(struct ethosu_driver *drv)
41+
}
42+
ethosu_mutex_unlock(ethosu_mutex);
43+
}
44+
+
45+
+bool ethosu_driver_is_registered(void)
46+
+{
47+
+ ethosu_mutex_lock(ethosu_mutex);
48+
+ bool result = registered_drivers != NULL;
49+
+ ethosu_mutex_unlock(ethosu_mutex);
50+
+ return result;
51+
+}
52+
--
53+
2.34.1
54+

zephyr/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,21 @@ if(CONFIG_EXECUTORCH)
5959
endif()
6060
if(CONFIG_ETHOS_U)
6161
set(EXECUTORCH_BUILD_ARM_BAREMETAL ON)
62+
# Patch hal_ethos_u to add ethosu_driver_is_registered(). Uses git apply
63+
# (not git am) to avoid creating commits in a west-managed repo. Idempotent:
64+
# git apply exits non-zero if already applied; ERROR_QUIET suppresses the
65+
# output and execute_process does not propagate the failure.
66+
set(_patch
67+
"${EXECUTORCH_DIR}/examples/arm/ethos-u-setup/core_driver/0001-Add-ethosu_driver_is_registered.patch"
68+
)
69+
set(_hal_ethos_u "${ZEPHYR_BASE}/../modules/hal/ethos_u")
70+
if(EXISTS "${_hal_ethos_u}" AND EXISTS "${_patch}")
71+
execute_process(
72+
COMMAND git apply "${_patch}"
73+
WORKING_DIRECTORY "${_hal_ethos_u}"
74+
OUTPUT_QUIET ERROR_QUIET
75+
)
76+
endif()
6277
endif()
6378

6479
set(EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL ON)

0 commit comments

Comments
 (0)