Blame src/libpfm-3.y/lib/pfmlib_intel_atom.c

Packit 577717
/*
Packit 577717
 * pfmlib_intel_atom.c : Intel Atom PMU
Packit 577717
 *
Packit 577717
 * Copyright (c) 2008 Google, Inc
Packit 577717
 * Contributed by Stephane Eranian <eranian@gmail.com>
Packit 577717
 *
Packit 577717
 * Based on work:
Packit 577717
 * Copyright (c) 2006 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
 *
Packit 577717
 * This file implements support for Intel Core PMU as specified in the following document:
Packit 577717
 * 	"IA-32 Intel Architecture Software Developer's Manual - Volume 3B: System
Packit 577717
 * 	Programming Guide"
Packit 577717
 *
Packit 577717
 * Intel Atom = architectural v3 + PEBS
Packit 577717
 */
Packit 577717
#include <sys/types.h>
Packit 577717
#include <ctype.h>
Packit 577717
#include <string.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <stdio.h>
Packit 577717
Packit 577717
/* public headers */
Packit 577717
#include <perfmon/pfmlib_intel_atom.h>
Packit 577717
Packit 577717
/* private headers */
Packit 577717
#include "pfmlib_priv.h"
Packit 577717
#include "pfmlib_intel_atom_priv.h"
Packit 577717
Packit 577717
#include "intel_atom_events.h"
Packit 577717
Packit 577717
/* let's define some handy shortcuts! */
Packit 577717
#define sel_event_select perfevtsel.sel_event_select
Packit 577717
#define sel_unit_mask	 perfevtsel.sel_unit_mask
Packit 577717
#define sel_usr		 perfevtsel.sel_usr
Packit 577717
#define sel_os		 perfevtsel.sel_os
Packit 577717
#define sel_edge	 perfevtsel.sel_edge
Packit 577717
#define sel_pc		 perfevtsel.sel_pc
Packit 577717
#define sel_int		 perfevtsel.sel_int
Packit 577717
#define sel_en		 perfevtsel.sel_en
Packit 577717
#define sel_inv		 perfevtsel.sel_inv
Packit 577717
#define sel_cnt_mask	 perfevtsel.sel_cnt_mask
Packit 577717
#define sel_any		 perfevtsel.sel_any
Packit 577717
Packit 577717
#define has_pebs(i)	(intel_atom_pe[i].pme_flags & PFMLIB_INTEL_ATOM_PEBS)
Packit 577717
Packit 577717
Packit 577717
/*
Packit 577717
 * Description of the PMC register mappings:
Packit 577717
 *
Packit 577717
 * 0  -> PMC0  -> PERFEVTSEL0
Packit 577717
 * 1  -> PMC1  -> PERFEVTSEL1 
Packit 577717
 * 16 -> PMC16 -> FIXED_CTR_CTRL
Packit 577717
 * 17 -> PMC17 -> PEBS_ENABLED
Packit 577717
 *
Packit 577717
 * Description of the PMD register mapping:
Packit 577717
 *
Packit 577717
 * 0  -> PMD0 -> PMC0
Packit 577717
 * 1  -> PMD1 -> PMC1
Packit 577717
 * 16 -> PMD2 -> FIXED_CTR0
Packit 577717
 * 17 -> PMD3 -> FIXED_CTR1
Packit 577717
 * 18 -> PMD4 -> FIXED_CTR2
Packit 577717
 */
Packit 577717
#define INTEL_ATOM_SEL_BASE	0x186
Packit 577717
#define INTEL_ATOM_CTR_BASE	0xc1
Packit 577717
#define FIXED_CTR_BASE		0x309
Packit 577717
Packit 577717
#define PFMLIB_INTEL_ATOM_ALL_FLAGS \
Packit 577717
	(PFM_INTEL_ATOM_SEL_INV|PFM_INTEL_ATOM_SEL_EDGE|PFM_INTEL_ATOM_SEL_ANYTHR)
Packit 577717
Packit 577717
static pfmlib_regmask_t intel_atom_impl_pmcs, intel_atom_impl_pmds;
Packit 577717
static int highest_counter;
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_detect(void)
Packit 577717
{
Packit 577717
	int ret, family, model;
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
	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
	/*
Packit 577717
	 * Atom : family 6 model 28
Packit 577717
	 */
Packit 577717
	return family == 6 && model == 28 ? PFMLIB_SUCCESS : PFMLIB_ERR_NOTSUPP;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_init(void)
Packit 577717
{
Packit 577717
	int i;
Packit 577717
Packit 577717
	/* generic counters */
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmcs, 0);
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 0);
Packit 577717
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmcs, 1);
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 1);
Packit 577717
Packit 577717
	/* fixed counters */
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmcs, 16);
Packit 577717
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 16);
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 17);
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 18);
Packit 577717
Packit 577717
	/* lbr */
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmds, 19);
Packit 577717
	for(i=0; i < 16; i++)
Packit 577717
		pfm_regmask_set(&intel_atom_impl_pmds, i);
Packit 577717
Packit 577717
	highest_counter = 18;
Packit 577717
Packit 577717
	/* PEBS */
Packit 577717
	pfm_regmask_set(&intel_atom_impl_pmcs, 17);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_is_fixed(pfmlib_event_t *e, unsigned int f)
Packit 577717
{
Packit 577717
	unsigned int fl, flc, i;
Packit 577717
	unsigned int mask = 0;
Packit 577717
Packit 577717
	fl = intel_atom_pe[e->event].pme_flags;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * first pass: check if event as a whole supports fixed counters
Packit 577717
	 */
Packit 577717
	switch(f) {
Packit 577717
		case 0:
Packit 577717
			mask = PFMLIB_INTEL_ATOM_FIXED0;
Packit 577717
			break;
Packit 577717
		case 1:
Packit 577717
			mask = PFMLIB_INTEL_ATOM_FIXED1;
Packit 577717
			break;
Packit 577717
		case 2:
Packit 577717
			mask = PFMLIB_INTEL_ATOM_FIXED2_ONLY;
Packit 577717
			break;
Packit 577717
		default:
Packit 577717
			return 0;
Packit 577717
	}
Packit 577717
	if (fl & mask)
Packit 577717
		return 1;
Packit 577717
	/*
Packit 577717
	 * second pass: check if unit mask supports fixed counter
Packit 577717
	 *
Packit 577717
	 * reject if mask not found OR if not all unit masks have
Packit 577717
	 * same fixed counter mask
Packit 577717
	 */
Packit 577717
	flc = 0;
Packit 577717
	for(i=0; i < e->num_masks; i++) {
Packit 577717
		fl = intel_atom_pe[e->event].pme_umasks[e->unit_masks[i]].pme_flags;
Packit 577717
		if (fl & mask)
Packit 577717
			flc++;
Packit 577717
	}
Packit 577717
	return flc > 0 && flc == e->num_masks ? 1 : 0;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * IMPORTANT: the interface guarantees that pfp_pmds[] elements are returned in the order the events
Packit 577717
 *	      were submitted.
Packit 577717
 */
Packit 577717
static int
Packit 577717
pfm_intel_atom_dispatch_counters(pfmlib_input_param_t *inp, pfmlib_intel_atom_input_param_t *param, pfmlib_output_param_t *outp)
Packit 577717
{
Packit 577717
#define HAS_OPTIONS(x)	(cntrs && (cntrs[x].flags || cntrs[x].cnt_mask))
Packit 577717
#define is_fixed_pmc(a) (a == 16 || a == 17 || a == 18)
Packit 577717
Packit 577717
	pfmlib_intel_atom_counter_t *cntrs;
Packit 577717
	pfm_intel_atom_sel_reg_t reg;
Packit 577717
	pfmlib_event_t *e;
Packit 577717
	pfmlib_reg_t *pc, *pd;
Packit 577717
	pfmlib_regmask_t *r_pmcs;
Packit 577717
	uint64_t val;
Packit 577717
	unsigned long plm;
Packit 577717
	unsigned long long fixed_ctr;
Packit 577717
	unsigned int npc, npmc0, npmc1, nf2;
Packit 577717
	unsigned int i, j, n, k, ucode, use_pebs = 0, done_pebs;
Packit 577717
	unsigned int assign_pc[PMU_INTEL_ATOM_NUM_COUNTERS];
Packit 577717
	unsigned int next_gen, last_gen;
Packit 577717
Packit 577717
	npc = npmc0 = npmc1 = nf2 = 0;
Packit 577717
Packit 577717
	e      = inp->pfp_events;
Packit 577717
	pc     = outp->pfp_pmcs;
Packit 577717
	pd     = outp->pfp_pmds;
Packit 577717
	n      = inp->pfp_event_count;
Packit 577717
	r_pmcs = &inp->pfp_unavail_pmcs;
Packit 577717
	cntrs  = param ? param->pfp_intel_atom_counters : NULL;
Packit 577717
	use_pebs = param ? param->pfp_intel_atom_pebs_used : 0;
Packit 577717
Packit 577717
	if (n > PMU_INTEL_ATOM_NUM_COUNTERS)
Packit 577717
		return PFMLIB_ERR_TOOMANY;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * initilize to empty
Packit 577717
	 */
Packit 577717
	for(i=0; i < PMU_INTEL_ATOM_NUM_COUNTERS; i++)
Packit 577717
		assign_pc[i] = -1;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * error checking
Packit 577717
	 */
Packit 577717
	for(i=0; i < n; i++) {
Packit 577717
		/*
Packit 577717
		 * only supports two priv levels for perf counters
Packit 577717
		 */
Packit 577717
		if (e[i].plm & (PFM_PLM1|PFM_PLM2))
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
		/*
Packit 577717
		 * check for valid flags
Packit 577717
		 */
Packit 577717
		if (cntrs && cntrs[i].flags & ~PFMLIB_INTEL_ATOM_ALL_FLAGS)
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
		if (intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_UMASK_NCOMBO
Packit 577717
		    && e[i].num_masks > 1) {
Packit 577717
			DPRINT("events does not support unit mask combination\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
		}
Packit 577717
Packit 577717
		/*
Packit 577717
		 * check event-level single register constraint (PMC0, PMC1, FIXED_CTR2)
Packit 577717
		 * fail if more than two events requested for the same counter
Packit 577717
		 */
Packit 577717
		if (intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_PMC0) {
Packit 577717
			if (++npmc0 > 1) {
Packit 577717
				DPRINT("two events compete for a PMC0\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			}
Packit 577717
		}
Packit 577717
		/*
Packit 577717
		 * check if PMC1 is available and if only one event is dependent on it
Packit 577717
		 */
Packit 577717
		if (intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_PMC1) {
Packit 577717
			if (++npmc1 > 1) {
Packit 577717
				DPRINT("two events compete for a PMC1\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			}
Packit 577717
		}
Packit 577717
		/*
Packit 577717
 		 * UNHALTED_REFERENCE_CYCLES can only be measured on FIXED_CTR2
Packit 577717
 		 */
Packit 577717
		if (intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_FIXED2_ONLY) {
Packit 577717
			if (++nf2 > 1) {
Packit 577717
				DPRINT("two events compete for FIXED_CTR2\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			}
Packit 577717
			if (cntrs && ((cntrs[i].flags & (PFM_INTEL_ATOM_SEL_EDGE|PFM_INTEL_ATOM_SEL_INV)) || cntrs[i].cnt_mask)) {
Packit 577717
				DPRINT("UNHALTED_REFERENCE_CYCLES only accepts anythr filter\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			}
Packit 577717
		}
Packit 577717
		/*
Packit 577717
 		 * unit-mask level constraint checking (PMC0, PMC1, FIXED_CTR2)
Packit 577717
 		 */	
Packit 577717
		for(j=0; j < e[i].num_masks; j++) {
Packit 577717
			unsigned int flags;
Packit 577717
Packit 577717
			flags = intel_atom_pe[e[i].event].pme_umasks[e[i].unit_masks[j]].pme_flags;
Packit 577717
Packit 577717
			if (flags & PFMLIB_INTEL_ATOM_FIXED2_ONLY) {
Packit 577717
				if (++nf2 > 1) {
Packit 577717
					DPRINT("two events compete for FIXED_CTR2\n");
Packit 577717
					return PFMLIB_ERR_NOASSIGN;
Packit 577717
				}
Packit 577717
				if (HAS_OPTIONS(i)) {
Packit 577717
					DPRINT("fixed counters do not support inversion/counter-mask\n");
Packit 577717
					return PFMLIB_ERR_NOASSIGN;
Packit 577717
				}
Packit 577717
			}
Packit 577717
                }
Packit 577717
	}
Packit 577717
Packit 577717
	next_gen = 0; /* first generic counter */
Packit 577717
	last_gen = 1; /* last generic counter */
Packit 577717
Packit 577717
	/*
Packit 577717
	 * strongest constraint first: works only in IA32_PMC0, IA32_PMC1, FIXED_CTR2
Packit 577717
	 *
Packit 577717
	 * When PEBS is used, we pick the first PEBS event and
Packit 577717
	 * place it into PMC0. Subsequent PEBS events, will go
Packit 577717
	 * in the other counters.
Packit 577717
	 */
Packit 577717
	done_pebs = 0;
Packit 577717
	for(i=0; i < n; i++) {
Packit 577717
		if ((intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_PMC0)
Packit 577717
		    || (use_pebs && pfm_intel_atom_has_pebs(e+i) && done_pebs == 0)) {
Packit 577717
			if (pfm_regmask_isset(r_pmcs, 0))
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			assign_pc[i] = 0;
Packit 577717
			next_gen = 1;
Packit 577717
			done_pebs = 1;
Packit 577717
		}
Packit 577717
		if (intel_atom_pe[e[i].event].pme_flags & PFMLIB_INTEL_ATOM_PMC1) {
Packit 577717
			if (pfm_regmask_isset(r_pmcs, 1))
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			assign_pc[i] = 1;
Packit 577717
			if (next_gen == 1)
Packit 577717
				next_gen = 2;
Packit 577717
			else
Packit 577717
				next_gen = 0;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * next constraint: fixed counters
Packit 577717
	 *
Packit 577717
	 * We abuse the mapping here for assign_pc to make it easier
Packit 577717
	 * to provide the correct values for pd[].
Packit 577717
	 * We use:
Packit 577717
	 * 	- 16 : fixed counter 0 (pmc16, pmd16)
Packit 577717
	 * 	- 17 : fixed counter 1 (pmc16, pmd17)
Packit 577717
	 * 	- 18 : fixed counter 1 (pmc16, pmd18)
Packit 577717
	 */
Packit 577717
	fixed_ctr = pfm_regmask_isset(r_pmcs, 16) ? 0 : 0x7;
Packit 577717
	if (fixed_ctr) {
Packit 577717
		for(i=0; i < n; i++) {
Packit 577717
			/* fixed counters do not support event options (filters) */
Packit 577717
			if (HAS_OPTIONS(i)) {
Packit 577717
				if (use_pebs && pfm_intel_atom_has_pebs(e+i))
Packit 577717
					continue;
Packit 577717
				if (cntrs[i].flags != PFM_INTEL_ATOM_SEL_ANYTHR)
Packit 577717
					continue;
Packit 577717
			}
Packit 577717
			if ((fixed_ctr & 0x1) && pfm_intel_atom_is_fixed(e+i, 0)) {
Packit 577717
				assign_pc[i] = 16;
Packit 577717
				fixed_ctr &= ~1;
Packit 577717
			}
Packit 577717
			if ((fixed_ctr & 0x2) && pfm_intel_atom_is_fixed(e+i, 1)) {
Packit 577717
				assign_pc[i] = 17;
Packit 577717
				fixed_ctr &= ~2;
Packit 577717
			}
Packit 577717
			if ((fixed_ctr & 0x4) && pfm_intel_atom_is_fixed(e+i, 2)) {
Packit 577717
				assign_pc[i] = 18;
Packit 577717
				fixed_ctr &= ~4;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * assign what is left
Packit 577717
	 */
Packit 577717
	for(i=0; i < n; i++) {
Packit 577717
		if (assign_pc[i] == -1) {
Packit 577717
			for(; next_gen <= last_gen; next_gen++) {
Packit 577717
				if (!pfm_regmask_isset(r_pmcs, next_gen))
Packit 577717
					break;
Packit 577717
			}
Packit 577717
			if (next_gen <= last_gen)
Packit 577717
				assign_pc[i] = next_gen++;
Packit 577717
			else {
Packit 577717
				DPRINT("cannot assign generic counters\n");
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	j = 0;
Packit 577717
Packit 577717
	/* setup fixed counters */
Packit 577717
	reg.val = 0;
Packit 577717
	k = 0;
Packit 577717
	for (i=0; i < n ; i++ ) {
Packit 577717
		if (!is_fixed_pmc(assign_pc[i]))
Packit 577717
			continue;
Packit 577717
		val = 0;
Packit 577717
		/* if plm is 0, then assume not specified per-event and use default */
Packit 577717
		plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
Packit 577717
		if (plm & PFM_PLM0)
Packit 577717
			val |= 1ULL;
Packit 577717
		if (plm & PFM_PLM3)
Packit 577717
			val |= 2ULL;
Packit 577717
		if (cntrs && cntrs[i].flags & PFM_INTEL_ATOM_SEL_ANYTHR)
Packit 577717
			val |= 4ULL;
Packit 577717
		val |= 1ULL << 3;	 /* force APIC int (kernel may force it anyway) */
Packit 577717
Packit 577717
		reg.val |= val << ((assign_pc[i]-16)<<2);
Packit 577717
	}
Packit 577717
Packit 577717
	if (reg.val) {
Packit 577717
		pc[npc].reg_num   = 16;
Packit 577717
		pc[npc].reg_value = reg.val;
Packit 577717
		pc[npc].reg_addr  = 0x38D;
Packit 577717
		pc[npc].reg_alt_addr  = 0x38D;
Packit 577717
Packit 577717
		__pfm_vbprintf("[FIXED_CTRL(pmc%u)=0x%"PRIx64" pmi0=1 en0=0x%"PRIx64" any0=%d pmi1=1 en1=0x%"PRIx64" any1=%d pmi2=1 en2=0x%"PRIx64" any2=%d] ",
Packit 577717
				pc[npc].reg_num,
Packit 577717
				reg.val,
Packit 577717
				reg.val & 0x3ULL,
Packit 577717
				!!(reg.val & 0x4ULL),
Packit 577717
				(reg.val>>4) & 0x3ULL,
Packit 577717
				!!((reg.val>>4) & 0x4ULL),
Packit 577717
				(reg.val>>8) & 0x3ULL,
Packit 577717
				!!((reg.val>>8) & 0x4ULL));
Packit 577717
Packit 577717
		if ((fixed_ctr & 0x1) == 0)
Packit 577717
			__pfm_vbprintf("INSTRUCTIONS_RETIRED ");
Packit 577717
		if ((fixed_ctr & 0x2) == 0)
Packit 577717
			__pfm_vbprintf("UNHALTED_CORE_CYCLES ");
Packit 577717
		if ((fixed_ctr & 0x4) == 0)
Packit 577717
			__pfm_vbprintf("UNHALTED_REFERENCE_CYCLES ");
Packit 577717
		__pfm_vbprintf("\n");
Packit 577717
Packit 577717
		npc++;
Packit 577717
Packit 577717
		if ((fixed_ctr & 0x1) == 0)
Packit 577717
			__pfm_vbprintf("[FIXED_CTR0(pmd16)]\n");
Packit 577717
		if ((fixed_ctr & 0x2) == 0)
Packit 577717
			__pfm_vbprintf("[FIXED_CTR1(pmd17)]\n");
Packit 577717
		if ((fixed_ctr & 0x4) == 0)
Packit 577717
			__pfm_vbprintf("[FIXED_CTR2(pmd18)]\n");
Packit 577717
	}
Packit 577717
Packit 577717
	for (i=0; i < n ; i++ ) {
Packit 577717
		/* skip fixed counters */
Packit 577717
		if (is_fixed_pmc(assign_pc[i]))
Packit 577717
			continue;
Packit 577717
Packit 577717
		reg.val = 0; /* assume reserved bits are zerooed */
Packit 577717
Packit 577717
		/* if plm is 0, then assume not specified per-event and use default */
Packit 577717
		plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
Packit 577717
Packit 577717
		val = intel_atom_pe[e[i].event].pme_code;
Packit 577717
Packit 577717
		reg.sel_event_select = val & 0xff;
Packit 577717
Packit 577717
		ucode = (val >> 8) & 0xff;
Packit 577717
Packit 577717
		for(k=0; k < e[i].num_masks; k++)
Packit 577717
			ucode |= intel_atom_pe[e[i].event].pme_umasks[e[i].unit_masks[k]].pme_ucode;
Packit 577717
Packit 577717
		val |= ucode << 8;
Packit 577717
Packit 577717
		reg.sel_unit_mask  = ucode;
Packit 577717
		reg.sel_usr        = plm & PFM_PLM3 ? 1 : 0;
Packit 577717
		reg.sel_os         = plm & PFM_PLM0 ? 1 : 0;
Packit 577717
		reg.sel_en         = 1; /* force enable bit to 1 */
Packit 577717
		reg.sel_int        = 1; /* force APIC int to 1 */
Packit 577717
Packit 577717
		reg.sel_cnt_mask = val >>24;
Packit 577717
		reg.sel_inv = val >> 23;
Packit 577717
		reg.sel_edge = val >> 18;
Packit 577717
		reg.sel_any = val >> 21;;
Packit 577717
Packit 577717
		if (cntrs) {
Packit 577717
			if (!reg.sel_cnt_mask) {
Packit 577717
				/*
Packit 577717
			 	 * counter mask is 8-bit wide, do not silently
Packit 577717
			 	 * wrap-around
Packit 577717
			 	 */
Packit 577717
				if (cntrs[i].cnt_mask > 255)
Packit 577717
					return PFMLIB_ERR_INVAL;
Packit 577717
				reg.sel_cnt_mask = cntrs[i].cnt_mask;
Packit 577717
			}
Packit 577717
Packit 577717
			if (!reg.sel_edge)
Packit 577717
				reg.sel_edge = cntrs[i].flags & PFM_INTEL_ATOM_SEL_EDGE ? 1 : 0;
Packit 577717
			if (!reg.sel_inv)
Packit 577717
				reg.sel_inv = cntrs[i].flags & PFM_INTEL_ATOM_SEL_INV ? 1 : 0;
Packit 577717
			if (!reg.sel_any)
Packit 577717
				reg.sel_any = cntrs[i].flags & PFM_INTEL_ATOM_SEL_ANYTHR? 1 : 0;
Packit 577717
		}
Packit 577717
Packit 577717
		pc[npc].reg_num     = assign_pc[i];
Packit 577717
		pc[npc].reg_value   = reg.val;
Packit 577717
		pc[npc].reg_addr    = INTEL_ATOM_SEL_BASE+assign_pc[i];
Packit 577717
		pc[npc].reg_alt_addr= INTEL_ATOM_SEL_BASE+assign_pc[i];
Packit 577717
Packit 577717
		__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 anythr=%d] %s\n",
Packit 577717
				pc[npc].reg_num,
Packit 577717
				pc[npc].reg_num,
Packit 577717
				reg.val,
Packit 577717
				reg.sel_event_select,
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
				reg.sel_any,
Packit 577717
				intel_atom_pe[e[i].event].pme_name);
Packit 577717
Packit 577717
		__pfm_vbprintf("[PMC%u(pmd%u)]\n",
Packit 577717
				pc[npc].reg_num,
Packit 577717
				pc[npc].reg_num);
Packit 577717
Packit 577717
		npc++;
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * setup pmds: must be in the same order as the events
Packit 577717
	 */
Packit 577717
	for (i=0; i < n ; i++) {
Packit 577717
		if (is_fixed_pmc(assign_pc[i])) {
Packit 577717
			/* setup pd array */
Packit 577717
			pd[i].reg_num = assign_pc[i];
Packit 577717
			pd[i].reg_addr = FIXED_CTR_BASE+assign_pc[i]-16;
Packit 577717
			pd[i].reg_alt_addr = 0x40000000+assign_pc[i]-16;
Packit 577717
		} else {
Packit 577717
			pd[i].reg_num  = assign_pc[i];
Packit 577717
			pd[i].reg_addr = INTEL_ATOM_CTR_BASE+assign_pc[i];
Packit 577717
			/* index to use with RDPMC */
Packit 577717
			pd[i].reg_alt_addr  = assign_pc[i];
Packit 577717
		}
Packit 577717
	}
Packit 577717
	outp->pfp_pmd_count = i;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * setup PEBS_ENABLE
Packit 577717
	 */
Packit 577717
	if (use_pebs && done_pebs) {
Packit 577717
		/*
Packit 577717
		 * check that PEBS_ENABLE is available
Packit 577717
		 */
Packit 577717
		if (pfm_regmask_isset(r_pmcs, 17))
Packit 577717
			return PFMLIB_ERR_NOASSIGN;
Packit 577717
		pc[npc].reg_num   = 17;
Packit 577717
		pc[npc].reg_value = 1ULL;
Packit 577717
		pc[npc].reg_addr  = 0x3f1; /* IA32_PEBS_ENABLE */
Packit 577717
		pc[npc].reg_alt_addr  = 0x3f1; /* IA32_PEBS_ENABLE */
Packit 577717
Packit 577717
		__pfm_vbprintf("[PEBS_ENABLE(pmc%u)=0x%"PRIx64" ena=%d]\n",
Packit 577717
				pc[npc].reg_num,
Packit 577717
				pc[npc].reg_value,
Packit 577717
				pc[npc].reg_value & 0x1ull);
Packit 577717
Packit 577717
		npc++;
Packit 577717
Packit 577717
	}
Packit 577717
	outp->pfp_pmc_count = npc;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_dispatch_events(pfmlib_input_param_t *inp, void *model_in, pfmlib_output_param_t *outp, void *model_out)
Packit 577717
{
Packit 577717
	pfmlib_intel_atom_input_param_t *mod_in  = (pfmlib_intel_atom_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_intel_atom_dispatch_counters(inp, mod_in, outp);
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_event_code(unsigned int i, unsigned int cnt, int *code)
Packit 577717
{
Packit 577717
	if (cnt != PFMLIB_CNT_FIRST
Packit 577717
	    && (cnt > highest_counter ||
Packit 577717
		!pfm_regmask_isset(&intel_atom_impl_pmds, cnt)))
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	*code = intel_atom_pe[i].pme_code;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_intel_atom_get_event_counters(unsigned int j, pfmlib_regmask_t *counters)
Packit 577717
{
Packit 577717
	unsigned int n, i;
Packit 577717
	unsigned int has_f0, has_f1, has_f2;
Packit 577717
Packit 577717
	memset(counters, 0, sizeof(*counters));
Packit 577717
Packit 577717
	n = intel_atom_pe[j].pme_numasks;
Packit 577717
	has_f0 = has_f1 = has_f2 = 0;
Packit 577717
Packit 577717
	for (i=0; i < n; i++) {
Packit 577717
		if (intel_atom_pe[j].pme_umasks[i].pme_flags & PFMLIB_INTEL_ATOM_FIXED0)
Packit 577717
			has_f0 = 1;
Packit 577717
		if (intel_atom_pe[j].pme_umasks[i].pme_flags & PFMLIB_INTEL_ATOM_FIXED1)
Packit 577717
			has_f1 = 1;
Packit 577717
		if (intel_atom_pe[j].pme_umasks[i].pme_flags & PFMLIB_INTEL_ATOM_FIXED2_ONLY)
Packit 577717
			has_f2 = 1;
Packit 577717
	}
Packit 577717
Packit 577717
	if (has_f0 == 0)
Packit 577717
		has_f0 = intel_atom_pe[j].pme_flags & PFMLIB_INTEL_ATOM_FIXED0;
Packit 577717
	if (has_f1 == 0)
Packit 577717
		has_f1 = intel_atom_pe[j].pme_flags & PFMLIB_INTEL_ATOM_FIXED1;
Packit 577717
	if (has_f2 == 0)
Packit 577717
		has_f2 = intel_atom_pe[j].pme_flags & PFMLIB_INTEL_ATOM_FIXED2_ONLY;
Packit 577717
Packit 577717
	if (has_f0)
Packit 577717
		pfm_regmask_set(counters, 16);
Packit 577717
	if (has_f1)
Packit 577717
		pfm_regmask_set(counters, 17);
Packit 577717
	if (has_f2)
Packit 577717
		pfm_regmask_set(counters, 18);
Packit 577717
Packit 577717
	/* the event on FIXED_CTR2 is exclusive CPU_CLK_UNHALTED:REF */
Packit 577717
	if (!has_f2) {
Packit 577717
		pfm_regmask_set(counters, 0);
Packit 577717
		pfm_regmask_set(counters, 1);
Packit 577717
Packit 577717
		if (intel_atom_pe[j].pme_flags & PFMLIB_INTEL_ATOM_PMC0)
Packit 577717
			pfm_regmask_clr(counters, 1);
Packit 577717
		if (intel_atom_pe[j].pme_flags & PFMLIB_INTEL_ATOM_PMC1)
Packit 577717
			pfm_regmask_clr(counters, 0);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_intel_atom_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs)
Packit 577717
{
Packit 577717
	*impl_pmcs = intel_atom_impl_pmcs;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_intel_atom_get_impl_pmds(pfmlib_regmask_t *impl_pmds)
Packit 577717
{
Packit 577717
	*impl_pmds = intel_atom_impl_pmds;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_intel_atom_get_impl_counters(pfmlib_regmask_t *impl_counters)
Packit 577717
{
Packit 577717
	pfm_regmask_set(impl_counters, 0);
Packit 577717
	pfm_regmask_set(impl_counters, 1);
Packit 577717
	pfm_regmask_set(impl_counters, 16);
Packit 577717
	pfm_regmask_set(impl_counters, 17);
Packit 577717
	pfm_regmask_set(impl_counters, 18);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Even though, CPUID 0xa returns in eax the actual counter
Packit 577717
 * width, the architecture specifies that writes are limited
Packit 577717
 * to lower 32-bits. As such, only the lower 32-bit have full
Packit 577717
 * degree of freedom. That is the "useable" counter width.
Packit 577717
 */
Packit 577717
#define PMU_INTEL_ATOM_COUNTER_WIDTH       32
Packit 577717
Packit 577717
static void
Packit 577717
pfm_intel_atom_get_hw_counter_width(unsigned int *width)
Packit 577717
{
Packit 577717
	/*
Packit 577717
	 * Even though, CPUID 0xa returns in eax the actual counter
Packit 577717
	 * width, the architecture specifies that writes are limited
Packit 577717
	 * to lower 32-bits. As such, only the lower 31 bits have full
Packit 577717
	 * degree of freedom. That is the "useable" counter width.
Packit 577717
	 */
Packit 577717
	*width = PMU_INTEL_ATOM_COUNTER_WIDTH;
Packit 577717
}
Packit 577717
Packit 577717
static char *
Packit 577717
pfm_intel_atom_get_event_name(unsigned int i)
Packit 577717
{
Packit 577717
	return intel_atom_pe[i].pme_name;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_event_description(unsigned int ev, char **str)
Packit 577717
{
Packit 577717
	char *s;
Packit 577717
	s = intel_atom_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_intel_atom_get_event_mask_name(unsigned int ev, unsigned int midx)
Packit 577717
{
Packit 577717
	return intel_atom_pe[ev].pme_umasks[midx].pme_uname;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_event_mask_desc(unsigned int ev, unsigned int midx, char **str)
Packit 577717
{
Packit 577717
	char *s;
Packit 577717
Packit 577717
	s = intel_atom_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_intel_atom_get_num_event_masks(unsigned int ev)
Packit 577717
{
Packit 577717
	return intel_atom_pe[ev].pme_numasks;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_event_mask_code(unsigned int ev, unsigned int midx, unsigned int *code)
Packit 577717
{
Packit 577717
	*code =intel_atom_pe[ev].pme_umasks[midx].pme_ucode;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_cycle_event(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	e->event = PME_INTEL_ATOM_UNHALTED_CORE_CYCLES;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_intel_atom_get_inst_retired(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	e->event = PME_INTEL_ATOM_INSTRUCTIONS_RETIRED;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * this function is directly accessible by external caller
Packit 577717
 * library initialization is not required, though recommended
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_intel_atom_has_pebs(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	unsigned int i, n=0;
Packit 577717
Packit 577717
	if (e == NULL || e->event >= PME_INTEL_ATOM_EVENT_COUNT)
Packit 577717
		return 0;
Packit 577717
Packit 577717
	if (intel_atom_pe[e->event].pme_flags & PFMLIB_INTEL_ATOM_PEBS)
Packit 577717
		return 1;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * ALL unit mask must support PEBS for this test to return true
Packit 577717
	 */
Packit 577717
	for(i=0; i < e->num_masks; i++) {
Packit 577717
		/* check for valid unit mask */
Packit 577717
		if (e->unit_masks[i] >= intel_atom_pe[e->event].pme_numasks)
Packit 577717
			return 0;
Packit 577717
		if (intel_atom_pe[e->event].pme_umasks[e->unit_masks[i]].pme_flags & PFMLIB_INTEL_ATOM_PEBS)
Packit 577717
			n++;
Packit 577717
	}
Packit 577717
	return n > 0 && n == e->num_masks;
Packit 577717
}
Packit 577717
Packit 577717
pfm_pmu_support_t intel_atom_support={
Packit 577717
	.pmu_name		= "Intel Atom",
Packit 577717
	.pmu_type		= PFMLIB_INTEL_ATOM_PMU,
Packit 577717
	.pme_count		= PME_INTEL_ATOM_EVENT_COUNT,
Packit 577717
	.pmc_count		= 4,
Packit 577717
	.pmd_count		= 22,
Packit 577717
	.num_cnt		= 5,
Packit 577717
	.get_event_code		= pfm_intel_atom_get_event_code,
Packit 577717
	.get_event_name		= pfm_intel_atom_get_event_name,
Packit 577717
	.get_event_counters	= pfm_intel_atom_get_event_counters,
Packit 577717
	.dispatch_events	= pfm_intel_atom_dispatch_events,
Packit 577717
	.pmu_detect		= pfm_intel_atom_detect,
Packit 577717
	.pmu_init		= pfm_intel_atom_init,
Packit 577717
	.get_impl_pmcs		= pfm_intel_atom_get_impl_pmcs,
Packit 577717
	.get_impl_pmds		= pfm_intel_atom_get_impl_pmds,
Packit 577717
	.get_impl_counters	= pfm_intel_atom_get_impl_counters,
Packit 577717
	.get_hw_counter_width	= pfm_intel_atom_get_hw_counter_width,
Packit 577717
	.get_event_desc         = pfm_intel_atom_get_event_description,
Packit 577717
	.get_num_event_masks	= pfm_intel_atom_get_num_event_masks,
Packit 577717
	.get_event_mask_name	= pfm_intel_atom_get_event_mask_name,
Packit 577717
	.get_event_mask_code	= pfm_intel_atom_get_event_mask_code,
Packit 577717
	.get_event_mask_desc	= pfm_intel_atom_get_event_mask_desc,
Packit 577717
	.get_cycle_event	= pfm_intel_atom_get_cycle_event,
Packit 577717
	.get_inst_retired_event = pfm_intel_atom_get_inst_retired
Packit 577717
};