Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hwpmc/hwpmc_amd.c
Show First 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | amd_read_pmc(int cpu, int ri, pmc_value_t *v) | ||||
pd = &amd_pmcdesc[ri]; | pd = &amd_pmcdesc[ri]; | ||||
KASSERT(pm != NULL, | KASSERT(pm != NULL, | ||||
("[amd,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, | ("[amd,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, | ||||
cpu, ri)); | cpu, ri)); | ||||
mode = PMC_TO_MODE(pm); | mode = PMC_TO_MODE(pm); | ||||
PMCDBG(MDP,REA,1,"amd-read id=%d class=%d", ri, pd->pm_descr.pd_class); | PMCDBG2(MDP,REA,1,"amd-read id=%d class=%d", ri, pd->pm_descr.pd_class); | ||||
#ifdef HWPMC_DEBUG | #ifdef HWPMC_DEBUG | ||||
KASSERT(pd->pm_descr.pd_class == amd_pmc_class, | KASSERT(pd->pm_descr.pd_class == amd_pmc_class, | ||||
("[amd,%d] unknown PMC class (%d)", __LINE__, | ("[amd,%d] unknown PMC class (%d)", __LINE__, | ||||
pd->pm_descr.pd_class)); | pd->pm_descr.pd_class)); | ||||
#endif | #endif | ||||
tmp = rdmsr(pd->pm_perfctr); /* RDMSR serializes */ | tmp = rdmsr(pd->pm_perfctr); /* RDMSR serializes */ | ||||
PMCDBG(MDP,REA,2,"amd-read (pre-munge) id=%d -> %jd", ri, tmp); | PMCDBG2(MDP,REA,2,"amd-read (pre-munge) id=%d -> %jd", ri, tmp); | ||||
if (PMC_IS_SAMPLING_MODE(mode)) { | if (PMC_IS_SAMPLING_MODE(mode)) { | ||||
/* Sign extend 48 bit value to 64 bits. */ | /* Sign extend 48 bit value to 64 bits. */ | ||||
tmp = (pmc_value_t) (((int64_t) tmp << 16) >> 16); | tmp = (pmc_value_t) (((int64_t) tmp << 16) >> 16); | ||||
tmp = AMD_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp); | tmp = AMD_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp); | ||||
} | } | ||||
*v = tmp; | *v = tmp; | ||||
PMCDBG(MDP,REA,2,"amd-read (post-munge) id=%d -> %jd", ri, *v); | PMCDBG2(MDP,REA,2,"amd-read (post-munge) id=%d -> %jd", ri, *v); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Write a PMC MSR. | * Write a PMC MSR. | ||||
*/ | */ | ||||
Show All 23 Lines | KASSERT(pd->pm_descr.pd_class == amd_pmc_class, | ||||
("[amd,%d] unknown PMC class (%d)", __LINE__, | ("[amd,%d] unknown PMC class (%d)", __LINE__, | ||||
pd->pm_descr.pd_class)); | pd->pm_descr.pd_class)); | ||||
#endif | #endif | ||||
/* use 2's complement of the count for sampling mode PMCs */ | /* use 2's complement of the count for sampling mode PMCs */ | ||||
if (PMC_IS_SAMPLING_MODE(mode)) | if (PMC_IS_SAMPLING_MODE(mode)) | ||||
v = AMD_RELOAD_COUNT_TO_PERFCTR_VALUE(v); | v = AMD_RELOAD_COUNT_TO_PERFCTR_VALUE(v); | ||||
PMCDBG(MDP,WRI,1,"amd-write cpu=%d ri=%d v=%jx", cpu, ri, v); | PMCDBG3(MDP,WRI,1,"amd-write cpu=%d ri=%d v=%jx", cpu, ri, v); | ||||
/* write the PMC value */ | /* write the PMC value */ | ||||
wrmsr(pd->pm_perfctr, v); | wrmsr(pd->pm_perfctr, v); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* configure hardware pmc according to the configuration recorded in | * configure hardware pmc according to the configuration recorded in | ||||
* pmc 'pm'. | * pmc 'pm'. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_config_pmc(int cpu, int ri, struct pmc *pm) | amd_config_pmc(int cpu, int ri, struct pmc *pm) | ||||
{ | { | ||||
struct pmc_hw *phw; | struct pmc_hw *phw; | ||||
PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); | PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); | ||||
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | ||||
("[amd,%d] illegal CPU value %d", __LINE__, cpu)); | ("[amd,%d] illegal CPU value %d", __LINE__, cpu)); | ||||
KASSERT(ri >= 0 && ri < AMD_NPMCS, | KASSERT(ri >= 0 && ri < AMD_NPMCS, | ||||
("[amd,%d] illegal row-index %d", __LINE__, ri)); | ("[amd,%d] illegal row-index %d", __LINE__, ri)); | ||||
phw = &amd_pcpu[cpu]->pc_amdpmcs[ri]; | phw = &amd_pcpu[cpu]->pc_amdpmcs[ri]; | ||||
Show All 22 Lines | |||||
* thread. | * thread. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) | amd_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) | ||||
{ | { | ||||
(void) pc; | (void) pc; | ||||
PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, | PMCDBG3(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, | ||||
(pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) != 0); | (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) != 0); | ||||
/* enable the RDPMC instruction if needed */ | /* enable the RDPMC instruction if needed */ | ||||
if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) | if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) | ||||
load_cr4(rcr4() | CR4_PCE); | load_cr4(rcr4() | CR4_PCE); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Machine dependent actions taken during the context switch out of a | * Machine dependent actions taken during the context switch out of a | ||||
* thread. | * thread. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) | amd_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) | ||||
{ | { | ||||
(void) pc; | (void) pc; | ||||
(void) pp; /* can be NULL */ | (void) pp; /* can be NULL */ | ||||
PMCDBG(MDP,SWO,1, "pc=%p pp=%p enable-msr=%d", pc, pp, pp ? | PMCDBG3(MDP,SWO,1, "pc=%p pp=%p enable-msr=%d", pc, pp, pp ? | ||||
(pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) == 1 : 0); | (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) == 1 : 0); | ||||
/* always turn off the RDPMC instruction */ | /* always turn off the RDPMC instruction */ | ||||
load_cr4(rcr4() & ~CR4_PCE); | load_cr4(rcr4() & ~CR4_PCE); | ||||
return 0; | return 0; | ||||
} | } | ||||
Show All 20 Lines | amd_allocate_pmc(int cpu, int ri, struct pmc *pm, | ||||
pd = &amd_pmcdesc[ri].pm_descr; | pd = &amd_pmcdesc[ri].pm_descr; | ||||
/* check class match */ | /* check class match */ | ||||
if (pd->pd_class != a->pm_class) | if (pd->pd_class != a->pm_class) | ||||
return EINVAL; | return EINVAL; | ||||
caps = pm->pm_caps; | caps = pm->pm_caps; | ||||
PMCDBG(MDP,ALL,1,"amd-allocate ri=%d caps=0x%x", ri, caps); | PMCDBG2(MDP,ALL,1,"amd-allocate ri=%d caps=0x%x", ri, caps); | ||||
if ((pd->pd_caps & caps) != caps) | if ((pd->pd_caps & caps) != caps) | ||||
return EPERM; | return EPERM; | ||||
pe = a->pm_ev; | pe = a->pm_ev; | ||||
/* map ev to the correct event mask code */ | /* map ev to the correct event mask code */ | ||||
config = allowed_unitmask = 0; | config = allowed_unitmask = 0; | ||||
Show All 30 Lines | if (caps & PMC_CAP_EDGE) | ||||
config |= AMD_PMC_EDGE; | config |= AMD_PMC_EDGE; | ||||
if (caps & PMC_CAP_INVERT) | if (caps & PMC_CAP_INVERT) | ||||
config |= AMD_PMC_INVERT; | config |= AMD_PMC_INVERT; | ||||
if (caps & PMC_CAP_INTERRUPT) | if (caps & PMC_CAP_INTERRUPT) | ||||
config |= AMD_PMC_INT; | config |= AMD_PMC_INT; | ||||
pm->pm_md.pm_amd.pm_amd_evsel = config; /* save config value */ | pm->pm_md.pm_amd.pm_amd_evsel = config; /* save config value */ | ||||
PMCDBG(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, config); | PMCDBG2(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, config); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Release machine dependent state associated with a PMC. This is a | * Release machine dependent state associated with a PMC. This is a | ||||
* no-op on this architecture. | * no-op on this architecture. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | amd_start_pmc(int cpu, int ri) | ||||
phw = &amd_pcpu[cpu]->pc_amdpmcs[ri]; | phw = &amd_pcpu[cpu]->pc_amdpmcs[ri]; | ||||
pm = phw->phw_pmc; | pm = phw->phw_pmc; | ||||
pd = &amd_pmcdesc[ri]; | pd = &amd_pmcdesc[ri]; | ||||
KASSERT(pm != NULL, | KASSERT(pm != NULL, | ||||
("[amd,%d] starting cpu%d,pmc%d with null pmc record", __LINE__, | ("[amd,%d] starting cpu%d,pmc%d with null pmc record", __LINE__, | ||||
cpu, ri)); | cpu, ri)); | ||||
PMCDBG(MDP,STA,1,"amd-start cpu=%d ri=%d", cpu, ri); | PMCDBG2(MDP,STA,1,"amd-start cpu=%d ri=%d", cpu, ri); | ||||
KASSERT(AMD_PMC_IS_STOPPED(pd->pm_evsel), | KASSERT(AMD_PMC_IS_STOPPED(pd->pm_evsel), | ||||
("[amd,%d] pmc%d,cpu%d: Starting active PMC \"%s\"", __LINE__, | ("[amd,%d] pmc%d,cpu%d: Starting active PMC \"%s\"", __LINE__, | ||||
ri, cpu, pd->pm_descr.pd_name)); | ri, cpu, pd->pm_descr.pd_name)); | ||||
/* turn on the PMC ENABLE bit */ | /* turn on the PMC ENABLE bit */ | ||||
config = pm->pm_md.pm_amd.pm_amd_evsel | AMD_PMC_ENABLE; | config = pm->pm_md.pm_amd.pm_amd_evsel | AMD_PMC_ENABLE; | ||||
PMCDBG(MDP,STA,2,"amd-start config=0x%x", config); | PMCDBG1(MDP,STA,2,"amd-start config=0x%x", config); | ||||
wrmsr(pd->pm_evsel, config); | wrmsr(pd->pm_evsel, config); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Stop a PMC. | * Stop a PMC. | ||||
*/ | */ | ||||
Show All 17 Lines | amd_stop_pmc(int cpu, int ri) | ||||
KASSERT(pm != NULL, | KASSERT(pm != NULL, | ||||
("[amd,%d] cpu%d,pmc%d no PMC to stop", __LINE__, | ("[amd,%d] cpu%d,pmc%d no PMC to stop", __LINE__, | ||||
cpu, ri)); | cpu, ri)); | ||||
KASSERT(!AMD_PMC_IS_STOPPED(pd->pm_evsel), | KASSERT(!AMD_PMC_IS_STOPPED(pd->pm_evsel), | ||||
("[amd,%d] PMC%d, CPU%d \"%s\" already stopped", | ("[amd,%d] PMC%d, CPU%d \"%s\" already stopped", | ||||
__LINE__, ri, cpu, pd->pm_descr.pd_name)); | __LINE__, ri, cpu, pd->pm_descr.pd_name)); | ||||
PMCDBG(MDP,STO,1,"amd-stop ri=%d", ri); | PMCDBG1(MDP,STO,1,"amd-stop ri=%d", ri); | ||||
/* turn off the PMC ENABLE bit */ | /* turn off the PMC ENABLE bit */ | ||||
config = pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE; | config = pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE; | ||||
wrmsr(pd->pm_evsel, config); | wrmsr(pd->pm_evsel, config); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
Show All 10 Lines | amd_intr(int cpu, struct trapframe *tf) | ||||
uint32_t config, evsel, perfctr; | uint32_t config, evsel, perfctr; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
struct amd_cpu *pac; | struct amd_cpu *pac; | ||||
pmc_value_t v; | pmc_value_t v; | ||||
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | ||||
("[amd,%d] out of range CPU %d", __LINE__, cpu)); | ("[amd,%d] out of range CPU %d", __LINE__, cpu)); | ||||
PMCDBG(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf, | PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf, | ||||
TRAPF_USERMODE(tf)); | TRAPF_USERMODE(tf)); | ||||
retval = 0; | retval = 0; | ||||
pac = amd_pcpu[cpu]; | pac = amd_pcpu[cpu]; | ||||
/* | /* | ||||
* look for all PMCs that have interrupted: | * look for all PMCs that have interrupted: | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | amd_pcpu_init(struct pmc_mdep *md, int cpu) | ||||
int classindex, first_ri, n; | int classindex, first_ri, n; | ||||
struct pmc_cpu *pc; | struct pmc_cpu *pc; | ||||
struct amd_cpu *pac; | struct amd_cpu *pac; | ||||
struct pmc_hw *phw; | struct pmc_hw *phw; | ||||
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | ||||
("[amd,%d] insane cpu number %d", __LINE__, cpu)); | ("[amd,%d] insane cpu number %d", __LINE__, cpu)); | ||||
PMCDBG(MDP,INI,1,"amd-init cpu=%d", cpu); | PMCDBG1(MDP,INI,1,"amd-init cpu=%d", cpu); | ||||
amd_pcpu[cpu] = pac = malloc(sizeof(struct amd_cpu), M_PMC, | amd_pcpu[cpu] = pac = malloc(sizeof(struct amd_cpu), M_PMC, | ||||
M_WAITOK|M_ZERO); | M_WAITOK|M_ZERO); | ||||
/* | /* | ||||
* Set the content of the hardware descriptors to a known | * Set the content of the hardware descriptors to a known | ||||
* state and initialize pointers in the MI per-cpu descriptor. | * state and initialize pointers in the MI per-cpu descriptor. | ||||
*/ | */ | ||||
Show All 30 Lines | amd_pcpu_fini(struct pmc_mdep *md, int cpu) | ||||
int classindex, first_ri, i; | int classindex, first_ri, i; | ||||
uint32_t evsel; | uint32_t evsel; | ||||
struct pmc_cpu *pc; | struct pmc_cpu *pc; | ||||
struct amd_cpu *pac; | struct amd_cpu *pac; | ||||
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), | ||||
("[amd,%d] insane cpu number (%d)", __LINE__, cpu)); | ("[amd,%d] insane cpu number (%d)", __LINE__, cpu)); | ||||
PMCDBG(MDP,INI,1,"amd-cleanup cpu=%d", cpu); | PMCDBG1(MDP,INI,1,"amd-cleanup cpu=%d", cpu); | ||||
/* | /* | ||||
* First, turn off all PMCs on this CPU. | * First, turn off all PMCs on this CPU. | ||||
*/ | */ | ||||
for (i = 0; i < 4; i++) { /* XXX this loop is now not needed */ | for (i = 0; i < 4; i++) { /* XXX this loop is now not needed */ | ||||
evsel = rdmsr(AMD_PMC_EVSEL_0 + i); | evsel = rdmsr(AMD_PMC_EVSEL_0 + i); | ||||
evsel &= ~AMD_PMC_ENABLE; | evsel &= ~AMD_PMC_ENABLE; | ||||
wrmsr(AMD_PMC_EVSEL_0 + i, evsel); | wrmsr(AMD_PMC_EVSEL_0 + i, evsel); | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | #endif | ||||
pmc_mdep->pmd_pcpu_init = NULL; | pmc_mdep->pmd_pcpu_init = NULL; | ||||
pmc_mdep->pmd_pcpu_fini = NULL; | pmc_mdep->pmd_pcpu_fini = NULL; | ||||
pmc_mdep->pmd_intr = amd_intr; | pmc_mdep->pmd_intr = amd_intr; | ||||
pmc_mdep->pmd_switch_in = amd_switch_in; | pmc_mdep->pmd_switch_in = amd_switch_in; | ||||
pmc_mdep->pmd_switch_out = amd_switch_out; | pmc_mdep->pmd_switch_out = amd_switch_out; | ||||
pmc_mdep->pmd_npmc += AMD_NPMCS; | pmc_mdep->pmd_npmc += AMD_NPMCS; | ||||
PMCDBG(MDP,INI,0,"%s","amd-initialize"); | PMCDBG0(MDP,INI,0,"amd-initialize"); | ||||
return (pmc_mdep); | return (pmc_mdep); | ||||
error: | error: | ||||
if (error) { | if (error) { | ||||
free(pmc_mdep, M_PMC); | free(pmc_mdep, M_PMC); | ||||
pmc_mdep = NULL; | pmc_mdep = NULL; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • Show Last 20 Lines |