From 61da4d35575ddf7f62d4f5c687356f65a7246aed Mon Sep 17 00:00:00 2001 From: Anton Moberg Date: Tue, 22 Dec 2020 16:00:31 +0100 Subject: MLBEDSW-3796 Ethos-U driver interface multiple NPUs ---ethosu_driver--- Modified: Declarations for the driver interfaces to support multiNPU (takes *drv) Added: ethosu_register_driver(...) to allow for a specific NPU driver to be instantiated Added: ethosu_deregister_Driver(...) to allow for a specific NPU driver to be de-registered Added: ethosu_reserve_driver(...) to reserve & return the first NPU driver instance available Added: ethosu_release_driver(...) to release a specific NPU driver instance and make it available again Added: *registered_drivers - A static linked list of drivers ready be used ---ethosu_pmu--- Modified: Declarations for pmu interfaces to support multiNPU (takes *drv) ---ethosu_device--- Modified: Resolved a circular include dependency (Remove include and add ETHOSU_PMU_NCOUNTERS macro) Change-Id: Iede41cd41bb0d5d483bd9d929d1b6c9ca5d3c48e --- include/ethosu_device.h | 6 +- include/ethosu_driver.h | 48 +++++++++++-- include/pmu_ethosu.h | 88 +++++++++++++++++------ src/ethosu_driver.c | 188 +++++++++++++++++++++++++++++++++++------------- src/ethosu_pmu.c | 146 +++++++++++++++++++------------------ 5 files changed, 322 insertions(+), 154 deletions(-) diff --git a/include/ethosu_device.h b/include/ethosu_device.h index eff9054..d9c233d 100644 --- a/include/ethosu_device.h +++ b/include/ethosu_device.h @@ -23,8 +23,6 @@ * Includes ******************************************************************************/ -#include "pmu_ethosu.h" - #include #include @@ -41,6 +39,10 @@ extern "C" { #define ETHOSU_DRIVER_VERSION_PATCH 0 ///< Driver patch version #define ETHOSU_DRIVER_BASEP_INDEXES 8 ///< Number of base pointer indexes +#ifndef ETHOSU_PMU_NCOUNTERS +#define ETHOSU_PMU_NCOUNTERS 4 +#endif + /****************************************************************************** * Types ******************************************************************************/ diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h index d47b676..70e3110 100644 --- a/include/ethosu_driver.h +++ b/include/ethosu_driver.h @@ -45,6 +45,8 @@ struct ethosu_driver size_t fast_memory_size; bool status_error; bool dev_power_always_on; + struct ethosu_driver *next; + bool reserved; }; struct ethosu_version_id @@ -90,7 +92,8 @@ extern struct ethosu_driver ethosu_drv; /** * Initialize the Ethos-U driver. */ -int ethosu_init_v3(const void *base_address, +int ethosu_init_v4(struct ethosu_driver *drv, + const void *base_address, const void *fast_memory, const size_t fast_memory_size, uint32_t secure_enable, @@ -99,16 +102,21 @@ int ethosu_init_v3(const void *base_address, #define ethosu_init(base_address) ethosu_init_v3(base_address, NULL, 0, 0, 0) #define ethosu_init_v2(base_address, fast_memory, fast_memory_size) \ ethosu_init_v3(base_address, fast_memory, fast_memory_size, 0, 0) +#define ethosu_init_v3(base_address, fast_memory, fast_memory_size, secure_enable, privilege_enable) \ + ethosu_init_v4(ðosu_drv, base_address, fast_memory, fast_memory_size, secure_enable, privilege_enable) /** * Get Ethos-U version. */ -int ethosu_get_version(struct ethosu_version *version); +int ethosu_get_version_v2(struct ethosu_driver *drv, struct ethosu_version *version); + +#define ethosu_get_version(version) ethosu_get_version_v2(ðosu_drv, version) /** * Invoke Vela command stream. */ -int ethosu_invoke_v2(const void *custom_data_ptr, +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, const int custom_data_size, const uint64_t *base_addr, const size_t *base_addr_size, @@ -116,21 +124,49 @@ int ethosu_invoke_v2(const void *custom_data_ptr, #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. */ -void ethosu_abort(void); +void ethosu_abort_v2(struct ethosu_driver *drv); + +#define ethosu_abort(void) ethosu_abort_v2(ðosu_drv) /** * Interrupt handler do be called on IRQ from Ethos-U */ -void ethosu_irq_handler(void); +void ethosu_irq_handler_v2(struct ethosu_driver *drv); + +#define ethosu_irq_handler(void) ethosu_irq_handler_v2(ðosu_drv) /** * Set Ethos-U power mode. */ -void ethosu_set_power_mode(bool); +void ethosu_set_power_mode_v2(struct ethosu_driver *drv, bool always_on); + +#define ethosu_set_power_mode(always_on) ethosu_set_power_mode_v2(ðosu_drv, always_on) + +/** + * Register a driver for multiNPU usage + */ +int ethosu_register_driver(struct ethosu_driver *drv); + +/** + * Deregister a driver from multiNPU usage + */ +int ethosu_deregister_driver(struct ethosu_driver *drv); + +/** + * Find, reserve, and return the first available driver + */ +struct ethosu_driver *ethosu_reserve_driver(void); + +/** + * Change driver status to available + */ +void ethosu_release_driver(struct ethosu_driver *drv); #ifdef __cplusplus } diff --git a/include/pmu_ethosu.h b/include/pmu_ethosu.h index 78d46ee..74a2989 100644 --- a/include/pmu_ethosu.h +++ b/include/pmu_ethosu.h @@ -25,6 +25,8 @@ #include +#include "ethosu_driver.h" + #ifdef __cplusplus extern "C" { #endif @@ -137,36 +139,48 @@ enum ethosu_pmu_event_type /** * \brief Enable the PMU */ -void ETHOSU_PMU_Enable(void); +void ETHOSU_PMU_Enable_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_Enable(void) ETHOSU_PMU_Enable_v2(ðosu_drv) /** * \brief Disable the PMU */ -void ETHOSU_PMU_Disable(void); +void ETHOSU_PMU_Disable_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_Disable(void) ETHOSU_PMU_Disable_v2(ðosu_drv) /** * \brief Set event to count for PMU eventer counter * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure * \param [in] type Event to count */ -void ETHOSU_PMU_Set_EVTYPER(uint32_t num, enum ethosu_pmu_event_type type); +void ETHOSU_PMU_Set_EVTYPER_v2(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type); + +#define ETHOSU_PMU_Set_EVTYPER(num, type) ETHOSU_PMU_Set_EVTYPER_v2(ðosu_drv, num, type) /** * \brief Get event to count for PMU eventer counter * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) to configure * \return type Event to count */ -enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(uint32_t num); +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER_v2(struct ethosu_driver *drv, uint32_t num); + +#define ETHOSU_PMU_Get_EVTYPER(num) ETHOSU_PMU_Get_EVTYPER_v2(ðosu_drv, num) /** * \brief Reset cycle counter */ -void ETHOSU_PMU_CYCCNT_Reset(void); +void ETHOSU_PMU_CYCCNT_Reset_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_CYCCNT_Reset(void) ETHOSU_PMU_CYCCNT_Reset_v2(ðosu_drv) /** * \brief Reset all event counters */ -void ETHOSU_PMU_EVCNTR_ALL_Reset(void); +void ETHOSU_PMU_EVCNTR_ALL_Reset_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_EVCNTR_ALL_Reset(void) ETHOSU_PMU_EVCNTR_ALL_Reset_v2(ðosu_drv) /** * \brief Enable counters @@ -175,7 +189,9 @@ void ETHOSU_PMU_EVCNTR_ALL_Reset(void); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) * - cycle counter (bit 31) */ -void ETHOSU_PMU_CNTR_Enable(uint32_t mask); +void ETHOSU_PMU_CNTR_Enable_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_CNTR_Enable(mask) ETHOSU_PMU_CNTR_Enable_v2(ðosu_drv, mask) /** * \brief Disable counters @@ -184,7 +200,9 @@ void ETHOSU_PMU_CNTR_Enable(uint32_t mask); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) * - cycle counter (bit 31) */ -void ETHOSU_PMU_CNTR_Disable(uint32_t mask); +void ETHOSU_PMU_CNTR_Disable_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_CNTR_Disable(mask) ETHOSU_PMU_CNTR_Disable_v2(ðosu_drv, mask) /** * \brief Determine counters activation @@ -196,7 +214,9 @@ void ETHOSU_PMU_CNTR_Disable(uint32_t mask); * - cycle counter activate (bit 31) * \note ETHOSU specific. Usage breaks CMSIS complience */ -uint32_t ETHOSU_PMU_CNTR_Status(void); +uint32_t ETHOSU_PMU_CNTR_Status_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_CNTR_Status(void) ETHOSU_PMU_CNTR_Status_v2(ðosu_drv) /** * \brief Read cycle counter (64 bit) @@ -207,7 +227,9 @@ uint32_t ETHOSU_PMU_CNTR_Status(void); * is not greater than the former, it means overflow of LSW without * incrementing MSW has occurred, in which case the former value is used. */ -uint64_t ETHOSU_PMU_Get_CCNTR(void); +uint64_t ETHOSU_PMU_Get_CCNTR_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_Get_CCNTR(void) ETHOSU_PMU_Get_CCNTR_v2(ðosu_drv) /** * \brief Set cycle counter (64 bit) @@ -216,14 +238,18 @@ uint64_t ETHOSU_PMU_Get_CCNTR(void); * To work-around raciness, counter is temporary disabled if enabled. * \note ETHOSU specific. Usage breaks CMSIS complience */ -void ETHOSU_PMU_Set_CCNTR(uint64_t val); +void ETHOSU_PMU_Set_CCNTR_v2(struct ethosu_driver *drv, uint64_t val); + +#define ETHOSU_PMU_Set_CCNTR(val) ETHOSU_PMU_Set_CCNTR_v2(ðosu_drv, val) /** * \brief Read event counter * \param [in] num Event counter (0-ETHOSU_PMU_NCOUNTERS) * \return Event count */ -uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num); +uint32_t ETHOSU_PMU_Get_EVCNTR_v2(struct ethosu_driver *drv, uint32_t num); + +#define ETHOSU_PMU_Get_EVCNTR(num) ETHOSU_PMU_Get_EVCNTR_v2(ðosu_drv, num) /** * \brief Set event counter value @@ -231,7 +257,9 @@ uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num); * \param [in] val Conter value * \note ETHOSU specific. Usage breaks CMSIS complience */ -void ETHOSU_PMU_Set_EVCNTR(uint32_t num, uint32_t val); +void ETHOSU_PMU_Set_EVCNTR_v2(struct ethosu_driver *drv, uint32_t num, uint32_t val); + +#define ETHOSU_PMU_Set_EVCNTR(num, val) ETHOSU_PMU_Set_EVCNTR_v2(ðosu_drv, num, val) /** * \brief Read counter overflow status @@ -239,7 +267,9 @@ void ETHOSU_PMU_Set_EVCNTR(uint32_t num, uint32_t val); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS)) * - cycle counter (bit 31) */ -uint32_t ETHOSU_PMU_Get_CNTR_OVS(void); +uint32_t ETHOSU_PMU_Get_CNTR_OVS_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_Get_CNTR_OVS(void) ETHOSU_PMU_Get_CNTR_OVS_v2(ðosu_drv) /** * \brief Clear counter overflow status @@ -248,7 +278,9 @@ uint32_t ETHOSU_PMU_Get_CNTR_OVS(void); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) * - cycle counter (bit 31) */ -void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask); +void ETHOSU_PMU_Set_CNTR_OVS_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_Set_CNTR_OVS(mask) ETHOSU_PMU_Set_CNTR_OVS_v2(ðosu_drv, mask) /** * \brief Enable counter overflow interrupt request @@ -257,7 +289,9 @@ void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) * - cycle counter (bit 31) */ -void ETHOSU_PMU_Set_CNTR_IRQ_Enable(uint32_t mask); +void ETHOSU_PMU_Set_CNTR_IRQ_Enable_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_Set_CNTR_IRQ_Enable(mask) ETHOSU_PMU_Set_CNTR_IRQ_Enable_v2(ðosu_drv, mask) /** * \brief Disable counter overflow interrupt request @@ -266,7 +300,9 @@ void ETHOSU_PMU_Set_CNTR_IRQ_Enable(uint32_t mask); * - event counters (bit 0-ETHOSU_PMU_NCOUNTERS) * - cycle counter (bit 31) */ -void ETHOSU_PMU_Set_CNTR_IRQ_Disable(uint32_t mask); +void ETHOSU_PMU_Set_CNTR_IRQ_Disable_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_Set_CNTR_IRQ_Disable(mask) ETHOSU_PMU_Set_CNTR_IRQ_Disable_v2(ðosu_drv, mask) /** * \brief Get counters overflow interrupt request stiinings @@ -276,7 +312,9 @@ void ETHOSU_PMU_Set_CNTR_IRQ_Disable(uint32_t mask); * - cycle counter (bit 31) * \note ETHOSU specific. Usage breaks CMSIS compliance */ -uint32_t ETHOSU_PMU_Get_IRQ_Enable(void); +uint32_t ETHOSU_PMU_Get_IRQ_Enable_v2(struct ethosu_driver *drv); + +#define ETHOSU_PMU_Get_IRQ_Enable(void) ETHOSU_PMU_Get_IRQ_Enable_v2(ðosu_drv) /** * \brief Software increment event counter @@ -285,7 +323,9 @@ uint32_t ETHOSU_PMU_Get_IRQ_Enable(void); * - cycle counter (bit 31) * \note Software increment bits for one or more event counters. */ -void ETHOSU_PMU_CNTR_Increment(uint32_t mask); +void ETHOSU_PMU_CNTR_Increment_v2(struct ethosu_driver *drv, uint32_t mask); + +#define ETHOSU_PMU_CNTR_Increment(mask) ETHOSU_PMU_CNTR_Increment_v2(ðosu_drv, mask) /** * \brief Set start event number for the cycle counter @@ -294,7 +334,10 @@ void ETHOSU_PMU_CNTR_Increment(uint32_t mask); * \note Sets the event number that starts the cycle counter. * - Event number in the range 0..1023 */ -void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event); +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event_v2(struct ethosu_driver *drv, uint32_t start_event); + +#define ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(start_event) \ + ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event_v2(ðosu_drv, start_event) /** * \brief Set stop event number for the cycle counter @@ -303,7 +346,10 @@ void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event); * \note Sets the event number that stops the cycle counter. * - Event number in the range 0..1023 */ -void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(uint32_t stop_event); +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event_v2(struct ethosu_driver *drv, uint32_t stop_event); + +#define ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(stop_event) \ + ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event_v2(ðosu_drv, stop_event) #ifdef __cplusplus } diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c index 182b90c..2eedfe3 100644 --- a/src/ethosu_driver.c +++ b/src/ethosu_driver.c @@ -154,33 +154,37 @@ struct ethosu_driver ethosu_drv = { .status_error = false, .dev_power_always_on = false}; +// Registered drivers linked list HEAD +static struct ethosu_driver *registered_drivers = NULL; + // IRQ static volatile bool irq_triggered = false; static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv); -void ethosu_irq_handler(void) + +void ethosu_irq_handler_v2(struct ethosu_driver *drv) { uint8_t irq_raised = 0; LOG_DEBUG("Interrupt. status=0x%08x, qread=%d\n", - ethosu_read_reg(ðosu_drv.dev, NPU_REG_STATUS), - ethosu_read_reg(ðosu_drv.dev, NPU_REG_QREAD)); + ethosu_read_reg(&drv->dev, NPU_REG_STATUS), + ethosu_read_reg(&drv->dev, NPU_REG_QREAD)); // Verify that interrupt has been raised - (void)ethosu_is_irq_raised(ðosu_drv.dev, &irq_raised); + (void)ethosu_is_irq_raised(&drv->dev, &irq_raised); ASSERT(irq_raised == 1); irq_triggered = true; // Clear interrupt - (void)ethosu_clear_irq_status(ðosu_drv.dev); + (void)ethosu_clear_irq_status(&drv->dev); // Verify that interrupt has been successfully cleared - (void)ethosu_is_irq_raised(ðosu_drv.dev, &irq_raised); + (void)ethosu_is_irq_raised(&drv->dev, &irq_raised); ASSERT(irq_raised == 0); - if (ethosu_status_has_error(ðosu_drv.dev)) + if (ethosu_status_has_error(&drv->dev)) { - ethosu_soft_reset_and_restore(ðosu_drv); - ethosu_drv.status_error = true; + ethosu_soft_reset_and_restore(drv); + drv->status_error = true; } } @@ -214,7 +218,8 @@ static void dump_npu_register(struct ethosu_driver *drv, int npu_reg, int npu_re 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); -int ethosu_init_v3(const void *base_address, +int ethosu_init_v4(struct ethosu_driver *drv, + const void *base_address, const void *fast_memory, const size_t fast_memory_size, uint32_t secure_enable, @@ -230,38 +235,40 @@ int ethosu_init_v3(const void *base_address, secure_enable, privilege_enable); - ethosu_drv.fast_memory = (uint32_t)fast_memory; - ethosu_drv.fast_memory_size = fast_memory_size; + ethosu_register_driver(drv); + + drv->fast_memory = (uint32_t)fast_memory; + drv->fast_memory_size = fast_memory_size; - if (ETHOSU_SUCCESS != ethosu_dev_init(ðosu_drv.dev, base_address, secure_enable, privilege_enable)) + if (ETHOSU_SUCCESS != ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable)) { LOG_ERR("Failed in ethosu_dev_init"); return -1; } - if (ETHOSU_SUCCESS != ethosu_set_clock_and_power(ðosu_drv.dev, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE)) + if (ETHOSU_SUCCESS != ethosu_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE)) { LOG_ERR("Failed to disable clock-q & power-q for Ethos-U\n"); return -1; } - if (ETHOSU_SUCCESS != ethosu_soft_reset(ðosu_drv.dev)) + if (ETHOSU_SUCCESS != ethosu_soft_reset(&drv->dev)) { return -1; } - if (ETHOSU_SUCCESS != ethosu_wait_for_reset(ðosu_drv.dev)) + if (ETHOSU_SUCCESS != ethosu_wait_for_reset(&drv->dev)) { LOG_ERR("Failed reset of Ethos-U\n"); return -1; } - ethosu_drv.status_error = false; + drv->status_error = false; return return_code; } -int ethosu_get_version(struct ethosu_version *version) +int ethosu_get_version_v2(struct ethosu_driver *drv, struct ethosu_version *version) { int return_code = 0; @@ -269,8 +276,8 @@ int ethosu_get_version(struct ethosu_version *version) { struct ethosu_id id; struct ethosu_config cfg; - (void)ethosu_get_id(ðosu_drv.dev, &id); - (void)ethosu_get_config(ðosu_drv.dev, &cfg); + (void)ethosu_get_id(&drv->dev, &id); + (void)ethosu_get_config(&drv->dev, &cfg); version->id.version_status = id.version_status; version->id.version_minor = id.version_minor; @@ -294,7 +301,8 @@ int ethosu_get_version(struct ethosu_version *version) return return_code; } -int ethosu_invoke_v2(const void *custom_data_ptr, +int ethosu_invoke_v3(struct ethosu_driver *drv, + const void *custom_data_ptr, const int custom_data_size, const uint64_t *base_addr, const size_t *base_addr_size, @@ -323,36 +331,39 @@ int ethosu_invoke_v2(const void *custom_data_ptr, ++data_ptr; // Adjust base address to fast memory area - if (ethosu_drv.fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX) + if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX) { uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX]; - if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > ethosu_drv.fast_memory_size) + if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size) { LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u\n", - ethosu_drv.fast_memory_size, + drv->fast_memory_size, base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]); return -1; } - *fast_memory = ethosu_drv.fast_memory; + *fast_memory = drv->fast_memory; } - if (!ethosu_drv.dev_power_always_on) + if (!drv->dev_power_always_on) { - if (ethosu_drv.dev.proto != ethosu_read_reg(ðosu_drv.dev, NPU_REG_PROT)) + // Only soft reset if securty state or privilege level needs changing + if (drv->dev.proto != ethosu_read_reg(&drv->dev, NPU_REG_PROT)) { - if (ETHOSU_SUCCESS != ethosu_soft_reset(ðosu_drv.dev)) + if (ETHOSU_SUCCESS != ethosu_soft_reset(&drv->dev)) { return -1; } } - ethosu_set_clock_and_power(ðosu_drv.dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE); - ethosu_restore_pmu_config(ðosu_drv.dev); - npu_axi_init(ðosu_drv); + + drv->status_error = false; + ethosu_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE); + ethosu_restore_pmu_config(&drv->dev); + npu_axi_init(drv); } - ethosu_drv.status_error = false; + drv->status_error = false; while (data_ptr < data_end) { @@ -363,7 +374,7 @@ int ethosu_invoke_v2(const void *custom_data_ptr, LOG_INFO("ethosu_invoke OPTIMIZER_CONFIG\n"); struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr; - ret = handle_optimizer_config(ðosu_drv, opt_cfg_p); + ret = handle_optimizer_config(drv, opt_cfg_p); data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD; break; case COMMAND_STREAM: @@ -371,34 +382,33 @@ int ethosu_invoke_v2(const void *custom_data_ptr, void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct custom_data_s); int cms_length = (data_ptr->reserved << 16) | data_ptr->length; - ethosu_drv.abort_inference = false; + drv->abort_inference = false; // It is safe to clear this flag without atomic, because npu is not running. irq_triggered = false; - ret = handle_command_stream( - ðosu_drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr); + ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr); - if (return_code == -1 && ethosu_drv.abort_inference) + if (return_code == -1 && drv->abort_inference) { uint32_t qread = 0; - ethosu_get_qread(ðosu_drv.dev, &qread); + ethosu_get_qread(&drv->dev, &qread); LOG_ERR("NPU timeout\n"); dump_command_stream(command_stream, cms_length, qread); - dump_npu_register(ðosu_drv, 0x200, 0x2BF); - dump_npu_register(ðosu_drv, 0x800, 0xB3F); - dump_shram(ðosu_drv); + dump_npu_register(drv, 0x200, 0x2BF); + dump_npu_register(drv, 0x800, 0xB3F); + dump_shram(drv); } data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length; break; case READ_APB_REG: LOG_INFO("ethosu_invoke READ_APB_REG\n"); - ret = read_apb_reg(ðosu_drv, data_ptr->driver_action_data); + ret = read_apb_reg(drv, data_ptr->driver_action_data); data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD; break; case DUMP_SHRAM: LOG_INFO("ethosu_invoke DUMP_SHRAM\n"); - ret = dump_shram(ðosu_drv); + ret = dump_shram(drv); data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD; break; case NOP: @@ -417,27 +427,103 @@ int ethosu_invoke_v2(const void *custom_data_ptr, } } - if (!ethosu_drv.status_error && !ethosu_drv.dev_power_always_on) + if (!drv->status_error && !drv->dev_power_always_on) { - ethosu_save_pmu_counters(ðosu_drv.dev); - ethosu_set_clock_and_power(ðosu_drv.dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE); + ethosu_save_pmu_counters(&drv->dev); + ethosu_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE); } return return_code; } -void ethosu_abort(void) +void ethosu_abort_v2(struct ethosu_driver *drv) { - ethosu_drv.abort_inference = true; + drv->abort_inference = true; } -void ethosu_set_power_mode(bool always_on) +void ethosu_set_power_mode_v2(struct ethosu_driver *drv, bool always_on) { - ethosu_drv.dev_power_always_on = always_on; + drv->dev_power_always_on = always_on; if (always_on) { - npu_axi_init(ðosu_drv); + npu_axi_init(drv); + } +} + +int ethosu_register_driver(struct ethosu_driver *drv) +{ + // Safeguard check for if driver is already registered + struct ethosu_driver *cur = registered_drivers; + while (cur != NULL) + { + if (cur == drv) + { + LOG_ERR("%s: NPU driver at address %p is already registered.\n", __FUNCTION__, drv); + return -1; + } + cur = cur->next; + } + + drv->next = registered_drivers; + // Designate new registered driver HEAD + registered_drivers = drv; + + LOG_INFO("%s: New NPU driver at address %p is registered.\n", __FUNCTION__, drv); + + return 0; +} + +int ethosu_deregister_driver(struct ethosu_driver *drv) +{ + struct ethosu_driver *cur = registered_drivers; + struct ethosu_driver **prev = ®istered_drivers; + + while (cur != NULL) + { + if (cur == drv) + { + *prev = cur->next; + LOG_INFO("%s: NPU driver at address %p is deregistered.\n", __FUNCTION__, drv); + return 0; + } + + prev = &cur->next; + cur = cur->next; + } + + 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 = registered_drivers; + + while (drv != NULL) + { + if (!drv->reserved) + { + drv->reserved = true; + LOG_INFO("%s - Driver %p reserved.\n", __FUNCTION__, drv); + return drv; + } + drv = drv->next; + } + + LOG_INFO("%s: No available drivers.\n", __FUNCTION__, drv); + + return NULL; +} + +void ethosu_release_driver(struct ethosu_driver *drv) +{ + if (drv != NULL && drv->reserved) + { + drv->reserved = false; + LOG_INFO("%s - Driver %p released\n", __FUNCTION__, drv); } } diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c index 57edacd..759a722 100644 --- a/src/ethosu_pmu.c +++ b/src/ethosu_pmu.c @@ -84,90 +84,90 @@ static uint32_t pmu_event_value(enum ethosu_pmu_event_type event) * Functions *****************************************************************************/ -void ETHOSU_PMU_Enable(void) +void ETHOSU_PMU_Enable_v2(struct ethosu_driver *drv) { LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_drv.dev.pmcr; + pmcr.word = drv->dev.pmcr; pmcr.cnt_en = 1; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_drv.dev.pmcr); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr); } -void ETHOSU_PMU_Disable(void) +void ETHOSU_PMU_Disable_v2(struct ethosu_driver *drv) { LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_drv.dev.pmcr; + pmcr.word = drv->dev.pmcr; pmcr.cnt_en = 0; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_drv.dev.pmcr); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr); } -void ETHOSU_PMU_Set_EVTYPER(uint32_t num, enum ethosu_pmu_event_type type) +void ETHOSU_PMU_Set_EVTYPER_v2(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type) { ASSERT(num < ETHOSU_PMU_NCOUNTERS); uint32_t val = pmu_event_value(type); LOG_DEBUG("%s: num=%u, type=%d, val=%u\n", __FUNCTION__, num, type, val); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMEVTYPER(num), val, ðosu_drv.dev.pmu_evtypr[num]); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMEVTYPER(num), val, &drv->dev.pmu_evtypr[num]); } -enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(uint32_t num) +enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER_v2(struct ethosu_driver *drv, uint32_t num) { ASSERT(num < ETHOSU_PMU_NCOUNTERS); - uint32_t val = ethosu_drv.dev.pmu_evtypr[num]; + uint32_t val = drv->dev.pmu_evtypr[num]; enum ethosu_pmu_event_type type = pmu_event_type(val); LOG_DEBUG("%s: num=%u, type=%d, val=%u\n", __FUNCTION__, num, type, val); return type; } -void ETHOSU_PMU_CYCCNT_Reset(void) +void ETHOSU_PMU_CYCCNT_Reset_v2(struct ethosu_driver *drv) { LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_drv.dev.pmcr; + pmcr.word = drv->dev.pmcr; pmcr.cycle_cnt_rst = 1; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_drv.dev.pmcr); - ethosu_drv.dev.pmccntr[0] = 0; - ethosu_drv.dev.pmccntr[1] = 0; + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr); + drv->dev.pmccntr[0] = 0; + drv->dev.pmccntr[1] = 0; } -void ETHOSU_PMU_EVCNTR_ALL_Reset(void) +void ETHOSU_PMU_EVCNTR_ALL_Reset_v2(struct ethosu_driver *drv) { LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_drv.dev.pmcr; + pmcr.word = drv->dev.pmcr; pmcr.event_cnt_rst = 1; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_drv.dev.pmcr); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr); for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) { - ethosu_drv.dev.pmu_evcntr[i] = 0; + drv->dev.pmu_evcntr[i] = 0; } } -void ETHOSU_PMU_CNTR_Enable(uint32_t mask) +void ETHOSU_PMU_CNTR_Enable_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCNTENSET, mask, ðosu_drv.dev.pmcnten); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENSET, mask, &drv->dev.pmcnten); } -void ETHOSU_PMU_CNTR_Disable(uint32_t mask) +void ETHOSU_PMU_CNTR_Disable_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCNTENCLR, mask, ðosu_drv.dev.pmcnten); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENCLR, mask, &drv->dev.pmcnten); } -uint32_t ETHOSU_PMU_CNTR_Status(void) +uint32_t ETHOSU_PMU_CNTR_Status_v2(struct ethosu_driver *drv) { - LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, ethosu_drv.dev.pmcnten); - return ethosu_drv.dev.pmcnten; + LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, drv->dev.pmcnten); + return drv->dev.pmcnten; } -uint64_t ETHOSU_PMU_Get_CCNTR(void) +uint64_t ETHOSU_PMU_Get_CCNTR_v2(struct ethosu_driver *drv) { - uint32_t val_lo = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_LO); - uint32_t val_hi = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI); + uint32_t val_lo = ethosu_read_reg(&drv->dev, NPU_REG_PMCCNTR_LO); + uint32_t val_hi = ethosu_read_reg(&drv->dev, NPU_REG_PMCCNTR_HI); uint64_t val = ((uint64_t)val_hi << 32) | val_lo; - uint64_t shadow = ((uint64_t)ethosu_drv.dev.pmccntr[1] << 32) | ethosu_drv.dev.pmccntr[0]; + uint64_t shadow = ((uint64_t)drv->dev.pmccntr[1] << 32) | drv->dev.pmccntr[0]; LOG_DEBUG("%s: val=%" PRIu64 ", shadow=%" PRIu64 "\n", __FUNCTION__, val, shadow); @@ -178,132 +178,130 @@ uint64_t ETHOSU_PMU_Get_CCNTR(void) } // Update the shadow variable - ethosu_drv.dev.pmccntr[0] = val_lo; - ethosu_drv.dev.pmccntr[1] = val_hi; + drv->dev.pmccntr[0] = val_lo; + drv->dev.pmccntr[1] = val_hi; return val; } -void ETHOSU_PMU_Set_CCNTR(uint64_t val) +void ETHOSU_PMU_Set_CCNTR_v2(struct ethosu_driver *drv, uint64_t val) { - uint32_t active = ETHOSU_PMU_CNTR_Status() & ETHOSU_PMU_CCNT_Msk; + uint32_t active = ETHOSU_PMU_CNTR_Status_v2(drv) & ETHOSU_PMU_CCNT_Msk; LOG_DEBUG("%s: val=%llu\n", __FUNCTION__, val); if (active) { - ETHOSU_PMU_CNTR_Disable(ETHOSU_PMU_CCNT_Msk); + ETHOSU_PMU_CNTR_Disable_v2(drv, ETHOSU_PMU_CCNT_Msk); } - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, ðosu_drv.dev.pmccntr[0]); - ethosu_write_reg_shadow( - ðosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, ðosu_drv.dev.pmccntr[1]); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]); if (active) { - ETHOSU_PMU_CNTR_Enable(ETHOSU_PMU_CCNT_Msk); + ETHOSU_PMU_CNTR_Enable_v2(drv, ETHOSU_PMU_CCNT_Msk); } } -uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num) +uint32_t ETHOSU_PMU_Get_EVCNTR_v2(struct ethosu_driver *drv, uint32_t num) { ASSERT(num < ETHOSU_PMU_NCOUNTERS); - uint32_t val = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMEVCNTR(num)); - LOG_DEBUG("%s: num=%u, val=%u, shadow=%u\n", __FUNCTION__, num, val, ethosu_drv.dev.pmu_evcntr[num]); + uint32_t val = ethosu_read_reg(&drv->dev, NPU_REG_PMEVCNTR(num)); + LOG_DEBUG("%s: num=%u, val=%u, shadow=%u\n", __FUNCTION__, num, val, drv->dev.pmu_evcntr[num]); // Return the shadow variable in case the NPU was powered off and lost the event count - if (ethosu_drv.dev.pmu_evcntr[num] > val) + if (drv->dev.pmu_evcntr[num] > val) { - return ethosu_drv.dev.pmu_evcntr[num]; + return drv->dev.pmu_evcntr[num]; } // Update the shadow variable - ethosu_drv.dev.pmu_evcntr[num] = val; + drv->dev.pmu_evcntr[num] = val; return val; } -void ETHOSU_PMU_Set_EVCNTR(uint32_t num, uint32_t val) +void ETHOSU_PMU_Set_EVCNTR_v2(struct ethosu_driver *drv, uint32_t num, uint32_t val) { ASSERT(num < ETHOSU_PMU_NCOUNTERS); LOG_DEBUG("%s: num=%u, val=%u\n", __FUNCTION__, num, val); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMEVCNTR(num), val); + ethosu_write_reg(&drv->dev, NPU_REG_PMEVCNTR(num), val); } -uint32_t ETHOSU_PMU_Get_CNTR_OVS(void) +uint32_t ETHOSU_PMU_Get_CNTR_OVS_v2(struct ethosu_driver *drv) { LOG_DEBUG("%s:\n", __FUNCTION__); - return ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMOVSSET); + return ethosu_read_reg(&drv->dev, NPU_REG_PMOVSSET); } -void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask) +void ETHOSU_PMU_Set_CNTR_OVS_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s:\n", __FUNCTION__); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMOVSCLR, mask); + ethosu_write_reg(&drv->dev, NPU_REG_PMOVSCLR, mask); } -void ETHOSU_PMU_Set_CNTR_IRQ_Enable(uint32_t mask) +void ETHOSU_PMU_Set_CNTR_IRQ_Enable_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMINTSET, mask, ðosu_drv.dev.pmint); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMINTSET, mask, &drv->dev.pmint); } -void ETHOSU_PMU_Set_CNTR_IRQ_Disable(uint32_t mask) +void ETHOSU_PMU_Set_CNTR_IRQ_Disable_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMINTCLR, mask, ðosu_drv.dev.pmint); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMINTCLR, mask, &drv->dev.pmint); } -uint32_t ETHOSU_PMU_Get_IRQ_Enable(void) +uint32_t ETHOSU_PMU_Get_IRQ_Enable_v2(struct ethosu_driver *drv) { - LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, ethosu_drv.dev.pmint); - return ethosu_drv.dev.pmint; + LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, drv->dev.pmint); + return drv->dev.pmint; } -void ETHOSU_PMU_CNTR_Increment(uint32_t mask) +void ETHOSU_PMU_CNTR_Increment_v2(struct ethosu_driver *drv, uint32_t mask) { LOG_DEBUG("%s:\n", __FUNCTION__); - uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status(); + uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status_v2(drv); // Disable counters - ETHOSU_PMU_CNTR_Disable(mask); + ETHOSU_PMU_CNTR_Disable_v2(drv, mask); // Increment cycle counter if (mask & ETHOSU_PMU_CCNT_Msk) { - uint64_t val = ETHOSU_PMU_Get_CCNTR() + 1; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, ðosu_drv.dev.pmccntr[0]); - ethosu_write_reg_shadow( - ðosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, ðosu_drv.dev.pmccntr[1]); + uint64_t val = ETHOSU_PMU_Get_CCNTR_v2(drv) + 1; + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]); } for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) { if (mask & (1 << i)) { - uint32_t val = ETHOSU_PMU_Get_EVCNTR(i); - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMEVCNTR(i), val + 1, ðosu_drv.dev.pmu_evcntr[i]); + uint32_t val = ETHOSU_PMU_Get_EVCNTR_v2(drv, i); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMEVCNTR(i), val + 1, &drv->dev.pmu_evcntr[i]); } } // Reenable the active counters - ETHOSU_PMU_CNTR_Enable(cntrs_active); + ETHOSU_PMU_CNTR_Enable_v2(drv, cntrs_active); } -void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event) +void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event_v2(struct ethosu_driver *drv, uint32_t start_event) { LOG_DEBUG("%s: start_event=%u\n", __FUNCTION__, start_event); struct pmccntr_cfg_r cfg; - cfg.word = ethosu_drv.dev.pmccntr_cfg; + cfg.word = drv->dev.pmccntr_cfg; cfg.CYCLE_CNT_CFG_START = start_event; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, ðosu_drv.dev.pmccntr_cfg); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg); } -void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(uint32_t stop_event) +void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event_v2(struct ethosu_driver *drv, uint32_t stop_event) { LOG_DEBUG("%s: stop_event=%u\n", __FUNCTION__, stop_event); struct pmccntr_cfg_r cfg; - cfg.word = ethosu_drv.dev.pmccntr_cfg; + cfg.word = drv->dev.pmccntr_cfg; cfg.CYCLE_CNT_CFG_STOP = stop_event; - ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, ðosu_drv.dev.pmccntr_cfg); + ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg); } -- cgit v1.2.1