diff options
Diffstat (limited to 'sys/dev/hwpmc/hwpmc_piv.c')
-rw-r--r-- | sys/dev/hwpmc/hwpmc_piv.c | 500 |
1 files changed, 183 insertions, 317 deletions
diff --git a/sys/dev/hwpmc/hwpmc_piv.c b/sys/dev/hwpmc/hwpmc_piv.c index b8f530c..601395c 100644 --- a/sys/dev/hwpmc/hwpmc_piv.c +++ b/sys/dev/hwpmc/hwpmc_piv.c @@ -153,11 +153,6 @@ __FBSDID("$FreeBSD$"); * the two logical processors in the package. We keep track of config * and de-config operations using the CFGFLAGS fields of the per-physical * cpu state. - * - * Handling TSCs - * - * TSCs are architectural state and each CPU in a HTT pair has its own - * TSC register. */ #define P4_PMCS() \ @@ -364,28 +359,6 @@ struct p4pmc_descr { }; static struct p4pmc_descr p4_pmcdesc[P4_NPMCS] = { - - /* - * TSC descriptor - */ - - { - .pm_descr = - { - .pd_name = "TSC", - .pd_class = PMC_CLASS_TSC, - .pd_caps = PMC_CAP_READ | PMC_CAP_WRITE, - .pd_width = 64 - }, - .pm_pmcnum = ~0, - .pm_cccr_msr = ~0, - .pm_pmc_msr = 0x10, - }, - - /* - * P4 PMCS - */ - #define P4_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \ PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \ PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE | \ @@ -435,8 +408,6 @@ static int p4_system_has_htt; /* * Per-CPU data structure for P4 class CPUs * - * [common stuff] - * [19 struct pmc_hw pointers] * [19 struct pmc_hw structures] * [45 ESCRs status bytes] * [per-cpu spin mutex] @@ -448,8 +419,6 @@ static int p4_system_has_htt; */ struct p4_cpu { - struct pmc_cpu pc_common; - struct pmc_hw *pc_hwpmcs[P4_NPMCS]; struct pmc_hw pc_p4pmcs[P4_NPMCS]; char pc_escrs[P4_NESCR]; struct mtx pc_mtx; /* spin lock */ @@ -463,19 +432,7 @@ struct p4_cpu { pmc_value_t pc_pmc_values[P4_NPMCS * P4_NHTT]; }; -/* - * A 'logical' CPU shares PMC resources with partner 'physical' CPU, - * except the TSC, which is architectural and hence seperate. The - * 'logical' CPU descriptor thus has pointers to the physical CPUs - * descriptor state except for the TSC (rowindex 0) which is not - * shared. - */ - -struct p4_logicalcpu { - struct pmc_cpu pc_common; - struct pmc_hw *pc_hwpmcs[P4_NPMCS]; - struct pmc_hw pc_tsc; -}; +static struct p4_cpu **p4_pcpu; #define P4_PCPU_PMC_VALUE(PC,RI,CPU) (PC)->pc_pmc_values[(RI)*((CPU) & 1)] #define P4_PCPU_HW_VALUE(PC,RI,CPU) (PC)->pc_si.pc_hw[(RI)*((CPU) & 1)] @@ -579,8 +536,8 @@ p4_find_event(enum pmc_event ev) if (p4_events[n].pm_event == ev) break; if (n == P4_NEVENTS) - return NULL; - return &p4_events[n]; + return (NULL); + return (&p4_events[n]); } /* @@ -588,13 +545,13 @@ p4_find_event(enum pmc_event ev) */ static int -p4_init(int cpu) +p4_pcpu_init(struct pmc_mdep *md, int cpu) { - int n, phycpu; char *pescr; - struct p4_cpu *pcs; - struct p4_logicalcpu *plcs; + int n, first_ri, phycpu; struct pmc_hw *phw; + struct p4_cpu *p4c; + struct pmc_cpu *pc, *plc; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[p4,%d] insane cpu number %d", __LINE__, cpu)); @@ -602,6 +559,8 @@ p4_init(int cpu) PMCDBG(MDP,INI,0, "p4-init cpu=%d is-primary=%d", cpu, pmc_cpu_is_primary(cpu) != 0); + first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P4].pcd_ri; + /* * The two CPUs in an HT pair share their per-cpu state. * @@ -619,56 +578,50 @@ p4_init(int cpu) p4_system_has_htt = 1; phycpu = P4_TO_HTT_PRIMARY(cpu); - pcs = (struct p4_cpu *) pmc_pcpu[phycpu]; - PMCDBG(MDP,INI,1, "p4-init cpu=%d phycpu=%d pcs=%p", - cpu, phycpu, pcs); - KASSERT(pcs, - ("[p4,%d] Null Per-Cpu state cpu=%d phycpu=%d", __LINE__, - cpu, phycpu)); - if (pcs == NULL) /* decline to init */ - return ENXIO; - - plcs = malloc(sizeof(struct p4_logicalcpu), - M_PMC, M_WAITOK|M_ZERO); - - /* The TSC is architectural state and is not shared */ - plcs->pc_hwpmcs[0] = &plcs->pc_tsc; - plcs->pc_tsc.phw_state = PMC_PHW_FLAG_IS_ENABLED | - PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(0) | - PMC_PHW_FLAG_IS_SHAREABLE; - - /* Other PMCs are shared with the physical CPU */ - for (n = 1; n < P4_NPMCS; n++) - plcs->pc_hwpmcs[n] = pcs->pc_hwpmcs[n]; - - pmc_pcpu[cpu] = (struct pmc_cpu *) plcs; - return 0; + pc = pmc_pcpu[phycpu]; + plc = pmc_pcpu[cpu]; + + KASSERT(plc != pc, ("[p4,%d] per-cpu config error", __LINE__)); + + PMCDBG(MDP,INI,1, "p4-init cpu=%d phycpu=%d pc=%p", cpu, + phycpu, pc); + KASSERT(pc, ("[p4,%d] Null Per-Cpu state cpu=%d phycpu=%d", + __LINE__, cpu, phycpu)); + + /* PMCs are shared with the physical CPU. */ + for (n = 0; n < P4_NPMCS; n++) + plc->pc_hwpmcs[n + first_ri] = + pc->pc_hwpmcs[n + first_ri]; + + return (0); } - pcs = malloc(sizeof(struct p4_cpu), M_PMC, M_WAITOK|M_ZERO); + p4c = malloc(sizeof(struct p4_cpu), M_PMC, M_WAITOK|M_ZERO); + + if (p4c == NULL) + return (ENOMEM); + + pc = pmc_pcpu[cpu]; + + KASSERT(pc != NULL, ("[p4,%d] cpu %d null per-cpu", __LINE__, cpu)); - if (pcs == NULL) - return ENOMEM; - phw = pcs->pc_p4pmcs; + p4_pcpu[cpu] = p4c; + phw = p4c->pc_p4pmcs; for (n = 0; n < P4_NPMCS; n++, phw++) { phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n); phw->phw_pmc = NULL; - pcs->pc_hwpmcs[n] = phw; + pc->pc_hwpmcs[n + first_ri] = phw; } - /* Mark the TSC as shareable */ - pcs->pc_hwpmcs[0]->phw_state |= PMC_PHW_FLAG_IS_SHAREABLE; - - pescr = pcs->pc_escrs; + pescr = p4c->pc_escrs; for (n = 0; n < P4_NESCR; n++) *pescr++ = P4_INVALID_PMC_INDEX; - pmc_pcpu[cpu] = (struct pmc_cpu *) pcs; - mtx_init(&pcs->pc_mtx, "p4-pcpu", "pmc-leaf", MTX_SPIN); + mtx_init(&p4c->pc_mtx, "p4-pcpu", "pmc-leaf", MTX_SPIN); - return 0; + return (0); } /* @@ -676,74 +629,39 @@ p4_init(int cpu) */ static int -p4_cleanup(int cpu) +p4_pcpu_fini(struct pmc_mdep *md, int cpu) { - int i; - struct p4_cpu *pcs; + int first_ri, i; + struct p4_cpu *p4c; + struct pmc_cpu *pc; PMCDBG(MDP,INI,0, "p4-cleanup cpu=%d", cpu); - if ((pcs = (struct p4_cpu *) pmc_pcpu[cpu]) == NULL) - return 0; - - /* Turn off all PMCs on this CPU */ - for (i = 0; i < P4_NPMCS - 1; i++) - wrmsr(P4_CCCR_MSR_FIRST + i, - rdmsr(P4_CCCR_MSR_FIRST + i) & ~P4_CCCR_ENABLE); - - /* - * If the CPU is physical we need to teardown the - * full MD state. - */ - if (!P4_CPU_IS_HTT_SECONDARY(cpu)) - mtx_destroy(&pcs->pc_mtx); - - free(pcs, M_PMC); - - pmc_pcpu[cpu] = NULL; + pc = pmc_pcpu[cpu]; + first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P4].pcd_ri; - return 0; -} - -/* - * Context switch in. - */ - -static int -p4_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) -{ - (void) pc; - - PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, - (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) != 0); + for (i = 0; i < P4_NPMCS; i++) + pc->pc_hwpmcs[i + first_ri] = NULL; - /* enable the RDPMC instruction */ - if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) - load_cr4(rcr4() | CR4_PCE); + if (!pmc_cpu_is_primary(cpu) && (cpu & 1)) + return (0); - PMCDBG(MDP,SWI,2, "cr4=0x%x", (uint32_t) rcr4()); + p4c = p4_pcpu[cpu]; - return 0; -} - -/* - * Context switch out. - */ + KASSERT(p4c != NULL, ("[p4,%d] NULL pcpu", __LINE__)); -static int -p4_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) -{ - (void) pc; - (void) pp; /* can be null */ + /* Turn off all PMCs on this CPU */ + for (i = 0; i < P4_NPMCS - 1; i++) + wrmsr(P4_CCCR_MSR_FIRST + i, + rdmsr(P4_CCCR_MSR_FIRST + i) & ~P4_CCCR_ENABLE); - PMCDBG(MDP,SWO,1, "pc=%p pp=%p", pc, pp); + mtx_destroy(&p4c->pc_mtx); - /* always disallow the RDPMC instruction */ - load_cr4(rcr4() & ~CR4_PCE); + free(p4c, M_PMC); - PMCDBG(MDP,SWO,2, "cr4=0x%x", (uint32_t) rcr4()); + p4_pcpu[cpu] = NULL; - return 0; + return (0); } /* @@ -753,50 +671,27 @@ p4_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) static int p4_read_pmc(int cpu, int ri, pmc_value_t *v) { - enum pmc_mode mode; - struct p4pmc_descr *pd; struct pmc *pm; - struct p4_cpu *pc; - struct pmc_hw *phw; pmc_value_t tmp; + struct p4_cpu *pc; + enum pmc_mode mode; + struct p4pmc_descr *pd; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[p4,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < P4_NPMCS, ("[p4,%d] illegal row-index %d", __LINE__, ri)); - - if (ri == 0) { /* TSC */ -#ifdef DEBUG - pc = (struct p4_cpu *) pmc_pcpu[cpu]; - phw = pc->pc_hwpmcs[ri]; - pm = phw->phw_pmc; - - KASSERT(pm, ("[p4,%d] cpu=%d ri=%d not configured", __LINE__, - cpu, ri)); - KASSERT(PMC_TO_CLASS(pm) == PMC_CLASS_TSC, - ("[p4,%d] cpu=%d ri=%d not a TSC (%d)", __LINE__, cpu, ri, - PMC_TO_CLASS(pm))); - KASSERT(PMC_IS_COUNTING_MODE(PMC_TO_MODE(pm)), - ("[p4,%d] TSC counter in non-counting mode", __LINE__)); -#endif - *v = rdtsc(); - PMCDBG(MDP,REA,2, "p4-read -> %jx", *v); - return 0; - } - - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; - pd = &p4_pmcdesc[ri]; - pm = phw->phw_pmc; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + pm = pc->pc_p4pmcs[ri].phw_pmc; + pd = &p4_pmcdesc[ri]; KASSERT(pm != NULL, - ("[p4,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, - cpu, ri)); + ("[p4,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, cpu, ri)); KASSERT(pd->pm_descr.pd_class == PMC_TO_CLASS(pm), ("[p4,%d] class mismatch pd %d != id class %d", __LINE__, - pd->pm_descr.pd_class, PMC_TO_CLASS(pm))); + pd->pm_descr.pd_class, PMC_TO_CLASS(pm))); mode = PMC_TO_MODE(pm); @@ -822,7 +717,8 @@ p4_read_pmc(int cpu, int ri, pmc_value_t *v) *v = tmp; PMCDBG(MDP,REA,2, "p4-read -> %jx", *v); - return 0; + + return (0); } /* @@ -843,29 +739,8 @@ p4_write_pmc(int cpu, int ri, pmc_value_t v) KASSERT(ri >= 0 && ri < P4_NPMCS, ("[amd,%d] illegal row-index %d", __LINE__, ri)); - - /* - * The P4's TSC register is writeable, but we don't allow a - * write as changing the TSC's value could interfere with - * timekeeping and other system functions. - */ - if (ri == 0) { -#ifdef DEBUG - pc = (struct p4_cpu *) pmc_pcpu[cpu]; - phw = pc->pc_hwpmcs[ri]; - pm = phw->phw_pmc; - KASSERT(pm, ("[p4,%d] cpu=%d ri=%d not configured", __LINE__, - cpu, ri)); - KASSERT(PMC_TO_CLASS(pm) == PMC_CLASS_TSC, - ("[p4,%d] cpu=%d ri=%d not a TSC (%d)", __LINE__, - cpu, ri, PMC_TO_CLASS(pm))); -#endif - return 0; - } - - /* Shared PMCs */ - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + phw = &pc->pc_p4pmcs[ri]; pm = phw->phw_pmc; pd = &p4_pmcdesc[ri]; @@ -891,7 +766,7 @@ p4_write_pmc(int cpu, int ri, pmc_value_t v) else P4_PCPU_PMC_VALUE(pc,ri,cpu) = v; - return 0; + return (0); } /* @@ -914,25 +789,14 @@ p4_config_pmc(int cpu, int ri, struct pmc *pm) KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[p4,%d] illegal CPU %d", __LINE__, cpu)); + KASSERT(ri >= 0 && ri < P4_NPMCS, ("[p4,%d] illegal row-index %d", __LINE__, ri)); PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); - if (ri == 0) { /* TSC */ - pc = (struct p4_cpu *) pmc_pcpu[cpu]; - phw = pc->pc_hwpmcs[ri]; - - KASSERT(pm == NULL || phw->phw_pmc == NULL, - ("[p4,%d] hwpmc doubly config'ed", __LINE__)); - phw->phw_pmc = pm; - return 0; - } - - /* Shared PMCs */ - - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + phw = &pc->pc_p4pmcs[ri]; KASSERT(pm == NULL || phw->phw_pmc == NULL || (p4_system_has_htt && phw->phw_pmc == pm), @@ -975,7 +839,7 @@ p4_config_pmc(int cpu, int ri, struct pmc *pm) mtx_unlock_spin(&pc->pc_mtx); - return 0; + return (0); } /* @@ -985,19 +849,22 @@ p4_config_pmc(int cpu, int ri, struct pmc *pm) static int p4_get_config(int cpu, int ri, struct pmc **ppm) { - struct p4_cpu *pc; - struct pmc_hw *phw; int cfgflags; + struct p4_cpu *pc; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[p4,%d] illegal CPU %d", __LINE__, cpu)); + KASSERT(ri >= 0 && ri < P4_NPMCS, + ("[p4,%d] illegal row-index %d", __LINE__, ri)); - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; mtx_lock_spin(&pc->pc_mtx); cfgflags = P4_PCPU_GET_CFGFLAGS(pc,ri); mtx_unlock_spin(&pc->pc_mtx); if (cfgflags & P4_CPU_TO_FLAG(cpu)) - *ppm = phw->phw_pmc; /* PMC config'ed on this CPU */ + *ppm = pc->pc_p4pmcs[ri].phw_pmc; /* PMC config'ed on this CPU */ else *ppm = NULL; @@ -1062,31 +929,23 @@ p4_allocate_pmc(int cpu, int ri, struct pmc *pm, /* check class */ if (pd->pm_descr.pd_class != a->pm_class) - return EINVAL; + return (EINVAL); /* check requested capabilities */ caps = a->pm_caps; if ((pd->pm_descr.pd_caps & caps) != caps) - return EPERM; - - if (pd->pm_descr.pd_class == PMC_CLASS_TSC) { - /* TSC's are always allocated in system-wide counting mode */ - if (a->pm_ev != PMC_EV_TSC_TSC || - a->pm_mode != PMC_MODE_SC) - return EINVAL; - return 0; - } + return (EPERM); /* * If the system has HTT enabled, and the desired allocation * mode is process-private, and the PMC row disposition is not - * free (0), decline the allocation. + * FREE (0), decline the allocation. */ if (p4_system_has_htt && PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm)) && pmc_getrowdisp(ri) != 0) - return EBUSY; + return (EBUSY); KASSERT(pd->pm_descr.pd_class == PMC_CLASS_P4, ("[p4,%d] unknown PMC class %d", __LINE__, @@ -1094,10 +953,10 @@ p4_allocate_pmc(int cpu, int ri, struct pmc *pm, if (pm->pm_event < PMC_EV_P4_FIRST || pm->pm_event > PMC_EV_P4_LAST) - return EINVAL; + return (EINVAL); if ((pevent = p4_find_event(pm->pm_event)) == NULL) - return ESRCH; + return (ESRCH); PMCDBG(MDP,ALL,2, "pevent={ev=%d,escrsel=0x%x,cccrsel=0x%x,isti=%d}", pevent->pm_event, pevent->pm_escr_eventselect, @@ -1112,9 +971,9 @@ p4_allocate_pmc(int cpu, int ri, struct pmc *pm, if (P4_EVENT_IS_TI(pevent) && PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm)) && p4_system_has_htt) - return EINVAL; + return (EINVAL); - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; found = 0; @@ -1170,7 +1029,7 @@ p4_allocate_pmc(int cpu, int ri, struct pmc *pm, } if (found == 0) - return ESRCH; + return (ESRCH); KASSERT((int) escr >= 0 && escr < P4_NESCR, ("[p4,%d] illegal ESCR value %d", __LINE__, escr)); @@ -1243,7 +1102,7 @@ p4_allocate_pmc(int cpu, int ri, struct pmc *pm, "escr=%d escrmsr=0x%x escrval=0x%x", pevent->pm_cccr_select, cccrvalue, escr, pm->pm_md.pm_p4.pm_p4_escrmsr, escrvalue); - return 0; + return (0); } /* @@ -1254,21 +1113,19 @@ static int p4_release_pmc(int cpu, int ri, struct pmc *pm) { enum pmc_p4escr escr; - struct pmc_hw *phw; struct p4_cpu *pc; - if (p4_pmcdesc[ri].pm_descr.pd_class == PMC_CLASS_TSC) - return 0; + KASSERT(ri >= 0 && ri < P4_NPMCS, + ("[p4,%d] illegal row-index %d", __LINE__, ri)); escr = pm->pm_md.pm_p4.pm_p4_escr; PMCDBG(MDP,REL,1, "p4-release cpu=%d ri=%d escr=%d", cpu, ri, escr); if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pm))) { - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - KASSERT(phw->phw_pmc == NULL, + KASSERT(pc->pc_p4pmcs[ri].phw_pmc == NULL, ("[p4,%d] releasing configured PMC ri=%d", __LINE__, ri)); P4_ESCR_UNMARK_ROW_STANDALONE(escr); @@ -1279,7 +1136,7 @@ p4_release_pmc(int cpu, int ri, struct pmc *pm) } else P4_ESCR_UNMARK_ROW_THREAD(escr); - return 0; + return (0); } /* @@ -1290,31 +1147,25 @@ static int p4_start_pmc(int cpu, int ri) { int rc; - uint32_t cccrvalue, cccrtbits, escrvalue, escrmsr, escrtbits; struct pmc *pm; struct p4_cpu *pc; - struct pmc_hw *phw; struct p4pmc_descr *pd; + uint32_t cccrvalue, cccrtbits, escrvalue, escrmsr, escrtbits; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[p4,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < P4_NPMCS, ("[p4,%d] illegal row-index %d", __LINE__, ri)); - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; - pm = phw->phw_pmc; - pd = &p4_pmcdesc[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + pm = pc->pc_p4pmcs[ri].phw_pmc; + pd = &p4_pmcdesc[ri]; KASSERT(pm != NULL, - ("[p4,%d] starting cpu%d,pmc%d with null pmc", __LINE__, - cpu, ri)); + ("[p4,%d] starting cpu%d,pmc%d with null pmc", __LINE__, cpu, ri)); PMCDBG(MDP,STA,1, "p4-start cpu=%d ri=%d", cpu, ri); - if (pd->pm_descr.pd_class == PMC_CLASS_TSC) /* TSC are always on */ - return 0; - KASSERT(pd->pm_descr.pd_class == PMC_CLASS_P4, ("[p4,%d] wrong PMC class %d", __LINE__, pd->pm_descr.pd_class)); @@ -1430,7 +1281,7 @@ p4_start_pmc(int cpu, int ri) ri, pm->pm_md.pm_p4.pm_p4_escr, escrmsr, escrvalue, cccrvalue, P4_PCPU_HW_VALUE(pc,ri,cpu)); - return 0; + return (0); } /* @@ -1444,7 +1295,6 @@ p4_stop_pmc(int cpu, int ri) uint32_t cccrvalue, cccrtbits, escrvalue, escrmsr, escrtbits; struct pmc *pm; struct p4_cpu *pc; - struct pmc_hw *phw; struct p4pmc_descr *pd; pmc_value_t tmp; @@ -1453,18 +1303,9 @@ p4_stop_pmc(int cpu, int ri) KASSERT(ri >= 0 && ri < P4_NPMCS, ("[p4,%d] illegal row index %d", __LINE__, ri)); - pd = &p4_pmcdesc[ri]; - - if (pd->pm_descr.pd_class == PMC_CLASS_TSC) - return 0; - - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; - phw = pc->pc_hwpmcs[ri]; - - KASSERT(phw != NULL, - ("[p4,%d] null phw for cpu%d, ri%d", __LINE__, cpu, ri)); - - pm = phw->phw_pmc; + pd = &p4_pmcdesc[ri]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + pm = pc->pc_p4pmcs[ri].phw_pmc; KASSERT(pm != NULL, ("[p4,%d] null pmc for cpu%d, ri%d", __LINE__, cpu, ri)); @@ -1474,7 +1315,7 @@ p4_stop_pmc(int cpu, int ri) if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pm))) { wrmsr(pd->pm_cccr_msr, pm->pm_md.pm_p4.pm_p4_cccrvalue & ~P4_CCCR_ENABLE); - return 0; + return (0); } /* @@ -1569,8 +1410,7 @@ static int p4_intr(int cpu, struct trapframe *tf) { uint32_t cccrval, ovf_mask, ovf_partner; - int i, did_interrupt, error, ri; - struct pmc_hw *phw; + int did_interrupt, error, ri; struct p4_cpu *pc; struct pmc *pm; pmc_value_t v; @@ -1578,7 +1418,7 @@ p4_intr(int cpu, struct trapframe *tf) PMCDBG(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf, TRAPF_USERMODE(tf)); - pc = (struct p4_cpu *) pmc_pcpu[P4_TO_HTT_PRIMARY(cpu)]; + pc = p4_pcpu[P4_TO_HTT_PRIMARY(cpu)]; ovf_mask = P4_CPU_IS_HTT_SECONDARY(cpu) ? P4_CCCR_OVF_PMI_T1 : P4_CCCR_OVF_PMI_T0; @@ -1597,9 +1437,7 @@ p4_intr(int cpu, struct trapframe *tf) * Loop through all CCCRs, looking for ones that have * interrupted this CPU. */ - for (i = 0; i < P4_NPMCS-1; i++) { - - ri = i + 1; /* row index */ + for (ri = 0; ri < P4_NPMCS; ri++) { /* * Check if our partner logical CPU has already marked @@ -1615,8 +1453,7 @@ p4_intr(int cpu, struct trapframe *tf) * Ignore de-configured or stopped PMCs. * Ignore PMCs not in sampling mode. */ - phw = pc->pc_hwpmcs[ri]; - pm = phw->phw_pmc; + pm = pc->pc_p4pmcs[ri].phw_pmc; if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { @@ -1632,7 +1469,7 @@ p4_intr(int cpu, struct trapframe *tf) * and the OVF_Tx bit for this logical * processor being set. */ - cccrval = rdmsr(P4_CCCR_MSR_FIRST + i); + cccrval = rdmsr(P4_CCCR_MSR_FIRST + ri); if ((cccrval & ovf_mask) != ovf_mask) continue; @@ -1646,13 +1483,13 @@ p4_intr(int cpu, struct trapframe *tf) if (p4_system_has_htt && (cccrval & ovf_partner)) P4_PCPU_SET_INTRFLAG(pc, ri, 1); - v = rdmsr(P4_PERFCTR_MSR_FIRST + i); + v = rdmsr(P4_PERFCTR_MSR_FIRST + ri); PMCDBG(MDP,INT, 2, "ri=%d v=%jx", ri, v); /* Stop the counter, and reset the overflow bit */ cccrval &= ~(P4_CCCR_OVF | P4_CCCR_ENABLE); - wrmsr(P4_CCCR_MSR_FIRST + i, cccrval); + wrmsr(P4_CCCR_MSR_FIRST + ri, cccrval); did_interrupt = 1; @@ -1660,8 +1497,7 @@ p4_intr(int cpu, struct trapframe *tf) * Ignore de-configured or stopped PMCs. Ignore PMCs * not in sampling mode. */ - phw = pc->pc_hwpmcs[ri]; - pm = phw->phw_pmc; + pm = pc->pc_p4pmcs[ri].phw_pmc; if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || @@ -1683,9 +1519,9 @@ p4_intr(int cpu, struct trapframe *tf) */ v = P4_RELOAD_COUNT_TO_PERFCTR_VALUE( pm->pm_sc.pm_reloadcount); - wrmsr(P4_PERFCTR_MSR_FIRST + i, v); + wrmsr(P4_PERFCTR_MSR_FIRST + ri, v); if (error == 0) - wrmsr(P4_CCCR_MSR_FIRST + i, + wrmsr(P4_CCCR_MSR_FIRST + ri, cccrval | P4_CCCR_ENABLE); } @@ -1718,7 +1554,6 @@ p4_describe(int cpu, int ri, struct pmc_info *pi, { int error; size_t copied; - struct pmc_hw *phw; const struct p4pmc_descr *pd; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), @@ -1729,26 +1564,25 @@ p4_describe(int cpu, int ri, struct pmc_info *pi, PMCDBG(MDP,OPS,1,"p4-describe cpu=%d ri=%d", cpu, ri); if (P4_CPU_IS_HTT_SECONDARY(cpu)) - return EINVAL; + return (EINVAL); - phw = pmc_pcpu[cpu]->pc_hwpmcs[ri]; pd = &p4_pmcdesc[ri]; if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name, - PMC_NAME_MAX, &copied)) != 0) - return error; + PMC_NAME_MAX, &copied)) != 0) + return (error); pi->pm_class = pd->pm_descr.pd_class; - if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { + if (p4_pcpu[cpu]->pc_p4pmcs[ri].phw_state & PMC_PHW_FLAG_IS_ENABLED) { pi->pm_enabled = TRUE; - *ppmc = phw->phw_pmc; + *ppmc = p4_pcpu[cpu]->pc_p4pmcs[ri].phw_pmc; } else { pi->pm_enabled = FALSE; *ppmc = NULL; } - return 0; + return (0); } /* @@ -1770,41 +1604,52 @@ p4_get_msr(int ri, uint32_t *msr) int -pmc_initialize_p4(struct pmc_mdep *pmc_mdep) +pmc_p4_initialize(struct pmc_mdep *md, int ncpus) { + struct pmc_classdep *pcd; struct p4_event_descr *pe; + KASSERT(md != NULL, ("[p4,%d] md is NULL", __LINE__)); KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0, ("[p4,%d] Initializing non-intel processor", __LINE__)); PMCDBG(MDP,INI,1, "%s", "p4-initialize"); - switch (pmc_mdep->pmd_cputype) { + /* Allocate space for pointers to per-cpu descriptors. */ + p4_pcpu = malloc(sizeof(struct p4_cpu **) * ncpus, M_PMC, + M_ZERO|M_WAITOK); + + /* Fill in the class dependent descriptor. */ + pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P4]; + + switch (md->pmd_cputype) { case PMC_CPU_INTEL_PIV: - pmc_mdep->pmd_npmc = P4_NPMCS; - pmc_mdep->pmd_classes[1].pm_class = PMC_CLASS_P4; - pmc_mdep->pmd_classes[1].pm_caps = P4_PMC_CAPS; - pmc_mdep->pmd_classes[1].pm_width = 40; - pmc_mdep->pmd_nclasspmcs[1] = 18; - - pmc_mdep->pmd_init = p4_init; - pmc_mdep->pmd_cleanup = p4_cleanup; - pmc_mdep->pmd_switch_in = p4_switch_in; - pmc_mdep->pmd_switch_out = p4_switch_out; - pmc_mdep->pmd_read_pmc = p4_read_pmc; - pmc_mdep->pmd_write_pmc = p4_write_pmc; - pmc_mdep->pmd_config_pmc = p4_config_pmc; - pmc_mdep->pmd_get_config = p4_get_config; - pmc_mdep->pmd_allocate_pmc = p4_allocate_pmc; - pmc_mdep->pmd_release_pmc = p4_release_pmc; - pmc_mdep->pmd_start_pmc = p4_start_pmc; - pmc_mdep->pmd_stop_pmc = p4_stop_pmc; - pmc_mdep->pmd_intr = p4_intr; - pmc_mdep->pmd_describe = p4_describe; - pmc_mdep->pmd_get_msr = p4_get_msr; /* i386 */ - - /* model specific munging */ + pcd->pcd_caps = P4_PMC_CAPS; + pcd->pcd_class = PMC_CLASS_P4; + pcd->pcd_num = P4_NPMCS; + pcd->pcd_ri = md->pmd_npmc; + pcd->pcd_width = 40; + + pcd->pcd_allocate_pmc = p4_allocate_pmc; + pcd->pcd_config_pmc = p4_config_pmc; + pcd->pcd_describe = p4_describe; + pcd->pcd_get_config = p4_get_config; + pcd->pcd_get_msr = p4_get_msr; + pcd->pcd_pcpu_fini = p4_pcpu_fini; + pcd->pcd_pcpu_init = p4_pcpu_init; + pcd->pcd_read_pmc = p4_read_pmc; + pcd->pcd_release_pmc = p4_release_pmc; + pcd->pcd_start_pmc = p4_start_pmc; + pcd->pcd_stop_pmc = p4_stop_pmc; + pcd->pcd_write_pmc = p4_write_pmc; + + md->pmd_pcpu_fini = NULL; + md->pmd_pcpu_init = NULL; + md->pmd_intr = p4_intr; + md->pmd_npmc += P4_NPMCS; + + /* model specific configuration */ if ((cpu_id & 0xFFF) < 0xF27) { /* @@ -1824,5 +1669,26 @@ pmc_initialize_p4(struct pmc_mdep *pmc_mdep) return ENOSYS; } - return 0; + return (0); +} + +void +pmc_p4_finalize(struct pmc_mdep *md) +{ +#if defined(INVARIANTS) + int i, ncpus; +#endif + + KASSERT(p4_pcpu != NULL, + ("[p4,%d] NULL p4_pcpu", __LINE__)); + +#if defined(INVARIANTS) + ncpus = pmc_cpu_max(); + for (i = 0; i < ncpus; i++) + KASSERT(p4_pcpu[i] == NULL, ("[p4,%d] non-null pcpu %d", + __LINE__, i)); +#endif + + free(p4_pcpu, M_PMC); + p4_pcpu = NULL; } |