summaryrefslogtreecommitdiffstats
path: root/sys/dev/hwpmc
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2011-11-09 17:38:27 +0000
committeradrian <adrian@FreeBSD.org>2011-11-09 17:38:27 +0000
commit0070160ceaa480667098d09d55d04e0e11d52c59 (patch)
treec991242b97638b5ea9d346d90abeb2583d1f131e /sys/dev/hwpmc
parent969e95a9f7e51110cfe0b80e6fa63779683a4830 (diff)
downloadFreeBSD-src-0070160ceaa480667098d09d55d04e0e11d52c59.zip
FreeBSD-src-0070160ceaa480667098d09d55d04e0e11d52c59.tar.gz
Flip on processing interrupt profile events for mips24k.
This is a bit hackish and should be made more generic (ie, support more than two hard-coded performance counter+config register pairs) so it can be used for mips74k and other chips. All this does is process the initial interrupt event. It doesn't (yet) handle callgraph events, so even if you route the exception/interrupt to this routine and flip the bit on, it will hang and crash pmc unless you disable callgraph support when you enable a sample based PMC.
Diffstat (limited to 'sys/dev/hwpmc')
-rw-r--r--sys/dev/hwpmc/hwpmc_mips24k.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/sys/dev/hwpmc/hwpmc_mips24k.c b/sys/dev/hwpmc/hwpmc_mips24k.c
index 0b2a117..4970171 100644
--- a/sys/dev/hwpmc/hwpmc_mips24k.c
+++ b/sys/dev/hwpmc/hwpmc_mips24k.c
@@ -254,6 +254,8 @@ mips24k_allocate_pmc(int cpu, int ri, struct pmc *pm,
config |= MIPS24K_PMC_USER_ENABLE;
if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
config |= MIPS24K_PMC_ENABLE;
+ if (caps & PMC_CAP_INTERRUPT)
+ config |= MIPS24K_PMC_INTERRUPT_ENABLE;
pm->pm_md.pm_mips24k.pm_mips24k_evsel = config;
@@ -404,7 +406,65 @@ mips24k_release_pmc(int cpu, int ri, struct pmc *pmc)
static int
mips24k_intr(int cpu, struct trapframe *tf)
{
- return 0;
+ int error;
+ int retval, ri;
+ struct pmc *pm;
+ struct mips24k_cpu *pc;
+ uint32_t r, r0, r2;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[mips24k,%d] CPU %d out of range", __LINE__, cpu));
+
+ retval = 0;
+ pc = mips24k_pcpu[cpu];
+
+ /* Stop PMCs without clearing the counter */
+ r0 = mips_rd_perfcnt0();
+ mips_wr_perfcnt0(r0 & ~(0x1f));
+ r2 = mips_rd_perfcnt2();
+ mips_wr_perfcnt2(r2 & ~(0x1f));
+
+ for (ri = 0; ri < mips24k_npmcs; ri++) {
+ pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
+ if (pm == NULL)
+ continue;
+ if (! PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ continue;
+
+ r = mips24k_pmcn_read(ri);
+
+ /* If bit 31 is set, the counter has overflowed */
+ if ((r & 0x80000000) == 0)
+ continue;
+
+ retval = 1;
+ if (pm->pm_state != PMC_STATE_RUNNING)
+ continue;
+ error = pmc_process_interrupt(cpu, pm, tf,
+ TRAPF_USERMODE(tf));
+ if (error) {
+ /* Clear/disable the relevant counter */
+ if (ri == 0)
+ r0 = 0;
+ else if (ri == 1)
+ r2 = 0;
+ mips24k_stop_pmc(cpu, ri);
+ }
+
+ /* Reload sampling count */
+ mips24k_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount);
+ }
+
+ /*
+ * Re-enable the PMC counters where they left off.
+ *
+ * Any counter which overflowed will have its sample count
+ * reloaded in the loop above.
+ */
+ mips_wr_perfcnt0(r0);
+ mips_wr_perfcnt2(r2);
+
+ return retval;
}
static int
OpenPOWER on IntegriCloud