diff options
Diffstat (limited to 'sys/dev/hwpmc/hwpmc_arm64.c')
-rw-r--r-- | sys/dev/hwpmc/hwpmc_arm64.c | 72 |
1 files changed, 53 insertions, 19 deletions
diff --git a/sys/dev/hwpmc/hwpmc_arm64.c b/sys/dev/hwpmc/hwpmc_arm64.c index af8d25b098c4..310e43065716 100644 --- a/sys/dev/hwpmc/hwpmc_arm64.c +++ b/sys/dev/hwpmc/hwpmc_arm64.c @@ -34,10 +34,12 @@ #include <machine/pmc_mdep.h> #include <machine/cpu.h> +#include <machine/machdep.h> #include "opt_acpi.h" static int arm64_npmcs; +static bool arm64_64bit_events __read_mostly = false; struct arm64_event_code_map { enum pmc_event pe_ev; @@ -112,7 +114,7 @@ arm64_counter_disable(unsigned int pmc) /* * Performance Monitors Control Register */ -static uint32_t +static uint64_t arm64_pmcr_read(void) { uint32_t reg; @@ -123,7 +125,7 @@ arm64_pmcr_read(void) } static void -arm64_pmcr_write(uint32_t reg) +arm64_pmcr_write(uint64_t reg) { WRITE_SPECIALREG(pmcr_el0, reg); @@ -134,7 +136,7 @@ arm64_pmcr_write(uint32_t reg) /* * Performance Count Register N */ -static uint32_t +static uint64_t arm64_pmcn_read(unsigned int pmc) { @@ -148,7 +150,7 @@ arm64_pmcn_read(unsigned int pmc) } static void -arm64_pmcn_write(unsigned int pmc, uint32_t reg) +arm64_pmcn_write(unsigned int pmc, uint64_t reg) { KASSERT(pmc < arm64_npmcs, ("%s: illegal PMC number %d", __func__, pmc)); @@ -163,7 +165,7 @@ static int arm64_allocate_pmc(int cpu, int ri, struct pmc *pm, const struct pmc_op_pmcallocate *a) { - uint32_t config; + uint64_t config; enum pmc_event pe; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), @@ -186,10 +188,18 @@ arm64_allocate_pmc(int cpu, int ri, struct pmc *pm, switch (a->pm_caps & (PMC_CAP_SYSTEM | PMC_CAP_USER)) { case PMC_CAP_SYSTEM: + /* Exclude EL0 */ config |= PMEVTYPER_U; + if (in_vhe()) { + /* If in VHE we need to include EL2 and exclude EL1 */ + config |= PMEVTYPER_NSH | PMEVTYPER_P; + } break; case PMC_CAP_USER: + /* Exclude EL1 */ config |= PMEVTYPER_P; + /* Exclude EL2 */ + config &= ~PMEVTYPER_NSH; break; default: /* @@ -197,11 +207,16 @@ arm64_allocate_pmc(int cpu, int ri, struct pmc *pm, * (default setting) or if both flags are specified * (user explicitly requested both qualifiers). */ + if (in_vhe()) { + /* If in VHE we need to include EL2 */ + config |= PMEVTYPER_NSH; + } break; } pm->pm_md.pm_arm64.pm_arm64_evsel = config; - PMCDBG2(MDP, ALL, 2, "arm64-allocate ri=%d -> config=0x%x", ri, config); + PMCDBG2(MDP, ALL, 2, "arm64-allocate ri=%d -> config=0x%lx", ri, + config); return (0); } @@ -233,7 +248,15 @@ arm64_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v) /* Reread counter in case we raced. */ tmp = arm64_pmcn_read(ri); } - tmp += 0x100000000llu * pm->pm_pcpu_state[cpu].pps_overflowcnt; + /* + * If the counter is 32-bit increment the upper bits of the counter. + * It it is 64-bit then there is nothing we can do as tmp is already + * 64-bit. + */ + if (!arm64_64bit_events) { + tmp &= 0xffffffffu; + tmp += (uint64_t)pm->pm_pcpu_state[cpu].pps_overflowcnt << 32; + } intr_restore(s); PMCDBG2(MDP, REA, 2, "arm64-read id=%d -> %jd", ri, tmp); @@ -267,7 +290,10 @@ arm64_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v) PMCDBG3(MDP, WRI, 1, "arm64-write cpu=%d ri=%d v=%jx", cpu, ri, v); - pm->pm_pcpu_state[cpu].pps_overflowcnt = v >> 32; + if (!arm64_64bit_events) { + pm->pm_pcpu_state[cpu].pps_overflowcnt = v >> 32; + v &= 0xffffffffu; + } arm64_pmcn_write(ri, v); return (0); @@ -299,7 +325,7 @@ arm64_config_pmc(int cpu, int ri, struct pmc *pm) static int arm64_start_pmc(int cpu, int ri, struct pmc *pm) { - uint32_t config; + uint64_t config; config = pm->pm_md.pm_arm64.pm_arm64_evsel; @@ -475,9 +501,10 @@ arm64_pcpu_init(struct pmc_mdep *md, int cpu) WRITE_SPECIALREG(pmcntenclr_el0, 0xffffffff); WRITE_SPECIALREG(pmintenclr_el1, 0xffffffff); - /* Enable unit */ - pmcr = arm64_pmcr_read(); - pmcr |= PMCR_E; + /* Enable unit with a useful default state */ + pmcr = PMCR_LC | PMCR_C | PMCR_P | PMCR_E; + if (arm64_64bit_events) + pmcr |= PMCR_LP; arm64_pmcr_write(pmcr); return (0); @@ -486,7 +513,7 @@ arm64_pcpu_init(struct pmc_mdep *md, int cpu) static int arm64_pcpu_fini(struct pmc_mdep *md, int cpu) { - uint32_t pmcr; + uint64_t pmcr; PMCDBG0(MDP, INI, 1, "arm64-pcpu-fini"); @@ -507,13 +534,14 @@ pmc_arm64_initialize(void) struct pmc_mdep *pmc_mdep; struct pmc_classdep *pcd; int classes, idcode, impcode; - int reg; + uint64_t dfr; + uint64_t pmcr; uint64_t midr; - reg = arm64_pmcr_read(); - arm64_npmcs = (reg & PMCR_N_MASK) >> PMCR_N_SHIFT; - impcode = (reg & PMCR_IMP_MASK) >> PMCR_IMP_SHIFT; - idcode = (reg & PMCR_IDCODE_MASK) >> PMCR_IDCODE_SHIFT; + pmcr = arm64_pmcr_read(); + arm64_npmcs = (pmcr & PMCR_N_MASK) >> PMCR_N_SHIFT; + impcode = (pmcr & PMCR_IMP_MASK) >> PMCR_IMP_SHIFT; + idcode = (pmcr & PMCR_IDCODE_MASK) >> PMCR_IDCODE_SHIFT; PMCDBG1(MDP, INI, 1, "arm64-init npmcs=%d", arm64_npmcs); @@ -529,6 +557,12 @@ pmc_arm64_initialize(void) midr &= ~(CPU_VAR_MASK | CPU_REV_MASK); snprintf(pmc_cpuid, sizeof(pmc_cpuid), "0x%016lx", midr); + /* Check if we have 64-bit counters */ + if (get_kernel_reg(ID_AA64DFR0_EL1, &dfr)) { + if (ID_AA64DFR0_PMUVer_VAL(dfr) >= ID_AA64DFR0_PMUVer_3_5) + arm64_64bit_events = true; + } + /* * Allocate space for pointers to PMC HW descriptors and for * the MDEP structure used by MI code. @@ -576,7 +610,7 @@ pmc_arm64_initialize(void) pcd->pcd_class = PMC_CLASS_ARMV8; pcd->pcd_num = arm64_npmcs; pcd->pcd_ri = pmc_mdep->pmd_npmc; - pcd->pcd_width = 32; + pcd->pcd_width = 64; pcd->pcd_allocate_pmc = arm64_allocate_pmc; pcd->pcd_config_pmc = arm64_config_pmc; |