svn commit: r319911 - in head/sys: dev/hwpmc sys

Zbigniew Bodek zbb at FreeBSD.org
Tue Jun 13 18:51:25 UTC 2017


Author: zbb
Date: Tue Jun 13 18:51:23 2017
New Revision: 319911
URL: https://svnweb.freebsd.org/changeset/base/319911

Log:
  Fix HWPMC interrupt handling in Counting Mode
  
  Additionally:
   - Fix support for Cycle Counter (evsel == 0xFF)
   - Stop and mask interrupts from all counters on init and finish
  
  Submitted by: Michal Mazur <mkm at semihalf.com>
  Obtained from: Semihalf
  Sponsored by: Stormshield, Netgate
  Differential revision: https://reviews.freebsd.org/D10910

Modified:
  head/sys/dev/hwpmc/hwpmc_armv7.c
  head/sys/sys/pmc.h

Modified: head/sys/dev/hwpmc/hwpmc_armv7.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_armv7.c	Tue Jun 13 18:50:08 2017	(r319910)
+++ head/sys/dev/hwpmc/hwpmc_armv7.c	Tue Jun 13 18:51:23 2017	(r319911)
@@ -46,6 +46,8 @@ struct armv7_event_code_map {
 	uint8_t		pe_code;
 };
 
+#define	PMC_EV_CPU_CYCLES	0xFF
+
 /*
  * Per-processor information.
  */
@@ -171,10 +173,11 @@ armv7_read_pmc(int cpu, int ri, pmc_value_t *v)
 
 	pm  = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
 
-	if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
-		tmp = cp15_pmccntr_get();
+	if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
+		tmp = (uint32_t)cp15_pmccntr_get();
 	else
 		tmp = armv7_pmcn_read(ri);
+	tmp += 0x100000000llu * pm->pm_overflowcnt;
 
 	PMCDBG2(MDP, REA, 2, "armv7-read id=%d -> %jd", ri, tmp);
 	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
@@ -202,7 +205,7 @@ armv7_write_pmc(int cpu, int ri, pmc_value_t v)
 	
 	PMCDBG3(MDP, WRI, 1, "armv7-write cpu=%d ri=%d v=%jx", cpu, ri, v);
 
-	if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
+	if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
 		cp15_pmccntr_set(v);
 	else
 		armv7_pmcn_write(ri, v);
@@ -244,11 +247,16 @@ armv7_start_pmc(int cpu, int ri)
 	pm     = phw->phw_pmc;
 	config = pm->pm_md.pm_armv7.pm_armv7_evsel;
 
+	pm->pm_overflowcnt = 0;
+
 	/*
 	 * Configure the event selection.
 	 */
-	cp15_pmselr_set(ri);
-	cp15_pmxevtyper_set(config);
+	if (config != PMC_EV_CPU_CYCLES) {
+		cp15_pmselr_set(ri);
+		cp15_pmxevtyper_set(config);
+	} else
+		ri = 31;
 
 	/*
 	 * Enable the PMC.
@@ -264,9 +272,13 @@ armv7_stop_pmc(int cpu, int ri)
 {
 	struct pmc_hw *phw;
 	struct pmc *pm;
+	uint32_t config;
 
 	phw    = &armv7_pcpu[cpu]->pc_armv7pmcs[ri];
 	pm     = phw->phw_pmc;
+	config = pm->pm_md.pm_armv7.pm_armv7_evsel;
+	if (config == PMC_EV_CPU_CYCLES)
+		ri = 31;
 
 	/*
 	 * Disable the PMCs.
@@ -313,11 +325,9 @@ armv7_intr(int cpu, struct trapframe *tf)
 		pm = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
 		if (pm == NULL)
 			continue;
-		if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
-			continue;
 
 		/* Check if counter has overflowed */
-		if (pm->pm_md.pm_armv7.pm_armv7_evsel == 0xFF)
+		if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
 			reg = (1 << 31);
 		else
 			reg = (1 << ri);
@@ -330,6 +340,11 @@ armv7_intr(int cpu, struct trapframe *tf)
 		cp15_pmovsr_set(reg);
 
 		retval = 1; /* Found an interrupting PMC. */
+
+		if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
+			pm->pm_overflowcnt += 1;
+			continue;
+		}
 		if (pm->pm_state != PMC_STATE_RUNNING)
 			continue;
 
@@ -430,6 +445,11 @@ armv7_pcpu_init(struct pmc_mdep *md, int cpu)
 		pc->pc_hwpmcs[i + first_ri] = phw;
 	}
 
+	pmnc = 0xffffffff;
+	cp15_pmcnten_clr(pmnc);
+	cp15_pminten_clr(pmnc);
+	cp15_pmovsr_set(pmnc);
+
 	/* Enable unit */
 	pmnc = cp15_pmcr_get();
 	pmnc |= ARMV7_PMNC_ENABLE;
@@ -446,6 +466,11 @@ armv7_pcpu_fini(struct pmc_mdep *md, int cpu)
 	pmnc = cp15_pmcr_get();
 	pmnc &= ~ARMV7_PMNC_ENABLE;
 	cp15_pmcr_set(pmnc);
+
+	pmnc = 0xffffffff;
+	cp15_pmcnten_clr(pmnc);
+	cp15_pminten_clr(pmnc);
+	cp15_pmovsr_set(pmnc);
 
 	return 0;
 }

Modified: head/sys/sys/pmc.h
==============================================================================
--- head/sys/sys/pmc.h	Tue Jun 13 18:50:08 2017	(r319910)
+++ head/sys/sys/pmc.h	Tue Jun 13 18:51:23 2017	(r319911)
@@ -741,6 +741,7 @@ struct pmc {
 	struct pmc_owner *pm_owner;	/* owner thread state */
 	int		pm_runcount;	/* #cpus currently on */
 	enum pmc_state	pm_state;	/* current PMC state */
+	uint32_t	pm_overflowcnt;	/* count overflow interrupts */
 
 	/*
 	 * The PMC ID field encodes the row-index for the PMC, its


More information about the svn-src-head mailing list