From 63879e9fa9c182418a2ee5feb142e105ef1d1798 Mon Sep 17 00:00:00 2001 From: Youngsik Yang Date: Fri, 5 Jun 2026 15:14:04 +0900 Subject: [PATCH] Arm backend: implement EthosUBackend::is_available() hardware check is_available() returned 1 unconditionally, causing two failure modes: - Cortex-M: missing ethosu_init() hangs silently in ethosu_reserve_driver() - Cortex-A: absent /dev/ethosu0 fails late with a cryptic driver error Changes: - Cortex-M: calls ethosu_driver_is_registered() to check whether ethosu_init() was called. A weak fallback (return true) is kept until ethosu_driver_is_registered() is available in all driver builds. - Cortex-A: constructs EthosU::Device to probe /dev/ethosu0. Signed-off-by: Youngsik Yang --- backends/arm/runtime/EthosUBackend.cpp | 3 +-- backends/arm/runtime/EthosUBackend_Cortex_A.cpp | 17 +++++++++++++++++ backends/arm/runtime/EthosUBackend_Cortex_M.cpp | 15 +++++++++++++++ backends/arm/runtime/EthosUBackend_Internal.h | 3 +++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backends/arm/runtime/EthosUBackend.cpp b/backends/arm/runtime/EthosUBackend.cpp index 4b78f9a7e28..3b7e78ab988 100644 --- a/backends/arm/runtime/EthosUBackend.cpp +++ b/backends/arm/runtime/EthosUBackend.cpp @@ -76,8 +76,7 @@ class EthosUBackend final : public ::executorch::runtime::BackendInterface { ~EthosUBackend() = default; virtual bool is_available() const override { - // TODO: revise to use a register check/init function - return 1; + return platform_is_available(); } Result init( diff --git a/backends/arm/runtime/EthosUBackend_Cortex_A.cpp b/backends/arm/runtime/EthosUBackend_Cortex_A.cpp index 5da0996fb19..28d30c6dce7 100644 --- a/backends/arm/runtime/EthosUBackend_Cortex_A.cpp +++ b/backends/arm/runtime/EthosUBackend_Cortex_A.cpp @@ -323,6 +323,23 @@ Error invoke_linux_driver( } } // namespace +bool platform_is_available() { + // Open the NPU device driver; thrown if it is absent or unopenable. + const LinuxDriverOptions defaults; + try { + EthosU::Device device(defaults.device_path.c_str()); + (void)device; + return true; + } catch (const std::exception& e) { + ET_LOG( + Info, + "Ethos-U device %s not available: %s", + defaults.device_path.c_str(), + e.what()); + return false; + } +} + PlatformState* platform_init( ArrayRef specs, MemoryAllocator* allocator) { diff --git a/backends/arm/runtime/EthosUBackend_Cortex_M.cpp b/backends/arm/runtime/EthosUBackend_Cortex_M.cpp index 96398762302..e17e7f6f5fd 100644 --- a/backends/arm/runtime/EthosUBackend_Cortex_M.cpp +++ b/backends/arm/runtime/EthosUBackend_Cortex_M.cpp @@ -54,6 +54,21 @@ namespace arm { struct PlatformState {}; +// TODO: Upstream ethosu_driver_is_registered() into the core driver. +// Keep the weak fallback until all builds are confirmed to be using a driver +// with ethosu_driver_is_registered() implemented, at which point the weak +// fallback can be removed. +extern "C" __attribute__((weak)) bool ethosu_driver_is_registered(void) { + return true; +} + +bool platform_is_available() { + // Check whether ethosu_init() was called before ExecuTorch runs. + // If ethosu_init() was not called and this unconditionally returned true, + // then the firmware freezes without any error. + return ethosu_driver_is_registered(); +} + PlatformState* platform_init( executorch::runtime::ArrayRef /*specs*/, executorch::runtime::MemoryAllocator* /*allocator*/) { diff --git a/backends/arm/runtime/EthosUBackend_Internal.h b/backends/arm/runtime/EthosUBackend_Internal.h index f3b05fa1a56..e683b8d46ab 100644 --- a/backends/arm/runtime/EthosUBackend_Internal.h +++ b/backends/arm/runtime/EthosUBackend_Internal.h @@ -77,6 +77,9 @@ extern unsigned char* ethosu_fast_scratch; extern size_t ethosu_fast_scratch_size; } +// Returns whether the Ethos-U device driver is available +bool platform_is_available(); + PlatformState* platform_init( executorch::runtime::ArrayRef specs, executorch::runtime::MemoryAllocator* allocator);