From df386e00295e32e05b9a76758ca5767b4d021848 Mon Sep 17 00:00:00 2001 From: Anton Moberg Date: Tue, 2 Feb 2021 11:26:48 +0100 Subject: MLBEDSW-3868 - Driver multiNPU locking Added: Weak linked symbols for locking if RTOS overrides Added: Semaphore Producer (release a reserved driver) Added: Semaphore Consumer (all drivers reserved and waiting for returned driver) Added: Mutex protect thread sensitive driver access Added: Weak linked symbols for yielding & resuming thread/task while waiting for IRQ Added: static inline function of ethosu_invoke_v2(...) for backwards compatibility Change-Id: If415a73b01b2357b31bb6da86f3038344c4245c6 --- include/ethosu_driver.h | 19 ++++++++++--- src/ethosu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h index 70e3110..2ce59c2 100644 --- a/include/ethosu_driver.h +++ b/include/ethosu_driver.h @@ -124,8 +124,6 @@ int ethosu_invoke_v3(struct ethosu_driver *drv, #define ethosu_invoke(custom_data_ptr, custom_data_size, base_addr, num_base_addr) \ ethosu_invoke_v2(custom_data_ptr, custom_data_size, base_addr, NULL, num_base_addr) -#define ethosu_invoke_v2(custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr) \ - ethosu_invoke_v3(ðosu_drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr) /** * Abort Ethos-U inference. @@ -159,7 +157,7 @@ int ethosu_register_driver(struct ethosu_driver *drv); int ethosu_deregister_driver(struct ethosu_driver *drv); /** - * Find, reserve, and return the first available driver + * Reserves a driver to execute inference with */ struct ethosu_driver *ethosu_reserve_driver(void); @@ -168,6 +166,21 @@ struct ethosu_driver *ethosu_reserve_driver(void); */ void ethosu_release_driver(struct ethosu_driver *drv); +/** + * Static inline for backwards-compatibility + */ +static inline int ethosu_invoke_v2(const void *custom_data_ptr, + const int custom_data_size, + const uint64_t *base_addr, + const size_t *base_addr_size, + const int num_base_addr) +{ + struct ethosu_driver *drv = ethosu_reserve_driver(); + int result = ethosu_invoke_v3(drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr); + ethosu_release_driver(drv); + return result; +} + #ifdef __cplusplus } #endif diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c index 2eedfe3..cb1790e 100644 --- a/src/ethosu_driver.c +++ b/src/ethosu_driver.c @@ -161,6 +161,46 @@ static struct ethosu_driver *registered_drivers = NULL; static volatile bool irq_triggered = false; static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv); +/* Default implementation to initialise ethosu driver mutex. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_mutex_init() {} + +/* Default implementation to initialise ethosu driver binary semaphore. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_semaphore_init() {} + +/* Default implementation to lock ethosu driver mutex. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_mutex_lock() {} + +/* Default implementation to unlock ethosu driver mutex. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_mutex_unlock() {} + +/* Default implementation to wait for and take free ethosu driver semaphore. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_semaphore_take() {} + +/* Default implementation to give ethosu driver semaphore. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_semaphore_give() {} + +/* Default implementation to force context-switch while waiting for Ethos-U IRQ. Override if available on the targeted + * RTOS. If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_yield() {} + +/* Default implementation to indicate thread/task is resuming. Override if available on the targeted RTOS. + * If not overridden, will do nothing (assumes baremetal). + */ +void __attribute__((weak)) ethosu_resume() {} + void ethosu_irq_handler_v2(struct ethosu_driver *drv) { uint8_t irq_raised = 0; @@ -201,7 +241,9 @@ static inline void wait_for_irq(struct ethosu_driver *drv) __WFI(); + ethosu_yield(); __enable_irq(); + ethosu_resume(); } } @@ -217,6 +259,7 @@ static int dump_shram(struct ethosu_driver *drv); static void dump_npu_register(struct ethosu_driver *drv, int npu_reg, int npu_reg_end); static void dump_command_stream(const uint32_t *cmd_stream, const int cms_length, int qread); static void npu_axi_init(struct ethosu_driver *drv); +static struct ethosu_driver *ethosu_find_and_reserve_driver(void); int ethosu_init_v4(struct ethosu_driver *drv, const void *base_address, @@ -235,6 +278,8 @@ int ethosu_init_v4(struct ethosu_driver *drv, secure_enable, privilege_enable); + ethosu_mutex_init(); + ethosu_semaphore_init(); ethosu_register_driver(drv); drv->fast_memory = (uint32_t)fast_memory; @@ -470,7 +515,6 @@ int ethosu_register_driver(struct ethosu_driver *drv) registered_drivers = drv; LOG_INFO("%s: New NPU driver at address %p is registered.\n", __FUNCTION__, drv); - return 0; } @@ -495,10 +539,33 @@ int ethosu_deregister_driver(struct ethosu_driver *drv) LOG_ERR("%s: NPU driver at address %p does not match a registered driver and therefore may not be deregistered.\n", __FUNCTION__, drv); + return -1; } struct ethosu_driver *ethosu_reserve_driver(void) +{ + struct ethosu_driver *drv = NULL; + + do + { + ethosu_mutex_lock(); + drv = ethosu_find_and_reserve_driver(); + ethosu_mutex_unlock(); + + if (drv != NULL) + { + break; + } + + ethosu_semaphore_take(); + + } while (1); + + return drv; +} + +static struct ethosu_driver *ethosu_find_and_reserve_driver(void) { struct ethosu_driver *drv = registered_drivers; @@ -520,11 +587,14 @@ struct ethosu_driver *ethosu_reserve_driver(void) void ethosu_release_driver(struct ethosu_driver *drv) { + ethosu_mutex_lock(); if (drv != NULL && drv->reserved) { drv->reserved = false; LOG_INFO("%s - Driver %p released\n", __FUNCTION__, drv); + ethosu_semaphore_give(); } + ethosu_mutex_unlock(); } static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv) -- cgit v1.2.1