Index: sys/dev/hwpmc/hwpmc_mips.c =================================================================== --- sys/dev/hwpmc/hwpmc_mips.c +++ sys/dev/hwpmc/hwpmc_mips.c @@ -51,6 +51,8 @@ static struct mips_cpu **mips_pcpu; +#define PMC_MIPS_NCNTRS_MAX 4 + #if defined(__mips_n64) # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) @@ -178,6 +180,47 @@ return 0; } +static void +pmc_mips_wr_perfctl(int ri, uint32_t x) +{ + + switch (ri) { + case 0: + mips_wr_perfctl0(x); + break; + case 1: + mips_wr_perfctl1(x); + break; + case 2: + mips_wr_perfctl2(x); + break; + case 3: + mips_wr_perfctl3(x); + break; + default: + panic("pmc_mips_wr_perfctl() invalid ri argument: %d\n", ri); + } +} + +static uint32_t +pmc_mips_rd_perfctl(int ri) +{ + + switch (ri) { + case 0: + return (mips_rd_perfctl0()); + case 1: + return (mips_rd_perfctl1()); + case 2: + return (mips_rd_perfctl2()); + case 3: + return (mips_rd_perfctl3()); + default: + break; + } + panic("pmc_mips_rd_perfctl() invalid ri argument: %d\n", ri); +} + static int mips_start_pmc(int cpu, int ri) { @@ -190,17 +233,7 @@ config = pm->pm_md.pm_mips_evsel; /* Enable the PMC. */ - switch (ri) { - case 0: - mips_wr_perfcnt0(config); - break; - case 1: - mips_wr_perfcnt2(config); - break; - default: - break; - } - + pmc_mips_wr_perfctl(ri, config); return 0; } @@ -219,16 +252,7 @@ * Clearing the entire register turns the counter off as well * as removes the previously sampled event. */ - switch (ri) { - case 0: - mips_wr_perfcnt0(0); - break; - case 1: - mips_wr_perfcnt2(0); - break; - default: - break; - } + pmc_mips_wr_perfctl(ri, 0); return 0; } @@ -256,7 +280,7 @@ int retval, ri; struct pmc *pm; struct mips_cpu *pc; - uint32_t r0, r2; + uint32_t sr[PMC_MIPS_NCNTRS_MAX]; pmc_value_t r; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), @@ -266,10 +290,9 @@ pc = mips_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 < mips_npmcs; ri++) { + sr[ri] = pmc_mips_rd_perfctl(ri); + } for (ri = 0; ri < mips_npmcs; ri++) { pm = mips_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; @@ -291,10 +314,7 @@ TRAPF_USERMODE(tf)); if (error) { /* Clear/disable the relevant counter */ - if (ri == 0) - r0 = 0; - else if (ri == 1) - r2 = 0; + sr[ri] = 0; mips_stop_pmc(cpu, ri); } @@ -308,8 +328,9 @@ * Any counter which overflowed will have its sample count * reloaded in the loop above. */ - mips_wr_perfcnt0(r0); - mips_wr_perfcnt2(r2); + for (ri = 0; ri < mips_npmcs; ri++) { + pmc_mips_wr_perfctl(ri, sr[ri]); + } return retval; } @@ -414,12 +435,24 @@ { struct pmc_mdep *pmc_mdep; struct pmc_classdep *pcd; + int ri; /* - * TODO: Use More bit of PerfCntlX register to detect actual + * Use More bit of PerfCtlX register to detect actual * number of counters */ - mips_npmcs = 2; + for (ri = 0; ri < PMC_MIPS_NCNTRS_MAX; ri++) { + if ((pmc_mips_rd_perfctl(ri) & MIPS_PERFCTL_M) == 0) { + break; + } + } + if (ri == PMC_MIPS_NCNTRS_MAX) { + printf("pmc_mips_initialize: your CPU appears support more " \ + "than %d hardware perfcounters, consider increasing " \ + "PMC_MIPS_NCNTRS_MAX\n", PMC_MIPS_NCNTRS_MAX); + ri -= 1; + } + mips_npmcs = ri + 1; PMCDBG1(MDP,INI,1,"mips-init npmcs=%d", mips_npmcs); Index: sys/dev/hwpmc/hwpmc_mips24k.c =================================================================== --- sys/dev/hwpmc/hwpmc_mips24k.c +++ sys/dev/hwpmc/hwpmc_mips24k.c @@ -193,9 +193,15 @@ switch (pmc) { case 0: - mips_wr_perfcnt1(reg); + mips_wr_perfcnt0(reg); break; case 1: + mips_wr_perfcnt1(reg); + break; + case 2: + mips_wr_perfcnt2(reg); + break; + case 3: mips_wr_perfcnt3(reg); break; default: Index: sys/dev/hwpmc/hwpmc_mips74k.c =================================================================== --- sys/dev/hwpmc/hwpmc_mips74k.c +++ sys/dev/hwpmc/hwpmc_mips74k.c @@ -225,9 +225,15 @@ switch (pmc) { case 0: - mips_wr_perfcnt1(reg); + mips_wr_perfcnt0(reg); break; case 1: + mips_wr_perfcnt1(reg); + break; + case 2: + mips_wr_perfcnt2(reg); + break; + case 3: mips_wr_perfcnt3(reg); break; default: Index: sys/mips/include/cpufunc.h =================================================================== --- sys/mips/include/cpufunc.h +++ sys/mips/include/cpufunc.h @@ -285,10 +285,17 @@ MIPS_RW32_COP0_SEL(watchhi2, MIPS_COP_0_WATCH_HI, 2); MIPS_RW32_COP0_SEL(watchhi3, MIPS_COP_0_WATCH_HI, 3); -MIPS_RW32_COP0_SEL(perfcnt0, MIPS_COP_0_PERFCNT, 0); -MIPS_RW32_COP0_SEL(perfcnt1, MIPS_COP_0_PERFCNT, 1); -MIPS_RW32_COP0_SEL(perfcnt2, MIPS_COP_0_PERFCNT, 2); -MIPS_RW32_COP0_SEL(perfcnt3, MIPS_COP_0_PERFCNT, 3); +/* Performance Counter Control registers */ +MIPS_RW32_COP0_SEL(perfctl0, MIPS_COP_0_PERFCNT, 0); +MIPS_RW32_COP0_SEL(perfctl1, MIPS_COP_0_PERFCNT, 2); +MIPS_RW32_COP0_SEL(perfctl2, MIPS_COP_0_PERFCNT, 4); +MIPS_RW32_COP0_SEL(perfctl3, MIPS_COP_0_PERFCNT, 6); + +/* Performance Counter Count registers */ +MIPS_RW32_COP0_SEL(perfcnt0, MIPS_COP_0_PERFCNT, 1); +MIPS_RW32_COP0_SEL(perfcnt1, MIPS_COP_0_PERFCNT, 3); +MIPS_RW32_COP0_SEL(perfcnt2, MIPS_COP_0_PERFCNT, 5); +MIPS_RW32_COP0_SEL(perfcnt3, MIPS_COP_0_PERFCNT, 7); #undef MIPS_RW32_COP0 #undef MIPS_RW32_COP0_SEL Index: sys/mips/include/cpuregs.h =================================================================== --- sys/mips/include/cpuregs.h +++ sys/mips/include/cpuregs.h @@ -420,6 +420,15 @@ /* Master-Checker Mode - 1: enabled */ #define MIPS_CONFIG_CM 0x80000000 +/* Performance Counter Control register(s) bits */ +#define MIPS_PERFCTL_EXL (1 << 0) +#define MIPS_PERFCTL_K (1 << 1) +#define MIPS_PERFCTL_S (1 << 2) +#define MIPS_PERFCTL_U (1 << 3) +#define MIPS_PERFCTL_IE (1 << 4) +#define MIPS_PERFCTL_PCTD (1 << 15) +#define MIPS_PERFCTL_M (1 << 31) + /* * The bits in the MIPS4 config register. */