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
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 @@
 
 #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(&ethosu_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_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 @@
  */
 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 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 @@
 
         __WFI();
 
+        ethosu_yield();
         __enable_irq();
+        ethosu_resume();
     }
 }
 
@@ -217,6 +259,7 @@
 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 @@
              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 @@
     registered_drivers = drv;
 
     LOG_INFO("%s: New NPU driver at address %p is registered.\n", __FUNCTION__, drv);
-
     return 0;
 }
 
@@ -495,11 +539,34 @@
     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;
 
     while (drv != NULL)
@@ -520,11 +587,14 @@
 
 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)