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 <m...@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
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to