From 4dc73dcea25d951971ae306481d1f201c8d6ebdd Mon Sep 17 00:00:00 2001 From: Kristofer Jonsson Date: Fri, 16 Oct 2020 12:33:47 +0200 Subject: PMU counter shadow Storing PMU counters in shadow variables, in case the PMU was powered off or soft reset. Change-Id: I64ccf3fb6195f9be2d8315891ec612bb75404885 --- src/ethosu_pmu.c | 171 ++++++++++++++++++++++--------------------------------- 1 file changed, 68 insertions(+), 103 deletions(-) (limited to 'src/ethosu_pmu.c') 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(ðosu_drv.dev, NPU_REG_PMCR, INIT_PMCR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCNTENSET, INIT_PMCNTENSET); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCNTENCLR, INIT_PMCNTENCLR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMOVSSET, INIT_PMOVSSET); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMOVSCLR, INIT_PMOVSCLR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMINTSET, INIT_PMINTSET); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMINTCLR, INIT_PMINTCLR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_LO, INIT_PMCCNTR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI, INIT_PMCCNTR); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_CFG, INIT_PMCCNTR_CFG); - - for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) - { - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMEVCNTR(i), 0); - ethosu_write_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word); - ethosu_drv.dev.pmcr = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCR); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_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(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word); - ethosu_drv.dev.pmcr = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCR); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_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(ðosu_drv.dev, NPU_REG_PMEVTYPER(num), val); - ethosu_drv.dev.pmu_evtypr[num] = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMEVTYPER(num)); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMEVTYPER(num), val, ðosu_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(ðosu_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(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word); - ethosu_drv.dev.pmcr = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCR); - ethosu_drv.dev.pmccntr = 0; + 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; } 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(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word); - ethosu_drv.dev.pmcr = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCR); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCR, pmcr.word, ðosu_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(ðosu_drv.dev, NPU_REG_PMCNTENSET, mask); - ethosu_drv.dev.pmcnten = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCNTENSET); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCNTENSET, mask, ðosu_drv.dev.pmcnten); } void ETHOSU_PMU_CNTR_Disable(uint32_t mask) { LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCNTENCLR, mask); - ethosu_drv.dev.pmcnten = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCNTENSET); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMCNTENCLR, mask, ðosu_drv.dev.pmcnten); } uint32_t ETHOSU_PMU_CNTR_Status(void) { - uint32_t val = ethosu_read_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) | - ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_LO); + uint32_t val_lo = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI); + uint32_t val_hi = ethosu_read_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCCNTR_LO, (val & MASK_0_31_BITS)); - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32); + 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]); - 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(ðosu_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(ðosu_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(ðosu_drv.dev, NPU_REG_PMINTSET, mask); - ethosu_drv.dev.pmint = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMINTSET); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMINTSET, mask, ðosu_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(ðosu_drv.dev, NPU_REG_PMINTCLR, mask); - ethosu_drv.dev.pmint = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMINTSET); + ethosu_write_reg_shadow(ðosu_drv.dev, NPU_REG_PMINTCLR, mask, ðosu_drv.dev.pmint); } uint32_t ETHOSU_PMU_Get_IRQ_Enable(void) { - uint32_t mask = ethosu_read_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCCNTR_LO, (val & MASK_0_31_BITS)); - ethosu_write_reg(ðosu_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(ð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]); } + 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(ðosu_drv.dev, NPU_REG_PMEVCNTR(i)); - ethosu_write_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMEVCNTR(i), val + 1, ðosu_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 *)ðosu_drv.dev.pmccntr_cfg; - cfg->CYCLE_CNT_CFG_START = start_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK; - ethosu_write_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, ðosu_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 *)ðosu_drv.dev.pmccntr_cfg; - cfg->CYCLE_CNT_CFG_STOP = stop_event & ETHOSU_PMCCNTR_CFG_START_STOP_EVENT_MASK; - ethosu_write_reg(ðosu_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(ðosu_drv.dev, NPU_REG_PMCCNTR_CFG, cfg.word, ðosu_drv.dev.pmccntr_cfg); } -- cgit v1.2.1