Skip to content

Commit c1df1d3

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 Corstone SDK driver via examples/arm/ethos-u-setup/core_driver/ patch (patch_repo mechanism) and to the Zephyr hal_ethos_u driver via examples/arm/ethos-u-setup/hal_ethos_u/ patch (git apply in zephyr/CMakeLists.txt). A weak symbol fallback (return true) covers build paths not reached by either patch. Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
1 parent 3f0e901 commit c1df1d3

8 files changed

Lines changed: 172 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+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
From a4b521ee5841374db88af0ca6337b7741e72bf50 Mon Sep 17 00:00:00 2001
2+
From: Youngsik Yang <vacu9708@gmail.com>
3+
Date: Fri, 5 Jun 2026 02:38:21 +0900
4+
Subject: [PATCH] Add ethosu_driver_is_registered() non-blocking availability
5+
check
6+
7+
Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
8+
---
9+
include/ethosu_driver.h | 8 ++++++++
10+
src/ethosu_driver.c | 8 ++++++++
11+
2 files changed, 16 insertions(+)
12+
13+
diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h
14+
index 1d7a573..5b2c70d 100644
15+
--- a/include/ethosu_driver.h
16+
+++ b/include/ethosu_driver.h
17+
@@ -396,3 +396,11 @@ static inline int ethosu_invoke_v2(const void *custom_data_ptr,
18+
#endif
19+
20+
#endif // ETHOSU_DRIVER_H
21+
+
22+
+/**
23+
+ * Returns true if at least one driver has been registered via ethosu_init().
24+
+ * Non-blocking; safe to call before reserving a driver.
25+
+ *
26+
+ * @return true if a driver is registered, false otherwise.
27+
+ */
28+
+bool ethosu_driver_is_registered(void);
29+
diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c
30+
index bd68c9e..43f8e86 100644
31+
--- a/src/ethosu_driver.c
32+
+++ b/src/ethosu_driver.c
33+
@@ -796,3 +796,11 @@ void ethosu_release_driver(struct ethosu_driver *drv)
34+
}
35+
ethosu_mutex_unlock(ethosu_mutex);
36+
}
37+
+
38+
+bool ethosu_driver_is_registered(void)
39+
+{
40+
+ ethosu_mutex_lock(ethosu_mutex);
41+
+ bool result = registered_drivers != NULL;
42+
+ ethosu_mutex_unlock(ethosu_mutex);
43+
+ return result;
44+
+}
45+
--
46+
2.34.1
47+

zephyr/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,35 @@ 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() if not already
63+
# present. Uses git apply (not patch_repo) because hal_ethos_u has no stable
64+
# release tag to reset to.
65+
set(_hal_ethos_u_dir "${ZEPHYR_BASE}/../modules/hal/ethos_u")
66+
set(_hal_ethos_u_patch
67+
"${EXECUTORCH_DIR}/examples/arm/ethos-u-setup/hal_ethos_u/0001-Add-ethosu_driver_is_registered.patch"
68+
)
69+
if(EXISTS "${_hal_ethos_u_dir}" AND EXISTS "${_hal_ethos_u_patch}")
70+
execute_process(
71+
COMMAND git apply --check "${_hal_ethos_u_patch}"
72+
WORKING_DIRECTORY "${_hal_ethos_u_dir}"
73+
RESULT_VARIABLE _patch_check
74+
OUTPUT_QUIET ERROR_QUIET
75+
)
76+
if(_patch_check EQUAL 0)
77+
execute_process(
78+
COMMAND git apply "${_hal_ethos_u_patch}"
79+
WORKING_DIRECTORY "${_hal_ethos_u_dir}"
80+
)
81+
message(
82+
STATUS "Applied ethosu_driver_is_registered patch to hal_ethos_u"
83+
)
84+
else()
85+
message(
86+
STATUS
87+
"Skipping hal_ethos_u patch - already applied or hal_ethos_u not found"
88+
)
89+
endif()
90+
endif()
6291
endif()
6392

6493
set(EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL ON)

0 commit comments

Comments
 (0)