|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* pfmlib_coreduo.c : Intel Core Duo/Solo
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Copyright (c) 2009 Google, Inc
|
|
Packit Service |
a1973e |
* Contributed by Stephane Eranian <eranian@gmail.com>
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit Service |
a1973e |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit Service |
a1973e |
* in the Software without restriction, including without limitation the rights
|
|
Packit Service |
a1973e |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit Service |
a1973e |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit Service |
a1973e |
* subject to the following conditions:
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit Service |
a1973e |
* copies or substantial portions of the Software.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit Service |
a1973e |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit Service |
a1973e |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit Service |
a1973e |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit Service |
a1973e |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit Service |
a1973e |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* This file implements support for Intel Core Duo/Solor PMU as specified in the
|
|
Packit Service |
a1973e |
* following document:
|
|
Packit Service |
a1973e |
* "IA-32 Intel Architecture Software Developer's Manual - Volume 3B: System
|
|
Packit Service |
a1973e |
* Programming Guide"
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Core Dup/Solo PMU = architectural perfmon v1 + model specific events
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
#include <sys/types.h>
|
|
Packit Service |
a1973e |
#include <ctype.h>
|
|
Packit Service |
a1973e |
#include <string.h>
|
|
Packit Service |
a1973e |
#include <stdlib.h>
|
|
Packit Service |
a1973e |
#include <stdio.h>
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* public headers */
|
|
Packit Service |
a1973e |
#include <perfmon/pfmlib_coreduo.h>
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* private headers */
|
|
Packit Service |
a1973e |
#include "pfmlib_priv.h"
|
|
Packit Service |
a1973e |
#include "pfmlib_coreduo_priv.h"
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#include "coreduo_events.h"
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* let's define some handy shortcuts! */
|
|
Packit Service |
a1973e |
#define sel_event_select perfevtsel.sel_event_select
|
|
Packit Service |
a1973e |
#define sel_unit_mask perfevtsel.sel_unit_mask
|
|
Packit Service |
a1973e |
#define sel_usr perfevtsel.sel_usr
|
|
Packit Service |
a1973e |
#define sel_os perfevtsel.sel_os
|
|
Packit Service |
a1973e |
#define sel_edge perfevtsel.sel_edge
|
|
Packit Service |
a1973e |
#define sel_pc perfevtsel.sel_pc
|
|
Packit Service |
a1973e |
#define sel_int perfevtsel.sel_int
|
|
Packit Service |
a1973e |
#define sel_en perfevtsel.sel_en
|
|
Packit Service |
a1973e |
#define sel_inv perfevtsel.sel_inv
|
|
Packit Service |
a1973e |
#define sel_cnt_mask perfevtsel.sel_cnt_mask
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* Description of the PMC register mappings:
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* 0 -> PMC0 -> PERFEVTSEL0
|
|
Packit Service |
a1973e |
* 1 -> PMC1 -> PERFEVTSEL1
|
|
Packit Service |
a1973e |
* 16 -> PMC16 -> FIXED_CTR_CTRL
|
|
Packit Service |
a1973e |
* 17 -> PMC17 -> PEBS_ENABLED
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* Description of the PMD register mapping:
|
|
Packit Service |
a1973e |
*
|
|
Packit Service |
a1973e |
* 0 -> PMD0 -> PMC0
|
|
Packit Service |
a1973e |
* 1 -> PMD1 -> PMC1
|
|
Packit Service |
a1973e |
* 16 -> PMD2 -> FIXED_CTR0
|
|
Packit Service |
a1973e |
* 17 -> PMD3 -> FIXED_CTR1
|
|
Packit Service |
a1973e |
* 18 -> PMD4 -> FIXED_CTR2
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
#define COREDUO_SEL_BASE 0x186
|
|
Packit Service |
a1973e |
#define COREDUO_CTR_BASE 0xc1
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
#define PFMLIB_COREDUO_ALL_FLAGS \
|
|
Packit Service |
a1973e |
(PFM_COREDUO_SEL_INV|PFM_COREDUO_SEL_EDGE)
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static pfmlib_regmask_t coreduo_impl_pmcs, coreduo_impl_pmds;
|
|
Packit Service |
a1973e |
static int highest_counter;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_detect(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
char buffer[128];
|
|
Packit Service |
a1973e |
int family, model;
|
|
Packit Service |
a1973e |
int ret;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ret = __pfm_getcpuinfo_attr("vendor_id", buffer, sizeof(buffer));
|
|
Packit Service |
a1973e |
if (ret == -1)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (strcmp(buffer, "GenuineIntel"))
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ret = __pfm_getcpuinfo_attr("cpu family", buffer, sizeof(buffer));
|
|
Packit Service |
a1973e |
if (ret == -1)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
family = atoi(buffer);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit Service |
a1973e |
if (ret == -1)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
model = atoi(buffer);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
return family == 6 && model == 14 ? PFMLIB_SUCCESS : PFMLIB_ERR_NOTSUPP;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_init(void)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
pfm_regmask_set(&coreduo_impl_pmcs, 0);
|
|
Packit Service |
a1973e |
pfm_regmask_set(&coreduo_impl_pmcs, 1);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pfm_regmask_set(&coreduo_impl_pmds, 0);
|
|
Packit Service |
a1973e |
pfm_regmask_set(&coreduo_impl_pmds, 1);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
highest_counter = 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* IMPORTANT: the interface guarantees that pfp_pmds[] elements are returned in the order the events
|
|
Packit Service |
a1973e |
* were submitted.
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_dispatch_counters(pfmlib_input_param_t *inp, pfmlib_coreduo_input_param_t *param, pfmlib_output_param_t *outp)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
#define HAS_OPTIONS(x) (cntrs && (cntrs[x].flags || cntrs[x].cnt_mask))
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pfm_coreduo_counter_t *cntrs;
|
|
Packit Service |
a1973e |
pfm_coreduo_sel_reg_t reg;
|
|
Packit Service |
a1973e |
pfmlib_event_t *e;
|
|
Packit Service |
a1973e |
pfmlib_reg_t *pc, *pd;
|
|
Packit Service |
a1973e |
pfmlib_regmask_t *r_pmcs;
|
|
Packit Service |
a1973e |
uint64_t val;
|
|
Packit Service |
a1973e |
unsigned long plm;
|
|
Packit Service |
a1973e |
unsigned int npc, npmc0, npmc1, nf2;
|
|
Packit Service |
a1973e |
unsigned int i, n, k, ucode;
|
|
Packit Service |
a1973e |
unsigned int assign_pc[PMU_COREDUO_NUM_COUNTERS];
|
|
Packit Service |
a1973e |
unsigned int next_gen, last_gen;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
npc = npmc0 = npmc1 = nf2 = 0;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
e = inp->pfp_events;
|
|
Packit Service |
a1973e |
pc = outp->pfp_pmcs;
|
|
Packit Service |
a1973e |
pd = outp->pfp_pmds;
|
|
Packit Service |
a1973e |
n = inp->pfp_event_count;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
r_pmcs = &inp->pfp_unavail_pmcs;
|
|
Packit Service |
a1973e |
cntrs = param ? param->pfp_coreduo_counters : NULL;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (n > PMU_COREDUO_NUM_COUNTERS)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_TOOMANY;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* initilize to empty
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
for(i=0; i < PMU_COREDUO_NUM_COUNTERS; i++)
|
|
Packit Service |
a1973e |
assign_pc[i] = -1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* error checking
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
for(i=0; i < n; i++) {
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* only supports two priv levels for perf counters
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (e[i].plm & (PFM_PLM1|PFM_PLM2))
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_INVAL;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* check for valid flags
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (cntrs && cntrs[i].flags & ~PFMLIB_COREDUO_ALL_FLAGS)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_INVAL;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* check event-level single register constraint (PMC0, PMC1, FIXED_CTR2)
|
|
Packit Service |
a1973e |
* fail if more than two events requested for the same counter
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_PMC0) {
|
|
Packit Service |
a1973e |
if (++npmc0 > 1) {
|
|
Packit Service |
a1973e |
DPRINT("two events compete for a PMC0\n");
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* check if PMC1 is available and if only one event is dependent on it
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_PMC1) {
|
|
Packit Service |
a1973e |
if (++npmc1 > 1) {
|
|
Packit Service |
a1973e |
DPRINT("two events compete for a PMC1\n");
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
next_gen = 0; /* first generic counter */
|
|
Packit Service |
a1973e |
last_gen = 1; /* last generic counter */
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* strongest constraint first: works only in IA32_PMC0, IA32_PMC1
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
for(i=0; i < n; i++) {
|
|
Packit Service |
a1973e |
if ((coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_PMC0)) {
|
|
Packit Service |
a1973e |
if (pfm_regmask_isset(r_pmcs, 0))
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
assign_pc[i] = 0;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
next_gen++;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if (coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_PMC1) {
|
|
Packit Service |
a1973e |
if (pfm_regmask_isset(r_pmcs, 1))
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
assign_pc[i] = 1;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
next_gen = (next_gen+1) % PMU_COREDUO_NUM_COUNTERS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* assign what is left
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
for(i=0; i < n; i++) {
|
|
Packit Service |
a1973e |
if (assign_pc[i] == -1) {
|
|
Packit Service |
a1973e |
for(; next_gen <= last_gen; next_gen++) {
|
|
Packit Service |
a1973e |
DPRINT("i=%d next_gen=%d last=%d isset=%d\n", i, next_gen, last_gen, pfm_regmask_isset(r_pmcs, next_gen));
|
|
Packit Service |
a1973e |
if (!pfm_regmask_isset(r_pmcs, next_gen))
|
|
Packit Service |
a1973e |
break;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
if (next_gen <= last_gen)
|
|
Packit Service |
a1973e |
assign_pc[i] = next_gen++;
|
|
Packit Service |
a1973e |
else {
|
|
Packit Service |
a1973e |
DPRINT("cannot assign generic counters\n");
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for (i=0; i < n ; i++ ) {
|
|
Packit Service |
a1973e |
reg.val = 0; /* assume reserved bits are zerooed */
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/* if plm is 0, then assume not specified per-event and use default */
|
|
Packit Service |
a1973e |
plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
val = coreduo_pe[e[i].event].pme_code;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
reg.sel_event_select = val & 0xff;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
ucode = (val >> 8) & 0xff;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
for(k=0; k < e[i].num_masks; k++) {
|
|
Packit Service |
a1973e |
ucode |= coreduo_pe[e[i].event].pme_umasks[e[i].unit_masks[k]].pme_ucode;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* for events supporting Core specificity (self, both), a value
|
|
Packit Service |
a1973e |
* of 0 for bits 15:14 (7:6 in our umask) is reserved, therefore we
|
|
Packit Service |
a1973e |
* force to SELF if user did not specify anything
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if ((coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_CSPEC)
|
|
Packit Service |
a1973e |
&& ((ucode & (0x3 << 6)) == 0)) {
|
|
Packit Service |
a1973e |
ucode |= 1 << 6;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* for events supporting MESI, a value
|
|
Packit Service |
a1973e |
* of 0 for bits 11:8 (0-3 in our umask) means nothing will be
|
|
Packit Service |
a1973e |
* counted. Therefore, we force a default of 0xf (M,E,S,I).
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if ((coreduo_pe[e[i].event].pme_flags & PFMLIB_COREDUO_MESI)
|
|
Packit Service |
a1973e |
&& ((ucode & 0xf) == 0)) {
|
|
Packit Service |
a1973e |
ucode |= 0xf;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
val |= ucode << 8;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
reg.sel_unit_mask = ucode;
|
|
Packit Service |
a1973e |
reg.sel_usr = plm & PFM_PLM3 ? 1 : 0;
|
|
Packit Service |
a1973e |
reg.sel_os = plm & PFM_PLM0 ? 1 : 0;
|
|
Packit Service |
a1973e |
reg.sel_en = 1; /* force enable bit to 1 */
|
|
Packit Service |
a1973e |
reg.sel_int = 1; /* force APIC int to 1 */
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
reg.sel_cnt_mask = val >>24;
|
|
Packit Service |
a1973e |
reg.sel_inv = val >> 23;
|
|
Packit Service |
a1973e |
reg.sel_edge = val >> 18;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (cntrs) {
|
|
Packit Service |
a1973e |
if (!reg.sel_cnt_mask) {
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* counter mask is 8-bit wide, do not silently
|
|
Packit Service |
a1973e |
* wrap-around
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
if (cntrs[i].cnt_mask > 255)
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_INVAL;
|
|
Packit Service |
a1973e |
reg.sel_cnt_mask = cntrs[i].cnt_mask;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (!reg.sel_edge)
|
|
Packit Service |
a1973e |
reg.sel_edge = cntrs[i].flags & PFM_COREDUO_SEL_EDGE ? 1 : 0;
|
|
Packit Service |
a1973e |
if (!reg.sel_inv)
|
|
Packit Service |
a1973e |
reg.sel_inv = cntrs[i].flags & PFM_COREDUO_SEL_INV ? 1 : 0;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pc[npc].reg_num = assign_pc[i];
|
|
Packit Service |
a1973e |
pc[npc].reg_value = reg.val;
|
|
Packit Service |
a1973e |
pc[npc].reg_addr = COREDUO_SEL_BASE+assign_pc[i];
|
|
Packit Service |
a1973e |
pc[npc].reg_alt_addr= COREDUO_SEL_BASE+assign_pc[i];
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%"PRIx64" event_sel=0x%x umask=0x%x os=%d usr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d] %s\n",
|
|
Packit Service |
a1973e |
pc[npc].reg_num,
|
|
Packit Service |
a1973e |
pc[npc].reg_num,
|
|
Packit Service |
a1973e |
reg.val,
|
|
Packit Service |
a1973e |
reg.sel_event_select,
|
|
Packit Service |
a1973e |
reg.sel_unit_mask,
|
|
Packit Service |
a1973e |
reg.sel_os,
|
|
Packit Service |
a1973e |
reg.sel_usr,
|
|
Packit Service |
a1973e |
reg.sel_en,
|
|
Packit Service |
a1973e |
reg.sel_int,
|
|
Packit Service |
a1973e |
reg.sel_inv,
|
|
Packit Service |
a1973e |
reg.sel_edge,
|
|
Packit Service |
a1973e |
reg.sel_cnt_mask,
|
|
Packit Service |
a1973e |
coreduo_pe[e[i].event].pme_name);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
__pfm_vbprintf("[PMC%u(pmd%u)]\n",
|
|
Packit Service |
a1973e |
pc[npc].reg_num,
|
|
Packit Service |
a1973e |
pc[npc].reg_num);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
npc++;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* setup pmds: must be in the same order as the events
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
for (i=0; i < n ; i++) {
|
|
Packit Service |
a1973e |
pd[i].reg_num = assign_pc[i];
|
|
Packit Service |
a1973e |
pd[i].reg_addr = COREDUO_CTR_BASE+assign_pc[i];
|
|
Packit Service |
a1973e |
/* index to use with RDPMC */
|
|
Packit Service |
a1973e |
pd[i].reg_alt_addr = assign_pc[i];
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
outp->pfp_pmd_count = i;
|
|
Packit Service |
a1973e |
outp->pfp_pmc_count = npc;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_dispatch_events(pfmlib_input_param_t *inp, void *model_in, pfmlib_output_param_t *outp, void *model_out)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
pfmlib_coreduo_input_param_t *mod_in = (pfmlib_coreduo_input_param_t *)model_in;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (inp->pfp_dfl_plm & (PFM_PLM1|PFM_PLM2)) {
|
|
Packit Service |
a1973e |
DPRINT("invalid plm=%x\n", inp->pfp_dfl_plm);
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_INVAL;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
return pfm_coreduo_dispatch_counters(inp, mod_in, outp);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_code(unsigned int i, unsigned int cnt, int *code)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
if (cnt != PFMLIB_CNT_FIRST
|
|
Packit Service |
a1973e |
&& (cnt > highest_counter ||
|
|
Packit Service |
a1973e |
!pfm_regmask_isset(&coreduo_impl_pmds, cnt)))
|
|
Packit Service |
a1973e |
return PFMLIB_ERR_INVAL;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
*code = coreduo_pe[i].pme_code;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_counters(unsigned int j, pfmlib_regmask_t *counters)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
memset(counters, 0, sizeof(*counters));
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pfm_regmask_set(counters, 0);
|
|
Packit Service |
a1973e |
pfm_regmask_set(counters, 1);
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
if (coreduo_pe[j].pme_flags & PFMLIB_COREDUO_PMC0)
|
|
Packit Service |
a1973e |
pfm_regmask_clr(counters, 1);
|
|
Packit Service |
a1973e |
if (coreduo_pe[j].pme_flags & PFMLIB_COREDUO_PMC1)
|
|
Packit Service |
a1973e |
pfm_regmask_clr(counters, 0);
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
pfm_coreduo_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
*impl_pmcs = coreduo_impl_pmcs;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
pfm_coreduo_get_impl_pmds(pfmlib_regmask_t *impl_pmds)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
*impl_pmds = coreduo_impl_pmds;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
pfm_coreduo_get_impl_counters(pfmlib_regmask_t *impl_counters)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
/* all pmds are counters */
|
|
Packit Service |
a1973e |
*impl_counters = coreduo_impl_pmds;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* Even though, CPUID 0xa returns in eax the actual counter
|
|
Packit Service |
a1973e |
* width, the architecture specifies that writes are limited
|
|
Packit Service |
a1973e |
* to lower 32-bits. As such, only the lower 32-bit have full
|
|
Packit Service |
a1973e |
* degree of freedom. That is the "useable" counter width.
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
static void
|
|
Packit Service |
a1973e |
pfm_coreduo_get_hw_counter_width(unsigned int *width)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
/*
|
|
Packit Service |
a1973e |
* Even though, CPUID 0xa returns in eax the actual counter
|
|
Packit Service |
a1973e |
* width, the architecture specifies that writes are limited
|
|
Packit Service |
a1973e |
* to lower 32-bits. As such, only the lower 31 bits have full
|
|
Packit Service |
a1973e |
* degree of freedom. That is the "useable" counter width.
|
|
Packit Service |
a1973e |
*/
|
|
Packit Service |
a1973e |
*width = 32;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static char *
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_name(unsigned int i)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
return coreduo_pe[i].pme_name;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_description(unsigned int ev, char **str)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
char *s;
|
|
Packit Service |
a1973e |
s = coreduo_pe[ev].pme_desc;
|
|
Packit Service |
a1973e |
if (s) {
|
|
Packit Service |
a1973e |
*str = strdup(s);
|
|
Packit Service |
a1973e |
} else {
|
|
Packit Service |
a1973e |
*str = NULL;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static char *
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_mask_name(unsigned int ev, unsigned int midx)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
return coreduo_pe[ev].pme_umasks[midx].pme_uname;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_mask_desc(unsigned int ev, unsigned int midx, char **str)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
char *s;
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
s = coreduo_pe[ev].pme_umasks[midx].pme_udesc;
|
|
Packit Service |
a1973e |
if (s) {
|
|
Packit Service |
a1973e |
*str = strdup(s);
|
|
Packit Service |
a1973e |
} else {
|
|
Packit Service |
a1973e |
*str = NULL;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static unsigned int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_num_event_masks(unsigned int ev)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
return coreduo_pe[ev].pme_numasks;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_event_mask_code(unsigned int ev, unsigned int midx, unsigned int *code)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
*code = coreduo_pe[ev].pme_umasks[midx].pme_ucode;
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_cycle_event(pfmlib_event_t *e)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
e->event = PME_COREDUO_UNHALTED_CORE_CYCLES;
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
static int
|
|
Packit Service |
a1973e |
pfm_coreduo_get_inst_retired(pfmlib_event_t *e)
|
|
Packit Service |
a1973e |
{
|
|
Packit Service |
a1973e |
e->event = PME_COREDUO_INSTRUCTIONS_RETIRED;
|
|
Packit Service |
a1973e |
return PFMLIB_SUCCESS;
|
|
Packit Service |
a1973e |
}
|
|
Packit Service |
a1973e |
|
|
Packit Service |
a1973e |
pfm_pmu_support_t coreduo_support={
|
|
Packit Service |
a1973e |
.pmu_name = "Intel Core Duo/Solo",
|
|
Packit Service |
a1973e |
.pmu_type = PFMLIB_COREDUO_PMU,
|
|
Packit Service |
a1973e |
.pme_count = PME_COREDUO_EVENT_COUNT,
|
|
Packit Service |
a1973e |
.pmc_count = 2,
|
|
Packit Service |
a1973e |
.pmd_count = 2,
|
|
Packit Service |
a1973e |
.num_cnt = 2,
|
|
Packit Service |
a1973e |
.get_event_code = pfm_coreduo_get_event_code,
|
|
Packit Service |
a1973e |
.get_event_name = pfm_coreduo_get_event_name,
|
|
Packit Service |
a1973e |
.get_event_counters = pfm_coreduo_get_event_counters,
|
|
Packit Service |
a1973e |
.dispatch_events = pfm_coreduo_dispatch_events,
|
|
Packit Service |
a1973e |
.pmu_detect = pfm_coreduo_detect,
|
|
Packit Service |
a1973e |
.pmu_init = pfm_coreduo_init,
|
|
Packit Service |
a1973e |
.get_impl_pmcs = pfm_coreduo_get_impl_pmcs,
|
|
Packit Service |
a1973e |
.get_impl_pmds = pfm_coreduo_get_impl_pmds,
|
|
Packit Service |
a1973e |
.get_impl_counters = pfm_coreduo_get_impl_counters,
|
|
Packit Service |
a1973e |
.get_hw_counter_width = pfm_coreduo_get_hw_counter_width,
|
|
Packit Service |
a1973e |
.get_event_desc = pfm_coreduo_get_event_description,
|
|
Packit Service |
a1973e |
.get_num_event_masks = pfm_coreduo_get_num_event_masks,
|
|
Packit Service |
a1973e |
.get_event_mask_name = pfm_coreduo_get_event_mask_name,
|
|
Packit Service |
a1973e |
.get_event_mask_code = pfm_coreduo_get_event_mask_code,
|
|
Packit Service |
a1973e |
.get_event_mask_desc = pfm_coreduo_get_event_mask_desc,
|
|
Packit Service |
a1973e |
.get_cycle_event = pfm_coreduo_get_cycle_event,
|
|
Packit Service |
a1973e |
.get_inst_retired_event = pfm_coreduo_get_inst_retired
|
|
Packit Service |
a1973e |
};
|