aboutsummaryrefslogtreecommitdiff
path: root/src/ethosu_pmu.c
diff options
context:
space:
mode:
authorKristofer Jonsson <kristofer.jonsson@arm.com>2020-10-16 12:33:47 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2020-10-20 14:33:06 +0200
commit4dc73dcea25d951971ae306481d1f201c8d6ebdd (patch)
tree6c9d460f047e9123dda07480a6abb5efbcecb050 /src/ethosu_pmu.c
parent5f8dad185b3e3a381fe2e3d16580a8a8e99f9db0 (diff)
downloadethos-u-core-driver-4dc73dcea25d951971ae306481d1f201c8d6ebdd.tar.gz
PMU counter shadow
Storing PMU counters in shadow variables, in case the PMU was powered off or soft reset. Change-Id: I64ccf3fb6195f9be2d8315891ec612bb75404885
Diffstat (limited to 'src/ethosu_pmu.c')
-rw-r--r--src/ethosu_pmu.c171
1 files changed, 68 insertions, 103 deletions
diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c
index 7ca35fc..f7cb957 100644
--- a/src/ethosu_pmu.c
+++ b/src/ethosu_pmu.c
@@ -42,8 +42,6 @@
#define EVID(A, name) (PMU_EVENT_TYPE_##name)
-#define ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK (0x3FF)
-
#define NPU_REG_PMEVCNTR(x) (NPU_REG_PMEVCNTR0 + ((x) * sizeof(uint32_t)))
#define NPU_REG_PMEVTYPER(x) (NPU_REG_PMEVTYPER0 + ((x) * sizeof(uint32_t)))
@@ -51,20 +49,13 @@
* Variables
*****************************************************************************/
-/**
- * NOTE: A pointer to ethosu_driver will be added to the PMU functions
- * when multi-NPU functionality is implemented later. We shall use a
- * shared ethosu_driver instance till then.
- * */
-extern struct ethosu_driver ethosu_drv;
-
static const enum pmu_event_type eventbyid[] = {EXPAND_PMU_EVENT_TYPE(EVID, COMMA)};
/*****************************************************************************
- * Functions
+ * Static functions
*****************************************************************************/
-enum ethosu_pmu_event_type pmu_event_type(uint32_t id)
+static enum ethosu_pmu_event_type pmu_event_type(uint32_t id)
{
switch (id)
{
@@ -76,7 +67,7 @@ enum ethosu_pmu_event_type pmu_event_type(uint32_t id)
return ETHOSU_PMU_SENTINEL;
}
-uint32_t pmu_event_value(enum ethosu_pmu_event_type event)
+static uint32_t pmu_event_value(enum ethosu_pmu_event_type event)
{
int a = event;
if ((a < ETHOSU_PMU_SENTINEL) && (a >= ETHOSU_PMU_NO_EVENT))
@@ -89,29 +80,9 @@ uint32_t pmu_event_value(enum ethosu_pmu_event_type event)
}
}
-void ethosu_pmu_driver_init(void)
-{
-#ifdef PMU_AUTOINIT
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, INIT_PMCR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET, INIT_PMCNTENSET);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENCLR, INIT_PMCNTENCLR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMOVSSET, INIT_PMOVSSET);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMOVSCLR, INIT_PMOVSCLR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTSET, INIT_PMINTSET);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTCLR, INIT_PMINTCLR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO, INIT_PMCCNTR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI, INIT_PMCCNTR);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, INIT_PMCCNTR_CFG);
-
- for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
- {
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(i), 0);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(i), 0);
- }
-#endif
-}
-
-void ethosu_pmu_driver_exit(void) {}
+/*****************************************************************************
+ * Functions
+ *****************************************************************************/
void ETHOSU_PMU_Enable(void)
{
@@ -119,8 +90,7 @@ void ETHOSU_PMU_Enable(void)
struct pmcr_r pmcr;
pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cnt_en = 1;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
- ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word, &ethosu_drv.dev.pmcr);
}
void ETHOSU_PMU_Disable(void)
@@ -129,8 +99,7 @@ void ETHOSU_PMU_Disable(void)
struct pmcr_r pmcr;
pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cnt_en = 0;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
- ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word, &ethosu_drv.dev.pmcr);
}
void ETHOSU_PMU_Set_EVTYPER(uint32_t num, enum ethosu_pmu_event_type type)
@@ -138,14 +107,13 @@ void ETHOSU_PMU_Set_EVTYPER(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(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num), val);
- ethosu_drv.dev.pmu_evtypr[num] = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num));
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num), val, &ethosu_drv.dev.pmu_evtypr[num]);
}
enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(uint32_t num)
{
ASSERT(num < ETHOSU_PMU_NCOUNTERS);
- uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVTYPER(num));
+ uint32_t val = ethosu_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;
@@ -157,9 +125,9 @@ void ETHOSU_PMU_CYCCNT_Reset(void)
struct pmcr_r pmcr;
pmcr.word = ethosu_drv.dev.pmcr;
pmcr.cycle_cnt_rst = 1;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
- ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
- ethosu_drv.dev.pmccntr = 0;
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word, &ethosu_drv.dev.pmcr);
+ ethosu_drv.dev.pmccntr[0] = 0;
+ ethosu_drv.dev.pmccntr[1] = 0;
}
void ETHOSU_PMU_EVCNTR_ALL_Reset(void)
@@ -168,8 +136,7 @@ void ETHOSU_PMU_EVCNTR_ALL_Reset(void)
struct pmcr_r pmcr;
pmcr.word = ethosu_drv.dev.pmcr;
pmcr.event_cnt_rst = 1;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word);
- ethosu_drv.dev.pmcr = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCR);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCR, pmcr.word, &ethosu_drv.dev.pmcr);
for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
{
@@ -180,55 +147,59 @@ void ETHOSU_PMU_EVCNTR_ALL_Reset(void)
void ETHOSU_PMU_CNTR_Enable(uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET, mask);
- ethosu_drv.dev.pmcnten = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCNTENSET, mask, &ethosu_drv.dev.pmcnten);
}
void ETHOSU_PMU_CNTR_Disable(uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCNTENCLR, mask);
- ethosu_drv.dev.pmcnten = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCNTENCLR, mask, &ethosu_drv.dev.pmcnten);
}
uint32_t ETHOSU_PMU_CNTR_Status(void)
{
- uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCNTENSET);
- LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, val);
- return val;
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, ethosu_drv.dev.pmcnten);
+ return ethosu_drv.dev.pmcnten;
}
uint64_t ETHOSU_PMU_Get_CCNTR(void)
{
- uint64_t val = (((uint64_t)ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) |
- ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO);
+ uint32_t val_lo = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI);
+ uint32_t val_hi = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO);
+ 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];
- LOG_DEBUG("%s: val=%llu, pmccntr=%llu\n", __FUNCTION__, val, ethosu_drv.dev.pmccntr);
+ LOG_DEBUG("%s: val=%llu, shadow=%llu\n", __FUNCTION__, val, shadow);
- // Return the cached value in case the NPU was powered off
- if (ethosu_drv.dev.pmccntr > val)
+ // Return the shadow variable in case the NPU was powered off and lost the cycle count
+ if (shadow > val)
{
- return ethosu_drv.dev.pmccntr;
+ return shadow;
}
+ // Update the shadow variable
+ ethosu_drv.dev.pmccntr[0] = val_lo;
+ ethosu_drv.dev.pmccntr[1] = val_hi;
+
return val;
}
void ETHOSU_PMU_Set_CCNTR(uint64_t val)
{
- uint32_t mask = ETHOSU_PMU_CNTR_Status();
+ uint32_t active = ETHOSU_PMU_CNTR_Status() & ETHOSU_PMU_CCNT_Msk;
LOG_DEBUG("%s: val=%llu\n", __FUNCTION__, val);
- if (mask & ETHOSU_PMU_CCNT_Msk)
+ if (active)
{
ETHOSU_PMU_CNTR_Disable(ETHOSU_PMU_CCNT_Msk);
}
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO, (val & MASK_0_31_BITS));
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &ethosu_drv.dev.pmccntr[0]);
+ ethosu_write_reg_shadow(
+ &ethosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &ethosu_drv.dev.pmccntr[1]);
- if (mask & ETHOSU_PMU_CCNT_Msk)
+ if (active)
{
ETHOSU_PMU_CNTR_Enable(ETHOSU_PMU_CCNT_Msk);
}
@@ -238,14 +209,17 @@ uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num)
{
ASSERT(num < ETHOSU_PMU_NCOUNTERS);
uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(num));
- LOG_DEBUG("%s: num=%u, val=%u, pmu_evcntr=%u\n", __FUNCTION__, num, val, ethosu_drv.dev.pmu_evcntr[num]);
+ LOG_DEBUG("%s: num=%u, val=%u, shadow=%u\n", __FUNCTION__, num, val, ethosu_drv.dev.pmu_evcntr[num]);
- // Return the cached value in case the NPU was powered off
+ // Return the shadow variable in case the NPU was powered off and lost the event count
if (ethosu_drv.dev.pmu_evcntr[num] > val)
{
return ethosu_drv.dev.pmu_evcntr[num];
}
+ // Update the shadow variable
+ ethosu_drv.dev.pmu_evcntr[num] = val;
+
return val;
}
@@ -262,8 +236,6 @@ uint32_t ETHOSU_PMU_Get_CNTR_OVS(void)
return ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMOVSSET);
}
-// TODO: check if this function name match with the description &
-// implementation.
void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask)
{
LOG_DEBUG("%s:\n", __FUNCTION__);
@@ -273,22 +245,19 @@ void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask)
void ETHOSU_PMU_Set_CNTR_IRQ_Enable(uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTSET, mask);
- ethosu_drv.dev.pmint = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMINTSET, mask, &ethosu_drv.dev.pmint);
}
void ETHOSU_PMU_Set_CNTR_IRQ_Disable(uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMINTCLR, mask);
- ethosu_drv.dev.pmint = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMINTCLR, mask, &ethosu_drv.dev.pmint);
}
uint32_t ETHOSU_PMU_Get_IRQ_Enable(void)
{
- uint32_t mask = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMINTSET);
- LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- return mask;
+ LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, ethosu_drv.dev.pmint);
+ return ethosu_drv.dev.pmint;
}
void ETHOSU_PMU_CNTR_Increment(uint32_t mask)
@@ -296,49 +265,45 @@ void ETHOSU_PMU_CNTR_Increment(uint32_t mask)
LOG_DEBUG("%s:\n", __FUNCTION__);
uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status();
+ // Disable counters
+ ETHOSU_PMU_CNTR_Disable(mask);
+
+ // Increment cycle counter
if (mask & ETHOSU_PMU_CCNT_Msk)
{
- if (mask & ETHOSU_PMU_CCNT_Msk)
- {
- ETHOSU_PMU_CNTR_Disable(ETHOSU_PMU_CCNT_Msk);
- uint64_t val = ETHOSU_PMU_Get_CCNTR() + 1;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO, (val & MASK_0_31_BITS));
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32);
- if (cntrs_active & ETHOSU_PMU_CCNT_Msk)
- {
- ETHOSU_PMU_CNTR_Enable(ETHOSU_PMU_CCNT_Msk);
- }
- }
+ uint64_t val = ETHOSU_PMU_Get_CCNTR() + 1;
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &ethosu_drv.dev.pmccntr[0]);
+ ethosu_write_reg_shadow(
+ &ethosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &ethosu_drv.dev.pmccntr[1]);
}
+
for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
{
- uint32_t cntr = (0x0001 << i);
-
- if (mask & cntr)
+ if (mask & (1 << i))
{
- ETHOSU_PMU_CNTR_Disable(cntr);
- uint32_t val = ethosu_read_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(i));
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMEVCNTR(i), val + 1);
- if (cntrs_active & cntr)
- {
- ETHOSU_PMU_CNTR_Enable(cntr);
- }
+ uint32_t val = ETHOSU_PMU_Get_EVCNTR(i);
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMEVCNTR(i), val + 1, &ethosu_drv.dev.pmu_evcntr[i]);
}
}
+
+ // Reenable the active counters
+ ETHOSU_PMU_CNTR_Enable(cntrs_active);
}
void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event)
{
LOG_DEBUG("%s: start_event=%u\n", __FUNCTION__, start_event);
- struct pmccntr_cfg_r *cfg = (struct pmccntr_cfg_r *)&ethosu_drv.dev.pmccntr_cfg;
- cfg->CYCLE_CNT_CFG_START = start_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg->word);
+ struct pmccntr_cfg_r cfg;
+ cfg.word = ethosu_drv.dev.pmccntr_cfg;
+ cfg.CYCLE_CNT_CFG_START = start_event;
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, &ethosu_drv.dev.pmccntr_cfg);
}
void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(uint32_t stop_event)
{
LOG_DEBUG("%s: stop_event=%u\n", __FUNCTION__, stop_event);
- struct pmccntr_cfg_r *cfg = (struct pmccntr_cfg_r *)&ethosu_drv.dev.pmccntr_cfg;
- cfg->CYCLE_CNT_CFG_STOP = stop_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK;
- ethosu_write_reg(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg->word);
+ struct pmccntr_cfg_r cfg;
+ cfg.word = ethosu_drv.dev.pmccntr_cfg;
+ cfg.CYCLE_CNT_CFG_STOP = stop_event;
+ ethosu_write_reg_shadow(&ethosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, &ethosu_drv.dev.pmccntr_cfg);
}