aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonny Svärd <jonny.svaerd@arm.com>2022-04-26 18:31:24 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2022-05-05 12:56:33 +0000
commit301399d9e0b619fb2e229c9a9223aaf31ec6bcfa (patch)
tree5dbbfa41d5186add0e28b6d6b3e07b2267856c4f
parentc6505f3f8df8a5f00197f0eee5cc502e4e59c6a4 (diff)
downloadethos-u-core-driver-301399d9e0b619fb2e229c9a9223aaf31ec6bcfa.tar.gz
Refactor power handling22.05-rc1
Add reference counted ethosu_request_power(), ethosu_release_power() functions. While there are active requests, disable the Q-channel power gating of the Ethos-U device, leaving the device powered on. Note that clock gating is implemented to follow the state of the power gating. Add ethosu_soft_reset() function. Restore power- and clock gating state after reset. Refactor and simplify driver code to use the new functions. Change-Id: I9756572c5c3e51b2be244bcea856d88e890e2d40
-rw-r--r--include/ethosu_driver.h35
-rw-r--r--src/ethosu_device_u55_u65.c3
-rw-r--r--src/ethosu_driver.c181
-rw-r--r--src/ethosu_pmu.c6
4 files changed, 91 insertions, 134 deletions
diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h
index 053b529..c48a3f2 100644
--- a/include/ethosu_driver.h
+++ b/include/ethosu_driver.h
@@ -74,11 +74,9 @@ struct ethosu_driver
void *semaphore;
uint64_t fast_memory;
size_t fast_memory_size;
+ uint32_t power_request_counter;
bool status_error;
- bool dev_power_always_on;
bool reserved;
- uint8_t clock_request;
- uint8_t power_request;
};
struct ethosu_driver_version
@@ -158,6 +156,24 @@ int ethosu_init(struct ethosu_driver *drv,
void ethosu_deinit(struct ethosu_driver *drv);
/**
+ * Soft resets the Ethos-U device.
+ */
+bool ethosu_soft_reset(struct ethosu_driver *drv);
+
+/**
+ * Request to disable Q-channel power gating of the Ethos-U device.
+ * Power requests are ref.counted. Increases count.
+ * (Note: clock gating is made to follow power gating)
+ */
+bool ethosu_request_power(struct ethosu_driver *drv);
+
+/**
+ * Release disable request for Q-channel power gating of the Ethos-U device.
+ * Power requests are ref.counted. Decreases count.
+ */
+void ethosu_release_power(struct ethosu_driver *drv);
+
+/**
* Get Ethos-U driver version.
*/
void ethosu_get_driver_version(struct ethosu_driver_version *ver);
@@ -209,11 +225,6 @@ int ethosu_invoke_async(struct ethosu_driver *drv,
int ethosu_wait(struct ethosu_driver *drv, bool block);
/**
- * Set Ethos-U power mode.
- */
-void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on);
-
-/**
* Reserves a driver to execute inference with
*/
struct ethosu_driver *ethosu_reserve_driver(void);
@@ -224,14 +235,6 @@ struct ethosu_driver *ethosu_reserve_driver(void);
void ethosu_release_driver(struct ethosu_driver *drv);
/**
- * Set clock and power request bits
- */
-enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
- enum ethosu_request_clients client,
- enum ethosu_clock_q_request clock_request,
- enum ethosu_power_q_request power_request);
-
-/**
* Static inline for backwards-compatibility
*/
static inline int ethosu_invoke_v2(const void *custom_data_ptr,
diff --git a/src/ethosu_device_u55_u65.c b/src/ethosu_device_u55_u65.c
index 31379fc..f16f9f8 100644
--- a/src/ethosu_device_u55_u65.c
+++ b/src/ethosu_device_u55_u65.c
@@ -209,6 +209,9 @@ bool ethosu_dev_verify_access_state(struct ethosu_device *dev)
enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
{
+ // Note that after a soft-reset, the NPU is unconditionally
+ // powered until the next CMD gets written.
+
struct reset_r reset;
reset.word = 0;
diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c
index 316ed4d..ee9d08c 100644
--- a/src/ethosu_driver.c
+++ b/src/ethosu_driver.c
@@ -320,8 +320,6 @@ static int handle_command_stream(struct ethosu_driver *drv, const uint8_t *cmd_s
}
}
- drv->job.state = ETHOSU_JOB_RUNNING;
-
// Flush the cache if available on CPU.
// The upcasting to uin32_t* is ok since the pointer never is dereferenced.
// The base_addr_size is null if invoking from prior to invoke_V2, in that case
@@ -341,17 +339,14 @@ static int handle_command_stream(struct ethosu_driver *drv, const uint8_t *cmd_s
}
// Request power gating disabled during inference run
- if (!drv->dev_power_always_on)
+ if (!ethosu_request_power(drv))
{
- // Will soft reset if security state or privilege level needs changing.
- // Also note that any configurations done in the NPU prior to this point
- // are lost in case power gating has been in effect.
- set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
-
- // Make sure AXI settings are applied
- ethosu_dev_axi_init(drv->dev);
+ LOG_ERR("Failed to request power");
+ return -1;
}
+ drv->job.state = ETHOSU_JOB_RUNNING;
+
// Inference begin callback
ethosu_inference_begin(drv, drv->job.user_arg);
@@ -406,8 +401,9 @@ int ethosu_init(struct ethosu_driver *drv,
ethosu_semaphore = ethosu_semaphore_create();
}
- drv->fast_memory = (uint32_t)fast_memory;
- drv->fast_memory_size = fast_memory_size;
+ drv->fast_memory = (uint32_t)fast_memory;
+ drv->fast_memory_size = fast_memory_size;
+ drv->power_request_counter = 0;
// Initialize the device and set requested security state and privilege mode
drv->dev = ethosu_dev_init(base_address, secure_enable, privilege_enable);
@@ -418,20 +414,11 @@ int ethosu_init(struct ethosu_driver *drv,
return -1;
}
- // Power always ON requested
- if (drv->dev_power_always_on)
- {
- if (set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE) !=
- ETHOSU_SUCCESS)
- {
- LOG_ERR("Failed to disable power-q for Ethos-U");
- return -1;
- }
- }
-
drv->semaphore = ethosu_semaphore_create();
drv->status_error = false;
+ ethosu_reset_job(drv);
+
ethosu_register_driver(drv);
return 0;
@@ -445,6 +432,56 @@ void ethosu_deinit(struct ethosu_driver *drv)
drv->dev = NULL;
}
+bool ethosu_soft_reset(struct ethosu_driver *drv)
+{
+ // Soft reset the NPU
+ if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
+ {
+ LOG_ERR("Failed to soft-reset NPU");
+ return false;
+ }
+
+ // Update power and clock gating after the soft reset
+ ethosu_dev_set_clock_and_power(drv->dev,
+ drv->power_request_counter > 0 ? ETHOSU_CLOCK_Q_DISABLE : ETHOSU_CLOCK_Q_ENABLE,
+ drv->power_request_counter > 0 ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE);
+
+ return true;
+}
+
+bool ethosu_request_power(struct ethosu_driver *drv)
+{
+ // Check if this is the first power request, increase counter
+ if (drv->power_request_counter++ == 0)
+ {
+ // Always reset to a known state. Changes to requested
+ // security state/privilege mode if necessary.
+ if (ethosu_soft_reset(drv) == false)
+ {
+ LOG_ERR("Failed to request power for Ethos-U");
+ drv->power_request_counter--;
+ return false;
+ }
+ }
+ return true;
+}
+
+void ethosu_release_power(struct ethosu_driver *drv)
+{
+ if (drv->power_request_counter == 0)
+ {
+ LOG_WARN("No power request left to release, reference counter is 0");
+ }
+ else
+ {
+ // Decrement ref counter and enable power gating if no requests remain
+ if (--drv->power_request_counter == 0)
+ {
+ ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
+ }
+ }
+}
+
void ethosu_get_driver_version(struct ethosu_driver_version *ver)
{
assert(ver != NULL);
@@ -486,6 +523,9 @@ int ethosu_wait(struct ethosu_driver *drv, bool block)
// Inference done callback
ethosu_inference_end(drv, drv->job.user_arg);
+ // Relase power gating disabled requirement
+ ethosu_release_power(drv);
+
// Check NPU and interrupt status
if (drv->status_error)
{
@@ -493,21 +533,13 @@ int ethosu_wait(struct ethosu_driver *drv, bool block)
ethosu_dev_print_err_status(drv->dev);
// Reset the NPU
- (void)ethosu_dev_soft_reset(drv->dev);
+ (void)ethosu_soft_reset(drv);
// NPU is no longer in error state
drv->status_error = false;
ret = -1;
}
- // Clear the clock/power gating disable request
- if (!drv->dev_power_always_on)
- {
- // NOTE: Other requesters (like PMU) can be active, keeping
- // clock/power gating disabled until no requests remain.
- set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
- }
-
if (ret == 0)
{
// Invalidate cache
@@ -664,31 +696,6 @@ int ethosu_invoke_v3(struct ethosu_driver *drv,
return ethosu_wait(drv, true);
}
-void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
-{
- drv->dev_power_always_on = always_on;
-
- if (always_on)
- {
- if (ethosu_dev_verify_access_state(drv->dev) == false)
- {
- // Reset to enter correct security state/privilege mode
- if (ethosu_dev_soft_reset(drv->dev) == false)
- {
- LOG_ERR("Failed to set power mode for Ethos-U");
- return;
- }
- }
-
- ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_UNCHANGED, ETHOSU_POWER_Q_DISABLE);
- ethosu_dev_axi_init(drv->dev);
- }
- else
- {
- ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_UNCHANGED, ETHOSU_POWER_Q_ENABLE);
- }
-}
-
struct ethosu_driver *ethosu_reserve_driver(void)
{
struct ethosu_driver *drv = NULL;
@@ -727,13 +734,12 @@ void ethosu_release_driver(struct ethosu_driver *drv)
if (ethosu_wait(drv, false) == 1)
{
// Still running, soft reset the NPU and reset driver
- ethosu_dev_soft_reset(drv->dev);
+ drv->power_request_counter = 0;
+ ethosu_soft_reset(drv);
ethosu_reset_job(drv);
drv->status_error = false;
/* TODO: feedback needed aout how to handle error (-1) return value */
ethosu_semaphore_give(drv->semaphore);
- (void)set_clock_and_power_request(
- drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
}
}
@@ -745,58 +751,3 @@ void ethosu_release_driver(struct ethosu_driver *drv)
/* TODO: feedback needed aout how to handle error (-1) return value */
ethosu_mutex_unlock(ethosu_mutex);
}
-
-enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
- enum ethosu_request_clients client,
- enum ethosu_clock_q_request clock_request,
- enum ethosu_power_q_request power_request)
-{
- // Keep track of which client requests clock gating to be disabled
- if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
- {
- drv->clock_request |= (1 << client);
- }
- else if (clock_request == ETHOSU_CLOCK_Q_ENABLE) // Remove client from bitmask
- {
- drv->clock_request &= ~(1 << client);
- }
-
- // Only enable clock gating when no client has asked for it to be disabled
- clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
-
- // Keep track of which client requests power gating to be disabled
- if (power_request == ETHOSU_POWER_Q_DISABLE)
- {
- drv->power_request |= (1 << client);
- }
- else if (power_request == ETHOSU_POWER_Q_ENABLE)
- {
- drv->power_request &= ~(1 << client);
- }
-
- // Override if power has been requested to be always on
- if (drv->dev_power_always_on == true)
- {
- power_request = ETHOSU_POWER_Q_DISABLE;
- }
- else
- {
- // Only enable power gating when no client has asked for it to be disabled
- power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
- }
-
- // Verify security state and privilege mode if power is requested to be on
- if (power_request == ETHOSU_POWER_Q_DISABLE)
- {
- if (ethosu_dev_verify_access_state(drv->dev) == false)
- {
- if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
- {
- LOG_ERR("Failed to set clock and power q channels for Ethos-U");
- return ETHOSU_GENERIC_FAILURE;
- }
- }
- }
- // Set clock and power
- return ethosu_dev_set_clock_and_power(drv->dev, clock_request, power_request);
-}
diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c
index e11636a..df69026 100644
--- a/src/ethosu_pmu.c
+++ b/src/ethosu_pmu.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022 Arm Limited.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -90,7 +90,7 @@ void ETHOSU_PMU_Enable(struct ethosu_driver *drv)
LOG_DEBUG("Enable PMU");
struct pmcr_r pmcr = {0};
pmcr.cnt_en = 1;
- set_clock_and_power_request(drv, ETHOSU_PMU_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE);
+ ethosu_request_power(drv);
drv->dev->reg->PMCR.word = pmcr.word;
}
@@ -98,7 +98,7 @@ void ETHOSU_PMU_Disable(struct ethosu_driver *drv)
{
LOG_DEBUG("Disable PMU");
drv->dev->reg->PMCR.word = 0;
- set_clock_and_power_request(drv, ETHOSU_PMU_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
+ ethosu_release_power(drv);
}
uint32_t ETHOSU_PMU_Get_NumEventCounters(void)