Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hwpmc/hwpmc_amd.c
Show First 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | static struct amd_descr amd_pmcdesc[AMD_NPMCS] = | ||||
{ | { | ||||
.pd_name = "", | .pd_name = "", | ||||
.pd_class = -1, | .pd_class = -1, | ||||
.pd_caps = AMD_PMC_CAPS, | .pd_caps = AMD_PMC_CAPS, | ||||
.pd_width = 48 | .pd_width = 48 | ||||
}, | }, | ||||
.pm_evsel = AMD_PMC_EVSEL_3, | .pm_evsel = AMD_PMC_EVSEL_3, | ||||
.pm_perfctr = AMD_PMC_PERFCTR_3 | .pm_perfctr = AMD_PMC_PERFCTR_3 | ||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_4, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_4 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_5, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_5 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_0, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_0 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_1, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_1 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_2, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_2 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_3, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_3 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_4, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_4 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_L3_5, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_L3_5 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_DF_0, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_DF_0 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_DF_1, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_DF_1 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_DF_2, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_DF_2 | |||||
}, | |||||
{ | |||||
.pm_descr = | |||||
{ | |||||
.pd_name = "", | |||||
.pd_class = -1, | |||||
.pd_caps = AMD_PMC_CAPS, | |||||
.pd_width = 48 | |||||
}, | |||||
.pm_evsel = AMD_PMC_EVSEL_EP_DF_3, | |||||
.pm_perfctr = AMD_PMC_PERFCTR_EP_DF_3 | |||||
} | } | ||||
}; | }; | ||||
struct amd_event_code_map { | struct amd_event_code_map { | ||||
enum pmc_event pe_ev; /* enum value */ | enum pmc_event pe_ev; /* enum value */ | ||||
uint16_t pe_code; /* encoded event mask */ | uint16_t pe_code; /* encoded event mask */ | ||||
uint8_t pe_mask; /* bits allowed in unit mask */ | uint8_t pe_mask; /* bits allowed in unit mask */ | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 313 Lines • ▼ Show 20 Lines | |||||
* Check if a given allocation is feasible. | * Check if a given allocation is feasible. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_allocate_pmc(int cpu, int ri, struct pmc *pm, | amd_allocate_pmc(int cpu, int ri, struct pmc *pm, | ||||
const struct pmc_op_pmcallocate *a) | const struct pmc_op_pmcallocate *a) | ||||
{ | { | ||||
int i; | int i; | ||||
uint32_t allowed_unitmask, caps, config, unitmask; | uint64_t allowed_unitmask, caps, config, unitmask; | ||||
enum pmc_event pe; | enum pmc_event pe; | ||||
const struct pmc_descr *pd; | const struct pmc_descr *pd; | ||||
(void) cpu; | (void) cpu; | ||||
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)); | ||||
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; | ||||
PMCDBG2(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((ri >= 0 && ri < 6) && !(a->pm_md.pm_amd.pm_amd_sub_class == PMC_AMD_SUB_CLASS_CORE)) | |||||
return EINVAL; | |||||
if((ri >= 6 && ri < 12) && !(a->pm_md.pm_amd.pm_amd_sub_class == PMC_AMD_SUB_CLASS_L3_CACHE)) | |||||
return EINVAL; | |||||
if((ri >= 12 && ri < 16) && !(a->pm_md.pm_amd.pm_amd_sub_class == PMC_AMD_SUB_CLASS_DATA_FABRIC)) | |||||
return EINVAL; | |||||
if ((pd->pd_caps & caps) != caps) | if ((pd->pd_caps & caps) != caps) | ||||
return EPERM; | return EPERM; | ||||
if (strlen(pmc_cpuid) != 0) { | if (strlen(pmc_cpuid) != 0) { | ||||
pm->pm_md.pm_amd.pm_amd_evsel = | pm->pm_md.pm_amd.pm_amd_evsel = | ||||
a->pm_md.pm_amd.pm_amd_config; | a->pm_md.pm_amd.pm_amd_config; | ||||
PMCDBG2(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, a->pm_md.pm_amd.pm_amd_config); | PMCDBG2(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, a->pm_md.pm_amd.pm_amd_config); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* start a PMC. | * start a PMC. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_start_pmc(int cpu, int ri) | amd_start_pmc(int cpu, int ri) | ||||
{ | { | ||||
uint32_t config; | uint64_t config; | ||||
struct pmc *pm; | struct pmc *pm; | ||||
struct pmc_hw *phw; | struct pmc_hw *phw; | ||||
const struct amd_descr *pd; | const struct amd_descr *pd; | ||||
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)); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
* to sleep or do anything a 'fast' interrupt handler is not allowed | * to sleep or do anything a 'fast' interrupt handler is not allowed | ||||
* to do. | * to do. | ||||
*/ | */ | ||||
static int | static int | ||||
amd_intr(struct trapframe *tf) | amd_intr(struct trapframe *tf) | ||||
{ | { | ||||
int i, error, retval, cpu; | int i, error, retval, cpu; | ||||
uint32_t config, evsel, perfctr; | uint64_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; | ||||
cpu = curcpu; | cpu = curcpu; | ||||
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)); | ||||
Show All 35 Lines | for (i = 0; retval == 0 && i < AMD_NPMCS; i++) { | ||||
/* Stop the PMC, reload count. */ | /* Stop the PMC, reload count. */ | ||||
evsel = AMD_PMC_EVSEL_0 + i; | evsel = AMD_PMC_EVSEL_0 + i; | ||||
perfctr = AMD_PMC_PERFCTR_0 + i; | perfctr = AMD_PMC_PERFCTR_0 + i; | ||||
v = pm->pm_sc.pm_reloadcount; | v = pm->pm_sc.pm_reloadcount; | ||||
config = rdmsr(evsel); | config = rdmsr(evsel); | ||||
KASSERT((config & ~AMD_PMC_ENABLE) == | KASSERT((config & ~AMD_PMC_ENABLE) == | ||||
(pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE), | (pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE), | ||||
("[amd,%d] config mismatch reg=0x%x pm=0x%x", __LINE__, | ("[amd,%d] config mismatch reg=0x%jx pm=0x%jx", __LINE__, | ||||
config, pm->pm_md.pm_amd.pm_amd_evsel)); | (uintmax_t)config, (uintmax_t)pm->pm_md.pm_amd.pm_amd_evsel)); | ||||
wrmsr(evsel, config & ~AMD_PMC_ENABLE); | wrmsr(evsel, config & ~AMD_PMC_ENABLE); | ||||
wrmsr(perfctr, AMD_RELOAD_COUNT_TO_PERFCTR_VALUE(v)); | wrmsr(perfctr, AMD_RELOAD_COUNT_TO_PERFCTR_VALUE(v)); | ||||
/* Restart the counter if logging succeeded. */ | /* Restart the counter if logging succeeded. */ | ||||
error = pmc_process_interrupt(PMC_HR, pm, tf); | error = pmc_process_interrupt(PMC_HR, pm, tf); | ||||
if (error == 0) | if (error == 0) | ||||
wrmsr(evsel, config); | wrmsr(evsel, config); | ||||
▲ Show 20 Lines • Show All 349 Lines • Show Last 20 Lines |