From ef387ea3cbff63e06d1d0808047b9f19adf244c9 Mon Sep 17 00:00:00 2001 From: Kristofer Jonsson Date: Tue, 25 Aug 2020 16:32:21 +0200 Subject: Save and restore PMU settings and counters Change-Id: I54a1927fef998bc97f5507f2de9faf7d4a7960f5 --- include/ethosu_device.h | 5 ++- src/ethosu_device.c | 50 +++++++++++++++++------- src/ethosu_driver.c | 9 ++--- src/ethosu_pmu.c | 101 ++++++++++++++++++++++++++++++++++++------------ 4 files changed, 121 insertions(+), 44 deletions(-) diff --git a/include/ethosu_device.h b/include/ethosu_device.h index 9c78bfc..e08aa3d 100644 --- a/include/ethosu_device.h +++ b/include/ethosu_device.h @@ -55,8 +55,11 @@ enum ethosu_error_codes struct ethosu_device { uintptr_t base_address; - bool restore_pmu_config; + uint32_t pmcr; uint64_t pmccntr; + uint32_t pmcnten; + uint32_t pmint; + uint32_t pmccntr_cfg; uint32_t pmu_evcntr[ETHOSU_PMU_NCOUNTERS]; enum ethosu_pmu_event_type pmu_evtypr[ETHOSU_PMU_NCOUNTERS]; }; diff --git a/src/ethosu_device.c b/src/ethosu_device.c index 9cb67ce..4729c49 100644 --- a/src/ethosu_device.c +++ b/src/ethosu_device.c @@ -38,6 +38,7 @@ enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev, const void *b { #if !defined(ARM_NPU_STUB) dev->base_address = (uintptr_t)base_address; + ethosu_save_pmu_config(dev); #else UNUSED(dev); UNUSED(base_address); @@ -559,15 +560,26 @@ void ethosu_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t valu enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev) { #if !defined(ARM_NPU_STUB) + // Save the PMU control register + dev->pmcr = ethosu_read_reg(dev, NPU_REG_PMCR); + + // Save IRQ control + dev->pmint = ethosu_read_reg(dev, NPU_REG_PMINTSET); + + // Save the enabled events mask + dev->pmcnten = ethosu_read_reg(dev, NPU_REG_PMCNTENSET); + + // Save start and stop event + dev->pmccntr_cfg = ethosu_read_reg(dev, NPU_REG_PMCCNTR_CFG); + + // Save the cycle counter dev->pmccntr = ETHOSU_PMU_Get_CCNTR(); + + // Save the event settings and counters for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) { - dev->pmu_evcntr[i] = ETHOSU_PMU_Get_EVCNTR(i); - dev->pmu_evtypr[i] = ETHOSU_PMU_Get_EVTYPER(i); - } - if (!dev->restore_pmu_config) - { - dev->restore_pmu_config = true; + dev->pmu_evcntr[i] = ethosu_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t)); + dev->pmu_evtypr[i] = ethosu_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t)); } #else UNUSED(dev); @@ -579,14 +591,26 @@ enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev) enum ethosu_error_codes ethosu_restore_pmu_config(struct ethosu_device *dev) { #if !defined(ARM_NPU_STUB) - if (dev->restore_pmu_config) + // Restore PMU control register + ethosu_write_reg(dev, NPU_REG_PMCR, dev->pmcr); + + // Restore IRQ control + ethosu_write_reg(dev, NPU_REG_PMINTSET, dev->pmint); + + // Restore enabled event mask + ethosu_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten); + + // Restore start and stop event + ethosu_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg); + + // Restore the cycle counter + ETHOSU_PMU_Set_CCNTR(dev->pmccntr); + + // Restore event settings and counters + for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) { - ETHOSU_PMU_Set_CCNTR(dev->pmccntr); - for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) - { - ETHOSU_PMU_Set_EVCNTR(i, dev->pmu_evcntr[i]); - ETHOSU_PMU_Set_EVTYPER(i, dev->pmu_evtypr[i]); - } + ethosu_write_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t), dev->pmu_evcntr[i]); + ethosu_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]); } #else UNUSED(dev); diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c index f47d3f2..702edb4 100644 --- a/src/ethosu_driver.c +++ b/src/ethosu_driver.c @@ -29,12 +29,9 @@ #include #include -struct ethosu_driver ethosu_drv = {.dev = {.base_address = NULL, - .restore_pmu_config = false, - .pmccntr = 0, - .pmu_evcntr = {0, 0, 0, 0}, - .pmu_evtypr = {0, 0, 0, 0}}, - .abort_inference = false}; +struct ethosu_driver ethosu_drv = { + .dev = {.base_address = NULL, .pmccntr = 0, .pmu_evcntr = {0, 0, 0, 0}, .pmu_evtypr = {0, 0, 0, 0}}, + .abort_inference = false}; // IRQ static volatile bool irq_triggered = false; diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c index 62dc5da..c9a46b0 100644 --- a/src/ethosu_pmu.c +++ b/src/ethosu_pmu.c @@ -110,79 +110,111 @@ void ethosu_pmu_driver_exit(void) {} void ETHOSU_PMU_Enable(void) { + LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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); } void ETHOSU_PMU_Disable(void) { + LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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); } void ETHOSU_PMU_Set_EVTYPER(uint32_t num, enum ethosu_pmu_event_type type) { - ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMEVTYPER(num), pmu_event_value(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)); } enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(uint32_t num) { - return pmu_event_type(ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMEVTYPER(num))); + ASSERT(num < ETHOSU_PMU_NCOUNTERS); + uint32_t val = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMEVTYPER(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) { + LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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_cfg = 0; } void ETHOSU_PMU_EVCNTR_ALL_Reset(void) { + LOG_DEBUG("%s:\n", __FUNCTION__); struct pmcr_r pmcr; - pmcr.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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); + + for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++) + { + ethosu_drv.dev.pmu_evcntr[i] = 0; + } } 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); } 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); } uint32_t ETHOSU_PMU_CNTR_Status(void) { - return ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCNTENSET); + uint32_t val = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCNTENSET); + LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, val); + return val; } uint64_t ETHOSU_PMU_Get_CCNTR(void) { - uint64_t val1 = (((uint64_t)ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) | - ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_LO); - uint64_t val2 = (((uint64_t)ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_HI)) << 32) | - ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMCCNTR_LO); + 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); - if (val2 > val1) + LOG_DEBUG("%s: val=%llu, pmccntr=%llu\n", __FUNCTION__, val, ethosu_drv.dev.pmccntr); + + // Return the cached value in case the NPU was powered off + if (ethosu_drv.dev.pmccntr > val) { - return val2; + return ethosu_drv.dev.pmccntr; } - return val1; + + return val; } void ETHOSU_PMU_Set_CCNTR(uint64_t val) { uint32_t mask = ETHOSU_PMU_CNTR_Status(); + LOG_DEBUG("%s: val=%llu\n", __FUNCTION__, val); + if (mask & ETHOSU_PMU_CCNT_Msk) { ETHOSU_PMU_CNTR_Disable(ETHOSU_PMU_CCNT_Msk); @@ -199,16 +231,29 @@ void ETHOSU_PMU_Set_CCNTR(uint64_t val) uint32_t ETHOSU_PMU_Get_EVCNTR(uint32_t num) { - return ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMEVCNTR(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]); + + // Return the cached value in case the NPU was powered off + if (ethosu_drv.dev.pmu_evcntr[num] > val) + { + return ethosu_drv.dev.pmu_evcntr[num]; + } + + return val; } void ETHOSU_PMU_Set_EVCNTR(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); } uint32_t ETHOSU_PMU_Get_CNTR_OVS(void) { + LOG_DEBUG("%s:\n", __FUNCTION__); return ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMOVSSET); } @@ -216,26 +261,34 @@ uint32_t ETHOSU_PMU_Get_CNTR_OVS(void) // implementation. void ETHOSU_PMU_Set_CNTR_OVS(uint32_t mask) { + LOG_DEBUG("%s:\n", __FUNCTION__); ethosu_write_reg(ðosu_drv.dev, NPU_REG_PMOVSCLR, 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); } 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); } uint32_t ETHOSU_PMU_Get_IRQ_Enable(void) { - return ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMINTSET); + uint32_t mask = ethosu_read_reg(ðosu_drv.dev, NPU_REG_PMINTSET); + LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask); + return mask; } void ETHOSU_PMU_CNTR_Increment(uint32_t mask) { + LOG_DEBUG("%s:\n", __FUNCTION__); uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status(); if (mask & ETHOSU_PMU_CCNT_Msk) @@ -271,16 +324,16 @@ void ETHOSU_PMU_CNTR_Increment(uint32_t mask) void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(uint32_t start_event) { - struct pmccntr_cfg_r cfg; - cfg.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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); + 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); } void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(uint32_t stop_event) { - struct pmccntr_cfg_r cfg; - cfg.word = ethosu_read_reg(ðosu_drv.dev, NPU_REG_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); + 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); } -- cgit v1.2.1