|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* pfmlib_i386_pm.c : support for the P6 processor family (family=6)
|
|
Packit |
577717 |
* incl. Pentium II, Pentium III, Pentium Pro, Pentium M
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
|
|
Packit |
577717 |
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
577717 |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
577717 |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
577717 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
577717 |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit |
577717 |
* subject to the following conditions:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit |
577717 |
* copies or substantial portions of the Software.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit |
577717 |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit |
577717 |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
577717 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
577717 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit |
577717 |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <sys/types.h>
|
|
Packit |
577717 |
#include <ctype.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
/* public headers */
|
|
Packit |
577717 |
#include <perfmon/pfmlib_i386_p6.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* private headers */
|
|
Packit |
577717 |
#include "pfmlib_priv.h" /* library private */
|
|
Packit |
577717 |
#include "pfmlib_i386_p6_priv.h" /* architecture private */
|
|
Packit |
577717 |
#include "i386_p6_events.h" /* event tables */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* let's define some handy shortcuts! */
|
|
Packit |
577717 |
#define sel_event_mask perfsel.sel_event_mask
|
|
Packit |
577717 |
#define sel_unit_mask perfsel.sel_unit_mask
|
|
Packit |
577717 |
#define sel_usr perfsel.sel_usr
|
|
Packit |
577717 |
#define sel_os perfsel.sel_os
|
|
Packit |
577717 |
#define sel_edge perfsel.sel_edge
|
|
Packit |
577717 |
#define sel_pc perfsel.sel_pc
|
|
Packit |
577717 |
#define sel_int perfsel.sel_int
|
|
Packit |
577717 |
#define sel_en perfsel.sel_en
|
|
Packit |
577717 |
#define sel_inv perfsel.sel_inv
|
|
Packit |
577717 |
#define sel_cnt_mask perfsel.sel_cnt_mask
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static char * pfm_i386_p6_get_event_name(unsigned int i);
|
|
Packit |
577717 |
static pme_i386_p6_entry_t *i386_pe;
|
|
Packit |
577717 |
static int i386_p6_cycle_event, i386_p6_inst_retired_event;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PFMLIB_I386_P6_HAS_COMBO(_e) ((i386_pe[_e].pme_flags & PFMLIB_I386_P6_UMASK_COMBO) != 0)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PFMLIB_I386_P6_ALL_FLAGS \
|
|
Packit |
577717 |
(PFM_I386_P6_SEL_INV|PFM_I386_P6_SEL_EDGE)
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Description of the PMC register mappings use by
|
|
Packit |
577717 |
* this module.
|
|
Packit |
577717 |
* pfp_pmcs[].reg_num:
|
|
Packit |
577717 |
* 0 -> PMC0 -> PERFEVTSEL0 -> MSR @ 0x186
|
|
Packit |
577717 |
* 1 -> PMC1 -> PERFEVTSEL1 -> MSR @ 0x187
|
|
Packit |
577717 |
* pfp_pmds[].reg_num:
|
|
Packit |
577717 |
* 0 -> PMD0 -> PERFCTR0 -> MSR @ 0xc1
|
|
Packit |
577717 |
* 1 -> PMD1 -> PERFCTR1 -> MSR @ 0xc2
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#define I386_P6_SEL_BASE 0x186
|
|
Packit |
577717 |
#define I386_P6_CTR_BASE 0xc1
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void pfm_i386_p6_get_impl_counters(pfmlib_regmask_t *impl_counters);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_detect_common(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret, family;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("vendor_id", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (strcmp(buffer, "GenuineIntel"))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("cpu family", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
family = atoi(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return family != 6 ? PFMLIB_ERR_NOTSUPP : PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* detect Pentium Pro
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_detect_ppro(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret, model;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = pfm_i386_detect_common();
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
model = atoi(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (model != 1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_init_ppro(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
i386_pe = i386_ppro_pe;
|
|
Packit |
577717 |
i386_p6_cycle_event = PME_I386_PPRO_CPU_CLK_UNHALTED;
|
|
Packit |
577717 |
i386_p6_inst_retired_event = PME_I386_PPRO_INST_RETIRED;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* detect Pentium II
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_detect_pii(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret, model;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = pfm_i386_detect_common();
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
model = atoi(buffer);
|
|
Packit |
577717 |
switch(model) {
|
|
Packit |
577717 |
case 3: /* Pentium II */
|
|
Packit |
577717 |
case 5: /* Pentium II Deschutes */
|
|
Packit |
577717 |
case 6: /* Pentium II Mendocino */
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_init_pii(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
|
|
Packit |
577717 |
i386_pe = i386_pII_pe;
|
|
Packit |
577717 |
i386_p6_cycle_event = PME_I386_PII_CPU_CLK_UNHALTED;
|
|
Packit |
577717 |
i386_p6_inst_retired_event = PME_I386_PII_INST_RETIRED;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* detect Pentium III
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_detect_piii(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret, model;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = pfm_i386_detect_common();
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
model = atoi(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch(model) {
|
|
Packit |
577717 |
case 7: /* Pentium III Katmai */
|
|
Packit |
577717 |
case 8: /* Pentium III Coppermine */
|
|
Packit |
577717 |
case 10:/* Pentium III Cascades */
|
|
Packit |
577717 |
case 11:/* Pentium III Tualatin */
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_init_piii(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
i386_pe = i386_pIII_pe;
|
|
Packit |
577717 |
i386_p6_cycle_event = PME_I386_PIII_CPU_CLK_UNHALTED;
|
|
Packit |
577717 |
i386_p6_inst_retired_event = PME_I386_PIII_INST_RETIRED;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* detect Pentium M
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_detect_pm(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret, model;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = pfm_i386_detect_common();
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
model = atoi(buffer);
|
|
Packit |
577717 |
switch (model) {
|
|
Packit |
577717 |
case 9:
|
|
Packit |
577717 |
case 13:
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_init_pm(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
i386_pe = i386_pm_pe;
|
|
Packit |
577717 |
i386_p6_cycle_event = PME_I386_PM_CPU_CLK_UNHALTED;
|
|
Packit |
577717 |
i386_p6_inst_retired_event = PME_I386_PM_INST_RETIRED;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Automatically dispatch events to corresponding counters following constraints.
|
|
Packit |
577717 |
* Upon return the pfarg_regt structure is ready to be submitted to kernel
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_dispatch_counters(pfmlib_input_param_t *inp, pfmlib_i386_p6_input_param_t *mod_in, pfmlib_output_param_t *outp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_i386_p6_input_param_t *param = mod_in;
|
|
Packit |
577717 |
pfmlib_i386_p6_counter_t *cntrs;
|
|
Packit |
577717 |
pfm_i386_p6_sel_reg_t reg;
|
|
Packit |
577717 |
pfmlib_event_t *e;
|
|
Packit |
577717 |
pfmlib_reg_t *pc, *pd;
|
|
Packit |
577717 |
pfmlib_regmask_t impl_cntrs, avail_cntrs;
|
|
Packit |
577717 |
unsigned long plm;
|
|
Packit |
577717 |
unsigned int i, j, cnt, k, umask;
|
|
Packit |
577717 |
unsigned int assign[PMU_I386_P6_NUM_COUNTERS];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e = inp->pfp_events;
|
|
Packit |
577717 |
pc = outp->pfp_pmcs;
|
|
Packit |
577717 |
pd = outp->pfp_pmds;
|
|
Packit |
577717 |
cnt = inp->pfp_event_count;
|
|
Packit |
577717 |
cntrs = param ? param->pfp_i386_p6_counters : NULL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (PFMLIB_DEBUG()) {
|
|
Packit |
577717 |
for (j=0; j < cnt; j++) {
|
|
Packit |
577717 |
DPRINT("ev[%d]=%s\n", j, i386_pe[e[j].event].pme_name);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cnt > PMU_I386_P6_NUM_COUNTERS)
|
|
Packit |
577717 |
return PFMLIB_ERR_TOOMANY;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_i386_p6_get_impl_counters(&impl_cntrs);
|
|
Packit |
577717 |
pfm_regmask_andnot(&avail_cntrs, &impl_cntrs, &inp->pfp_unavail_pmcs);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
DPRINT("impl=0x%lx avail=0x%lx unavail=0x%lx\n", impl_cntrs.bits[0], avail_cntrs.bits[0], inp->pfp_unavail_pmcs.bits[0]);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(j=0; j < cnt; j++) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* P6 only supports two priv levels for perf counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (e[j].plm & (PFM_PLM1|PFM_PLM2)) {
|
|
Packit |
577717 |
DPRINT("event=%d invalid plm=%d\n", e[j].event, e[j].plm);
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntrs && cntrs[j].flags & ~PFMLIB_I386_P6_ALL_FLAGS) {
|
|
Packit |
577717 |
DPRINT("event=%d invalid flags=0x%lx\n", e[j].event, e[j].flags);
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check illegal unit masks combination
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (e[j].num_masks > 1 && PFMLIB_I386_P6_HAS_COMBO(e[j].event) == 0) {
|
|
Packit |
577717 |
DPRINT("event does not support unit mask combination\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_FEATCOMB;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* first pass: events for fixed counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(j=0; j < cnt; j++) {
|
|
Packit |
577717 |
if (i386_pe[e[j].event].pme_flags & PFMLIB_I386_P6_CTR0_ONLY) {
|
|
Packit |
577717 |
if (!pfm_regmask_isset(&avail_cntrs, 0))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
assign[j] = 0;
|
|
Packit |
577717 |
pfm_regmask_clr(&avail_cntrs, 0);
|
|
Packit |
577717 |
} else if (i386_pe[e[j].event].pme_flags & PFMLIB_I386_P6_CTR1_ONLY) {
|
|
Packit |
577717 |
if (!pfm_regmask_isset(&avail_cntrs, 1))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
assign[j] = 1;
|
|
Packit |
577717 |
pfm_regmask_clr(&avail_cntrs, 1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* second pass: events with no constraints
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (j=0, i=0; j < cnt ; j++ ) {
|
|
Packit |
577717 |
if (i386_pe[e[j].event].pme_flags & (PFMLIB_I386_P6_CTR0_ONLY|PFMLIB_I386_P6_CTR1_ONLY))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while (i < PMU_I386_P6_NUM_COUNTERS && !pfm_regmask_isset(&avail_cntrs, i))
|
|
Packit |
577717 |
i++;
|
|
Packit |
577717 |
if (i == PMU_I386_P6_NUM_COUNTERS)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
pfm_regmask_clr(&avail_cntrs, i);
|
|
Packit |
577717 |
assign[j] = i++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* final pass: assign value to registers
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (j=0; j < cnt ; j++) {
|
|
Packit |
577717 |
reg.val = 0; /* assume reserved bits are zeroed */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* if plm is 0, then assume not specified per-event and use default */
|
|
Packit |
577717 |
plm = e[j].plm ? e[j].plm : inp->pfp_dfl_plm;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.sel_event_mask = i386_pe[e[j].event].pme_code;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* some events have only a single umask. We do not create
|
|
Packit |
577717 |
* specific umask entry in this case. The umask code is taken
|
|
Packit |
577717 |
* out of the (extended) event code (2nd byte)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
umask = (i386_pe[e[j].event].pme_code >> 8) & 0xff;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(k=0; k < e[j].num_masks; k++) {
|
|
Packit |
577717 |
umask |= i386_pe[e[j].event].pme_umasks[e[j].unit_masks[k]].pme_ucode;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
reg.sel_unit_mask = umask;
|
|
Packit |
577717 |
reg.sel_usr = plm & PFM_PLM3 ? 1 : 0;
|
|
Packit |
577717 |
reg.sel_os = plm & PFM_PLM0 ? 1 : 0;
|
|
Packit |
577717 |
reg.sel_int = 1; /* force APIC int to 1 */
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* only perfevtsel0 has an enable bit (allows atomic start/stop)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (assign[j] == 0)
|
|
Packit |
577717 |
reg.sel_en = 1; /* force enable bit to 1 */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntrs) {
|
|
Packit |
577717 |
reg.sel_cnt_mask = cntrs[j].cnt_mask;
|
|
Packit |
577717 |
reg.sel_edge = cntrs[j].flags & PFM_I386_P6_SEL_EDGE ? 1 : 0;
|
|
Packit |
577717 |
reg.sel_inv = cntrs[j].flags & PFM_I386_P6_SEL_INV ? 1 : 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pc[j].reg_num = assign[j];
|
|
Packit |
577717 |
pc[j].reg_value = reg.val;
|
|
Packit |
577717 |
pc[j].reg_addr = I386_P6_SEL_BASE+assign[j];
|
|
Packit |
577717 |
pc[j].reg_alt_addr= I386_P6_SEL_BASE+assign[j];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pd[j].reg_num = assign[j];
|
|
Packit |
577717 |
pd[j].reg_addr = I386_P6_CTR_BASE+assign[j];
|
|
Packit |
577717 |
/* index to use with RDPMC */
|
|
Packit |
577717 |
pd[j].reg_alt_addr = assign[j];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%lx emask=0x%x umask=0x%x os=%d usr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d] %s\n",
|
|
Packit |
577717 |
assign[j],
|
|
Packit |
577717 |
assign[j],
|
|
Packit |
577717 |
reg.val,
|
|
Packit |
577717 |
reg.sel_event_mask,
|
|
Packit |
577717 |
reg.sel_unit_mask,
|
|
Packit |
577717 |
reg.sel_os,
|
|
Packit |
577717 |
reg.sel_usr,
|
|
Packit |
577717 |
reg.sel_en,
|
|
Packit |
577717 |
reg.sel_int,
|
|
Packit |
577717 |
reg.sel_inv,
|
|
Packit |
577717 |
reg.sel_edge,
|
|
Packit |
577717 |
reg.sel_cnt_mask,
|
|
Packit |
577717 |
i386_pe[e[j].event].pme_name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PMC%u(pmd%u)]\n", pd[j].reg_num, pd[j].reg_num);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* add perfsel0 if not used. This is required as it holds
|
|
Packit |
577717 |
* the enable bit for all counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (pfm_regmask_isset(&avail_cntrs, 0)) {
|
|
Packit |
577717 |
reg.val = 0;
|
|
Packit |
577717 |
reg.sel_en = 1; /* force enable bit to 1 */
|
|
Packit |
577717 |
pc[j].reg_num = 0;
|
|
Packit |
577717 |
pc[j].reg_value = reg.val;
|
|
Packit |
577717 |
pc[j].reg_addr = I386_P6_SEL_BASE;
|
|
Packit |
577717 |
pc[j].reg_alt_addr = I386_P6_SEL_BASE;
|
|
Packit |
577717 |
j++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PERFEVTSEL0(pmc0)=0x%lx] required for enabling counters\n", reg.val);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* number of evtsel registers programmed */
|
|
Packit |
577717 |
outp->pfp_pmc_count = j;
|
|
Packit |
577717 |
outp->pfp_pmd_count = cnt;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_dispatch_events(pfmlib_input_param_t *inp, void *model_in, pfmlib_output_param_t *outp, void *model_out)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_i386_p6_input_param_t *mod_in = (pfmlib_i386_p6_input_param_t *)model_in;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (inp->pfp_dfl_plm & (PFM_PLM1|PFM_PLM2)) {
|
|
Packit |
577717 |
DPRINT("invalid plm=%x\n", inp->pfp_dfl_plm);
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return pfm_i386_p6_dispatch_counters(inp, mod_in, outp);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_event_code(unsigned int i, unsigned int cnt, int *code)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (cnt != PFMLIB_CNT_FIRST && cnt > 2)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
*code = i386_pe[i].pme_code;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_i386_p6_get_event_counters(unsigned int j, pfmlib_regmask_t *counters)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(counters, 0, sizeof(*counters));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (i386_pe[j].pme_flags & PFMLIB_I386_P6_CTR0_ONLY) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 0);
|
|
Packit |
577717 |
} else if (i386_pe[j].pme_flags & PFMLIB_I386_P6_CTR1_ONLY) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 1);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
for(i=0; i < PMU_I386_P6_NUM_COUNTERS; i++)
|
|
Packit |
577717 |
pfm_regmask_set(counters, i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_i386_p6_get_impl_perfsel(pfmlib_regmask_t *impl_pmcs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* all pmcs are contiguous */
|
|
Packit |
577717 |
for(i=0; i < PMU_I386_P6_NUM_PERFSEL; i++)
|
|
Packit |
577717 |
pfm_regmask_set(impl_pmcs, i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_i386_p6_get_impl_perfctr(pfmlib_regmask_t *impl_pmds)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* all pmds are contiguous */
|
|
Packit |
577717 |
for(i=0; i < PMU_I386_P6_NUM_PERFCTR; i++)
|
|
Packit |
577717 |
pfm_regmask_set(impl_pmds, i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_i386_p6_get_impl_counters(pfmlib_regmask_t *impl_counters)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* counting pmds are contiguous */
|
|
Packit |
577717 |
for(i=0; i < PMU_I386_P6_NUM_COUNTERS; i++)
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_i386_p6_get_hw_counter_width(unsigned int *width)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
*width = PMU_I386_P6_COUNTER_WIDTH;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static char *
|
|
Packit |
577717 |
pfm_i386_p6_get_event_name(unsigned int i)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return i386_pe[i].pme_name;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_event_description(unsigned int ev, char **str)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
char *s;
|
|
Packit |
577717 |
s = i386_pe[ev].pme_desc;
|
|
Packit |
577717 |
if (s) {
|
|
Packit |
577717 |
*str = strdup(s);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
*str = NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static char *
|
|
Packit |
577717 |
pfm_i386_p6_get_event_mask_name(unsigned int ev, unsigned int midx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return i386_pe[ev].pme_umasks[midx].pme_uname;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_event_mask_desc(unsigned int ev, unsigned int midx, char **str)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
char *s;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
s = i386_pe[ev].pme_umasks[midx].pme_udesc;
|
|
Packit |
577717 |
if (s) {
|
|
Packit |
577717 |
*str = strdup(s);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
*str = NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned int
|
|
Packit |
577717 |
pfm_i386_p6_get_num_event_masks(unsigned int ev)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return i386_pe[ev].pme_numasks;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_event_mask_code(unsigned int ev, unsigned int midx, unsigned int *code)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
*code = i386_pe[ev].pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_cycle_event(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
e->event = i386_p6_cycle_event;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_i386_p6_get_inst_retired(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
e->event = i386_p6_inst_retired_event;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* Pentium II support */
|
|
Packit |
577717 |
pfm_pmu_support_t i386_pii_support={
|
|
Packit |
577717 |
.pmu_name = "Intel Pentium II",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_INTEL_PII_PMU,
|
|
Packit |
577717 |
.pme_count = PME_I386_PII_EVENT_COUNT,
|
|
Packit |
577717 |
.pmc_count = PMU_I386_P6_NUM_PERFSEL,
|
|
Packit |
577717 |
.pmd_count = PMU_I386_P6_NUM_PERFCTR,
|
|
Packit |
577717 |
.num_cnt = PMU_I386_P6_NUM_COUNTERS,
|
|
Packit |
577717 |
.get_event_code = pfm_i386_p6_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_i386_p6_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_i386_p6_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_i386_p6_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_i386_p6_detect_pii,
|
|
Packit |
577717 |
.pmu_init = pfm_i386_p6_init_pii,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_i386_p6_get_impl_perfsel,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_i386_p6_get_impl_perfctr,
|
|
Packit |
577717 |
.get_impl_counters = pfm_i386_p6_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_i386_p6_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_i386_p6_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_i386_p6_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_i386_p6_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_i386_p6_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_i386_p6_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_i386_p6_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_i386_p6_get_inst_retired
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Generic P6 processor support (not incl. Pentium M) */
|
|
Packit |
577717 |
pfm_pmu_support_t i386_p6_support={
|
|
Packit |
577717 |
.pmu_name = "Intel P6 Processor Family",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_I386_P6_PMU,
|
|
Packit |
577717 |
.pme_count = PME_I386_PIII_EVENT_COUNT,
|
|
Packit |
577717 |
.pmc_count = PMU_I386_P6_NUM_PERFSEL,
|
|
Packit |
577717 |
.pmd_count = PMU_I386_P6_NUM_PERFCTR,
|
|
Packit |
577717 |
.num_cnt = PMU_I386_P6_NUM_COUNTERS,
|
|
Packit |
577717 |
.get_event_code = pfm_i386_p6_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_i386_p6_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_i386_p6_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_i386_p6_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_i386_p6_detect_piii,
|
|
Packit |
577717 |
.pmu_init = pfm_i386_p6_init_piii,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_i386_p6_get_impl_perfsel,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_i386_p6_get_impl_perfctr,
|
|
Packit |
577717 |
.get_impl_counters = pfm_i386_p6_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_i386_p6_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_i386_p6_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_i386_p6_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_i386_p6_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_i386_p6_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_i386_p6_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_i386_p6_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_i386_p6_get_inst_retired
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_pmu_support_t i386_ppro_support={
|
|
Packit |
577717 |
.pmu_name = "Intel Pentium Pro",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_INTEL_PPRO_PMU,
|
|
Packit |
577717 |
.pme_count = PME_I386_PPRO_EVENT_COUNT,
|
|
Packit |
577717 |
.pmc_count = PMU_I386_P6_NUM_PERFSEL,
|
|
Packit |
577717 |
.pmd_count = PMU_I386_P6_NUM_PERFCTR,
|
|
Packit |
577717 |
.num_cnt = PMU_I386_P6_NUM_COUNTERS,
|
|
Packit |
577717 |
.get_event_code = pfm_i386_p6_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_i386_p6_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_i386_p6_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_i386_p6_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_i386_p6_detect_ppro,
|
|
Packit |
577717 |
.pmu_init = pfm_i386_p6_init_ppro,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_i386_p6_get_impl_perfsel,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_i386_p6_get_impl_perfctr,
|
|
Packit |
577717 |
.get_impl_counters = pfm_i386_p6_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_i386_p6_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_i386_p6_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_i386_p6_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_i386_p6_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_i386_p6_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_i386_p6_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_i386_p6_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_i386_p6_get_inst_retired
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Pentium M support */
|
|
Packit |
577717 |
pfm_pmu_support_t i386_pm_support={
|
|
Packit |
577717 |
.pmu_name = "Intel Pentium M",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_I386_PM_PMU,
|
|
Packit |
577717 |
.pme_count = PME_I386_PM_EVENT_COUNT,
|
|
Packit |
577717 |
.pmc_count = PMU_I386_P6_NUM_PERFSEL,
|
|
Packit |
577717 |
.pmd_count = PMU_I386_P6_NUM_PERFCTR,
|
|
Packit |
577717 |
.num_cnt = PMU_I386_P6_NUM_COUNTERS,
|
|
Packit |
577717 |
.get_event_code = pfm_i386_p6_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_i386_p6_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_i386_p6_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_i386_p6_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_i386_p6_detect_pm,
|
|
Packit |
577717 |
.pmu_init = pfm_i386_p6_init_pm,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_i386_p6_get_impl_perfsel,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_i386_p6_get_impl_perfctr,
|
|
Packit |
577717 |
.get_impl_counters = pfm_i386_p6_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_i386_p6_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_i386_p6_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_i386_p6_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_i386_p6_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_i386_p6_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_i386_p6_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_i386_p6_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_i386_p6_get_inst_retired
|
|
Packit |
577717 |
};
|