diff --git a/sys/dev/hwpmc/hwpmc_armv7.c b/sys/dev/hwpmc/hwpmc_armv7.c --- a/sys/dev/hwpmc/hwpmc_armv7.c +++ b/sys/dev/hwpmc/hwpmc_armv7.c @@ -109,9 +109,13 @@ * Performance Count Register N */ static uint32_t -armv7_pmcn_read(unsigned int pmc) +armv7_pmcn_read(unsigned int pmc, uint32_t evsel) { + if (evsel == PMC_EV_CPU_CYCLES) { + return ((uint32_t)cp15_pmccntr_get()); + } + KASSERT(pmc < armv7_npmcs, ("%s: illegal PMC number %d", __func__, pmc)); cp15_pmselr_set(pmc); @@ -165,6 +169,8 @@ { pmc_value_t tmp; struct pmc *pm; + register_t s; + u_int reg; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[armv7,%d] illegal CPU value %d", __LINE__, cpu)); @@ -173,11 +179,26 @@ pm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc; + s = intr_disable(); + tmp = armv7_pmcn_read(ri, pm->pm_md.pm_armv7.pm_armv7_evsel); + + /* Check if counter has overflowed */ if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES) - tmp = (uint32_t)cp15_pmccntr_get(); + reg = (1u << 31); else - tmp = armv7_pmcn_read(ri); + reg = (1u << ri); + + if ((cp15_pmovsr_get() & reg) != 0) { + /* Clear Overflow Flag */ + cp15_pmovsr_set(reg); + if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) + pm->pm_overflowcnt += 1; + + /* Reread counter in case we raced. */ + tmp = armv7_pmcn_read(ri, pm->pm_md.pm_armv7.pm_armv7_evsel); + } tmp += 0x100000000llu * pm->pm_overflowcnt; + intr_restore(s); PMCDBG2(MDP, REA, 2, "armv7-read id=%d -> %jd", ri, tmp); if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) @@ -205,6 +226,7 @@ PMCDBG3(MDP, WRI, 1, "armv7-write cpu=%d ri=%d v=%jx", cpu, ri, v); + pm->pm_overflowcnt = v >> 32; if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES) cp15_pmccntr_set(v); else @@ -247,8 +269,6 @@ pm = phw->phw_pmc; config = pm->pm_md.pm_armv7.pm_armv7_evsel; - pm->pm_overflowcnt = 0; - /* * Configure the event selection. */ @@ -329,9 +349,9 @@ /* Check if counter has overflowed */ if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES) - reg = (1 << 31); + reg = (1u << 31); else - reg = (1 << ri); + reg = (1u << ri); if ((cp15_pmovsr_get() & reg) == 0) { continue;