Blame src/perfctr-2.7.x/linux/drivers/perfctr/ppc64.c

Packit 577717
/*
Packit 577717
 * PPC64 performance-monitoring counters driver.
Packit 577717
 *
Packit 577717
 * based on Mikael Pettersson's 32 bit ppc code
Packit 577717
 * Copyright (C) 2004  David Gibson, IBM Corporation.
Packit 577717
 * Copyright (C) 2004, 2007  Mikael Pettersson
Packit 577717
 */
Packit 577717
#include <linux/version.h>
Packit 577717
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
Packit 577717
#include <linux/config.h>
Packit 577717
#endif
Packit 577717
#include <linux/init.h>
Packit 577717
#include <linux/sched.h>
Packit 577717
#include <linux/fs.h>
Packit 577717
#include <linux/perfctr.h>
Packit 577717
#include <asm/prom.h>
Packit 577717
#include <asm/time.h>		/* tb_ticks_per_jiffy */
Packit 577717
#include <asm/pmc.h>
Packit 577717
#include <asm/cputable.h>
Packit 577717
Packit 577717
#include "ppc64_tests.h"
Packit 577717
Packit 577717
extern void ppc64_enable_pmcs(void);
Packit 577717
Packit 577717
/* Support for lazy perfctr SPR updates. */
Packit 577717
struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
Packit 577717
	unsigned int id;	/* cache owner id */
Packit 577717
	/* Physically indexed cache of the MMCRs. */
Packit 577717
	unsigned long ppc64_mmcr0, ppc64_mmcr1, ppc64_mmcra;
Packit 577717
};
Packit 577717
static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache);
Packit 577717
#define __get_cpu_cache(cpu) (&per_cpu(per_cpu_cache, cpu))
Packit 577717
#define get_cpu_cache()	(&__get_cpu_var(per_cpu_cache))
Packit 577717
Packit 577717
/* Structure for counter snapshots, as 32-bit values. */
Packit 577717
struct perfctr_low_ctrs {
Packit 577717
	u64 tsc;
Packit 577717
	u32 pmc[8];
Packit 577717
};
Packit 577717
Packit 577717
static unsigned int new_id(void)
Packit 577717
{
Packit 577717
	static DEFINE_SPINLOCK(lock);
Packit 577717
	static unsigned int counter;
Packit 577717
	int id;
Packit 577717
Packit 577717
	spin_lock(&lock);
Packit 577717
	id = ++counter;
Packit 577717
	spin_unlock(&lock);
Packit 577717
	return id;
Packit 577717
}
Packit 577717
Packit 577717
static inline u32 read_pmc(int pmc)
Packit 577717
{
Packit 577717
	switch (pmc) {
Packit 577717
	case 0:
Packit 577717
		return mfspr(SPRN_PMC1);
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		return mfspr(SPRN_PMC2);
Packit 577717
		break;
Packit 577717
	case 2:
Packit 577717
		return mfspr(SPRN_PMC3);
Packit 577717
		break;
Packit 577717
	case 3:
Packit 577717
		return mfspr(SPRN_PMC4);
Packit 577717
		break;
Packit 577717
	case 4:
Packit 577717
		return mfspr(SPRN_PMC5);
Packit 577717
		break;
Packit 577717
	case 5:
Packit 577717
		return mfspr(SPRN_PMC6);
Packit 577717
		break;
Packit 577717
	case 6:
Packit 577717
		return mfspr(SPRN_PMC7);
Packit 577717
		break;
Packit 577717
	case 7:
Packit 577717
		return mfspr(SPRN_PMC8);
Packit 577717
		break;
Packit 577717
Packit 577717
	default:
Packit 577717
		return -EINVAL;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static inline void write_pmc(int pmc, u32 val)
Packit 577717
{
Packit 577717
	switch (pmc) {
Packit 577717
	case 0:
Packit 577717
		mtspr(SPRN_PMC1, val);
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		mtspr(SPRN_PMC2, val);
Packit 577717
		break;
Packit 577717
	case 2:
Packit 577717
		mtspr(SPRN_PMC3, val);
Packit 577717
		break;
Packit 577717
	case 3:
Packit 577717
		mtspr(SPRN_PMC4, val);
Packit 577717
		break;
Packit 577717
	case 4:
Packit 577717
		mtspr(SPRN_PMC5, val);
Packit 577717
		break;
Packit 577717
	case 5:
Packit 577717
		mtspr(SPRN_PMC6, val);
Packit 577717
		break;
Packit 577717
	case 6:
Packit 577717
		mtspr(SPRN_PMC7, val);
Packit 577717
		break;
Packit 577717
	case 7:
Packit 577717
		mtspr(SPRN_PMC8, val);
Packit 577717
		break;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
static void perfctr_default_ihandler(unsigned long pc)
Packit 577717
{
Packit 577717
	unsigned int mmcr0 = mfspr(SPRN_MMCR0);
Packit 577717
Packit 577717
	mmcr0 &= ~MMCR0_PMXE;
Packit 577717
	mtspr(SPRN_MMCR0, mmcr0);
Packit 577717
}
Packit 577717
Packit 577717
static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
Packit 577717
Packit 577717
void do_perfctr_interrupt(struct pt_regs *regs)
Packit 577717
{
Packit 577717
	unsigned long mmcr0;
Packit 577717
Packit 577717
	/* interrupts are disabled here, so we don't need to
Packit 577717
	 * preempt_disable() */
Packit 577717
Packit 577717
	(*perfctr_ihandler)(instruction_pointer(regs));
Packit 577717
Packit 577717
	/* clear PMAO so the interrupt doesn't reassert immediately */
Packit 577717
	mmcr0 = mfspr(SPRN_MMCR0) & ~MMCR0_PMAO;
Packit 577717
	mtspr(SPRN_MMCR0, mmcr0);
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
Packit 577717
{
Packit 577717
	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
Packit 577717
}
Packit 577717
Packit 577717
#else
Packit 577717
#define perfctr_cstatus_has_ictrs(cstatus)	0
Packit 577717
#endif
Packit 577717
Packit 577717
Packit 577717
#if defined(CONFIG_SMP) && defined(CONFIG_PERFCTR_INTERRUPT_SUPPORT)
Packit 577717
Packit 577717
static inline void
Packit 577717
set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
Packit 577717
{
Packit 577717
	state->isuspend_cpu = cpu;
Packit 577717
}
Packit 577717
Packit 577717
static inline int
Packit 577717
is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
Packit 577717
{
Packit 577717
	return state->isuspend_cpu == cpu;
Packit 577717
}
Packit 577717
Packit 577717
static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	state->isuspend_cpu = NR_CPUS;
Packit 577717
}
Packit 577717
Packit 577717
#else
Packit 577717
static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
Packit 577717
static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
Packit 577717
static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
Packit 577717
#endif
Packit 577717
Packit 577717
Packit 577717
static void ppc64_clear_counters(void)
Packit 577717
{
Packit 577717
	mtspr(SPRN_MMCR0, 0);
Packit 577717
	mtspr(SPRN_MMCR1, 0);
Packit 577717
	mtspr(SPRN_MMCRA, 0);
Packit 577717
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 1)
Packit 577717
		mtspr(SPRN_PMC1, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 2)
Packit 577717
		mtspr(SPRN_PMC2, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 3)
Packit 577717
		mtspr(SPRN_PMC3, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 4)
Packit 577717
		mtspr(SPRN_PMC4, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 5)
Packit 577717
		mtspr(SPRN_PMC5, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 6)
Packit 577717
		mtspr(SPRN_PMC6, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 7)
Packit 577717
		mtspr(SPRN_PMC7, 0);
Packit 577717
	if (cur_cpu_spec->num_pmcs >= 8)
Packit 577717
		mtspr(SPRN_PMC8, 0);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Driver methods, internal and exported.
Packit 577717
 */
Packit 577717
Packit 577717
static void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	struct per_cpu_cache *cache;
Packit 577717
	unsigned long long value;
Packit 577717
Packit 577717
	cache = get_cpu_cache();
Packit 577717
	/*
Packit 577717
	 * Order matters here: update threshmult and event
Packit 577717
	 * selectors before updating global control, which
Packit 577717
	 * potentially enables PMIs.
Packit 577717
	 *
Packit 577717
	 * Since mtspr doesn't accept a runtime value for the
Packit 577717
	 * SPR number, unroll the loop so each mtspr targets
Packit 577717
	 * a constant SPR.
Packit 577717
	 *
Packit 577717
	 * For processors without MMCR2, we ensure that the
Packit 577717
	 * cache and the state indicate the same value for it,
Packit 577717
	 * preventing any actual mtspr to it. Ditto for MMCR1.
Packit 577717
	 */
Packit 577717
	value = state->control.mmcra;
Packit 577717
	if (value != cache->ppc64_mmcra) {
Packit 577717
		cache->ppc64_mmcra = value;
Packit 577717
		mtspr(SPRN_MMCRA, value);
Packit 577717
	}
Packit 577717
	value = state->control.mmcr1;
Packit 577717
	if (value != cache->ppc64_mmcr1) {
Packit 577717
		cache->ppc64_mmcr1 = value;
Packit 577717
		mtspr(SPRN_MMCR1, value);
Packit 577717
	}
Packit 577717
	value = state->control.mmcr0;
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->user.cstatus))
Packit 577717
	    value |= MMCR0_PMXE;
Packit 577717
	if (value != cache->ppc64_mmcr0) {
Packit 577717
		cache->ppc64_mmcr0 = value;
Packit 577717
		mtspr(SPRN_MMCR0, value);
Packit 577717
	}
Packit 577717
	cache->id = state->id;
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_read_counters(struct perfctr_cpu_state *state,
Packit 577717
				      struct perfctr_low_ctrs *ctrs)
Packit 577717
{
Packit 577717
	unsigned int cstatus, i, pmc;
Packit 577717
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		ctrs->tsc = mftb();
Packit 577717
Packit 577717
	for (i = 0; i < perfctr_cstatus_nractrs(cstatus); ++i) {
Packit 577717
		pmc = state->control.pmc_map[i];
Packit 577717
		ctrs->pmc[i] = read_pmc(pmc);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
static void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int cstatus, nrctrs, i;
Packit 577717
	int cpu;
Packit 577717
Packit 577717
	cpu = smp_processor_id();
Packit 577717
	set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
	for (i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
Packit 577717
		int pmc = state->control.pmc_map[i];
Packit 577717
		u32 now = read_pmc(pmc);
Packit 577717
Packit 577717
		state->user.pmc[i].sum += (u32)(now-state->user.pmc[i].start);
Packit 577717
		state->user.pmc[i].start = now;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	struct per_cpu_cache *cache;
Packit 577717
	unsigned int cstatus, nrctrs, i;
Packit 577717
	int cpu;
Packit 577717
Packit 577717
	cpu = smp_processor_id();
Packit 577717
	cache = __get_cpu_cache(cpu);
Packit 577717
	if (cache->id == state->id) {
Packit 577717
		/* Clearing cache->id to force write_control()
Packit 577717
		   to unfreeze MMCR0 would be done here, but it
Packit 577717
		   is subsumed by resume()'s MMCR0 reload logic. */
Packit 577717
		if (is_isuspend_cpu(state, cpu)) {
Packit 577717
			return; /* skip reload of PMCs */
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * The CPU state wasn't ours.
Packit 577717
	 *
Packit 577717
	 * The counters must be frozen before being reinitialised,
Packit 577717
	 * to prevent unexpected increments and missed overflows.
Packit 577717
	 *
Packit 577717
	 * All unused counters must be reset to a non-overflow state.
Packit 577717
	 */
Packit 577717
	if (!(cache->ppc64_mmcr0 & MMCR0_FC)) {
Packit 577717
		cache->ppc64_mmcr0 |= MMCR0_FC;
Packit 577717
		mtspr(SPRN_MMCR0, cache->ppc64_mmcr0);
Packit 577717
	}
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
	for (i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
Packit 577717
		write_pmc(state->control.pmc_map[i], state->user.pmc[i].start);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
Packit 577717
   bypass internal caching and force a reload if the I-mode PMCs. */
Packit 577717
void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
#ifdef CONFIG_SMP
Packit 577717
	clear_isuspend_cpu(state);
Packit 577717
#else
Packit 577717
	get_cpu_cache()->id = 0;
Packit 577717
#endif
Packit 577717
}
Packit 577717
Packit 577717
/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
Packit 577717
unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int cstatus, nractrs, nrctrs, i;
Packit 577717
	unsigned int pmc_mask = 0;
Packit 577717
	int nr_pmcs = cur_cpu_spec->num_pmcs;
Packit 577717
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	nractrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
Packit 577717
	/* Ickity, ickity, ick.  We don't have fine enough interrupt
Packit 577717
	 * control to disable interrupts on all the counters we're not
Packit 577717
	 * interested in.  So, we have to deal with overflows on actrs
Packit 577717
	 * amd unused PMCs as well as the ones we actually care
Packit 577717
	 * about. */
Packit 577717
	for (i = 0; i < nractrs; ++i) {
Packit 577717
		int pmc = state->control.pmc_map[i];
Packit 577717
		u32 val = read_pmc(pmc);
Packit 577717
Packit 577717
		/* For actrs, force a sample if they overflowed */
Packit 577717
Packit 577717
		if ((s32)val < 0) {
Packit 577717
			state->user.pmc[i].sum += (u32)(val - state->user.pmc[i].start);
Packit 577717
			state->user.pmc[i].start = 0;
Packit 577717
			write_pmc(pmc, 0);
Packit 577717
		}
Packit 577717
	}
Packit 577717
	for (; i < nrctrs; ++i) {
Packit 577717
		if ((s32)state->user.pmc[i].start < 0) { /* PPC64-specific */
Packit 577717
			int pmc = state->control.pmc_map[i];
Packit 577717
			/* XXX: "+=" to correct for overshots */
Packit 577717
			state->user.pmc[i].start = state->control.ireset[pmc];
Packit 577717
			pmc_mask |= (1 << i);
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/* Clear any unused overflowed counters, so we don't loop on
Packit 577717
	 * the interrupt */
Packit 577717
	for (i = 0; i < nr_pmcs; ++i) {
Packit 577717
		if (! (state->unused_pmcs & (1<
Packit 577717
			continue;
Packit 577717
Packit 577717
		if ((int)read_pmc(i) < 0)
Packit 577717
			write_pmc(i, 0);
Packit 577717
	}
Packit 577717
Packit 577717
	/* XXX: HW cleared MMCR0[ENINT]. We presumably cleared the entire
Packit 577717
	   MMCR0, so the re-enable occurs automatically later, no? */
Packit 577717
	return pmc_mask;
Packit 577717
}
Packit 577717
Packit 577717
static inline int check_ireset(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int nrctrs, i;
Packit 577717
Packit 577717
	i = state->control.header.nractrs;
Packit 577717
	nrctrs = i + state->control.header.nrictrs;
Packit 577717
	for(; i < nrctrs; ++i) {
Packit 577717
		unsigned int pmc = state->control.pmc_map[i];
Packit 577717
		if ((int)state->control.ireset[pmc] < 0) /* PPC64-specific */
Packit 577717
			return -EINVAL;
Packit 577717
		state->user.pmc[i].start = state->control.ireset[pmc];
Packit 577717
	}
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
#else	/* CONFIG_PERFCTR_INTERRUPT_SUPPORT */
Packit 577717
static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
Packit 577717
static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
Packit 577717
static inline int check_ireset(struct perfctr_cpu_state *state) { return 0; }
Packit 577717
#endif	/* CONFIG_PERFCTR_INTERRUPT_SUPPORT */
Packit 577717
Packit 577717
static int check_control(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int i, nractrs, nrctrs, pmc_mask, pmc;
Packit 577717
	unsigned int nr_pmcs = cur_cpu_spec->num_pmcs;
Packit 577717
Packit 577717
	nractrs = state->control.header.nractrs;
Packit 577717
	nrctrs = nractrs + state->control.header.nrictrs;
Packit 577717
	if (nrctrs < nractrs || nrctrs > nr_pmcs)
Packit 577717
		return -EINVAL;
Packit 577717
Packit 577717
	pmc_mask = 0;
Packit 577717
	for (i = 0; i < nrctrs; ++i) {
Packit 577717
		pmc = state->control.pmc_map[i];
Packit 577717
		if (pmc >= nr_pmcs || (pmc_mask & (1<
Packit 577717
			return -EINVAL;
Packit 577717
		pmc_mask |= (1<
Packit 577717
	}
Packit 577717
Packit 577717
	/* We need to retain internal control of PMXE and PMAO.  PMXE
Packit 577717
	 * will be set when ictrs are active.  We can't really handle
Packit 577717
	 * TB interrupts, so we don't allow those either. */
Packit 577717
	if ( (state->control.mmcr0 & MMCR0_PMXE)
Packit 577717
	     || (state->control.mmcr0 & MMCR0_PMAO)
Packit 577717
	     || (state->control.mmcr0 & MMCR0_TBEE) )
Packit 577717
		return -EINVAL;
Packit 577717
Packit 577717
	state->unused_pmcs = ((1 << nr_pmcs)-1) & ~pmc_mask;
Packit 577717
Packit 577717
	state->id = new_id();
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
Packit 577717
{
Packit 577717
	int err;
Packit 577717
Packit 577717
	clear_isuspend_cpu(state);
Packit 577717
	state->user.cstatus = 0;
Packit 577717
Packit 577717
	/* disallow i-mode counters if we cannot catch the interrupts */
Packit 577717
	if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
Packit 577717
	    && state->control.header.nrictrs)
Packit 577717
		return -EPERM;
Packit 577717
Packit 577717
	err = check_control(state); /* may initialise state->cstatus */
Packit 577717
	if (err < 0)
Packit 577717
		return err;
Packit 577717
	err = check_ireset(state);
Packit 577717
	if (err < 0)
Packit 577717
		return err;
Packit 577717
	state->user.cstatus |= perfctr_mk_cstatus(state->control.header.tsc_on,
Packit 577717
						  state->control.header.nractrs,
Packit 577717
						  state->control.header.nrictrs);
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * get_reg_offset() maps SPR numbers to offsets into struct perfctr_cpu_control.
Packit 577717
 */
Packit 577717
static const struct {
Packit 577717
	unsigned int spr;
Packit 577717
	unsigned int offset;
Packit 577717
	unsigned int size;
Packit 577717
} reg_offsets[] = {
Packit 577717
	{ SPRN_MMCR0, offsetof(struct perfctr_cpu_control, mmcr0), sizeof(long) },
Packit 577717
	{ SPRN_MMCR1, offsetof(struct perfctr_cpu_control, mmcr1), sizeof(long) },
Packit 577717
	{ SPRN_MMCRA, offsetof(struct perfctr_cpu_control, mmcra), sizeof(long) },
Packit 577717
	{ SPRN_PMC1,  offsetof(struct perfctr_cpu_control, ireset[1-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC2,  offsetof(struct perfctr_cpu_control, ireset[2-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC3,  offsetof(struct perfctr_cpu_control, ireset[3-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC4,  offsetof(struct perfctr_cpu_control, ireset[4-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC5,  offsetof(struct perfctr_cpu_control, ireset[5-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC6,  offsetof(struct perfctr_cpu_control, ireset[6-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC7,  offsetof(struct perfctr_cpu_control, ireset[7-1]), sizeof(int) },
Packit 577717
	{ SPRN_PMC8,  offsetof(struct perfctr_cpu_control, ireset[8-1]), sizeof(int) },
Packit 577717
};
Packit 577717
Packit 577717
static int get_reg_offset(unsigned int spr, unsigned int *size)
Packit 577717
{
Packit 577717
	unsigned int i;
Packit 577717
Packit 577717
	for(i = 0; i < ARRAY_SIZE(reg_offsets); ++i)
Packit 577717
		if (spr == reg_offsets[i].spr) {
Packit 577717
			*size = reg_offsets[i].size;
Packit 577717
			return reg_offsets[i].offset;
Packit 577717
		}
Packit 577717
	return -1;
Packit 577717
}
Packit 577717
Packit 577717
static int access_regs(struct perfctr_cpu_control *control,
Packit 577717
		       void *argp, unsigned int argbytes, int do_write)
Packit 577717
{
Packit 577717
	struct perfctr_cpu_reg *regs;
Packit 577717
	unsigned int i, nr_regs, size;
Packit 577717
	int offset;
Packit 577717
Packit 577717
	nr_regs = argbytes / sizeof(struct perfctr_cpu_reg);
Packit 577717
	if (nr_regs * sizeof(struct perfctr_cpu_reg) != argbytes)
Packit 577717
		return -EINVAL;
Packit 577717
	regs = (struct perfctr_cpu_reg*)argp;
Packit 577717
Packit 577717
	for(i = 0; i < nr_regs; ++i) {
Packit 577717
		offset = get_reg_offset(regs[i].nr, &size);
Packit 577717
		if (offset < 0)
Packit 577717
			return -EINVAL;
Packit 577717
		if (size == sizeof(long)) {
Packit 577717
			unsigned long *where = (unsigned long*)((char*)control + offset);
Packit 577717
			if (do_write)
Packit 577717
				*where = regs[i].value;
Packit 577717
			else
Packit 577717
				regs[i].value = *where;
Packit 577717
		} else {
Packit 577717
			unsigned int *where = (unsigned int*)((char*)control + offset);
Packit 577717
			if (do_write)
Packit 577717
				*where = regs[i].value;
Packit 577717
			else
Packit 577717
				regs[i].value = *where;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return argbytes;
Packit 577717
}
Packit 577717
Packit 577717
int perfctr_cpu_control_write(struct perfctr_cpu_control *control, unsigned int domain,
Packit 577717
			      const void *srcp, unsigned int srcbytes)
Packit 577717
{
Packit 577717
	if (domain != PERFCTR_DOMAIN_CPU_REGS)
Packit 577717
		return -EINVAL;
Packit 577717
	return access_regs(control, (void*)srcp, srcbytes, 1);
Packit 577717
}
Packit 577717
Packit 577717
int perfctr_cpu_control_read(const struct perfctr_cpu_control *control, unsigned int domain,
Packit 577717
			     void *dstp, unsigned int dstbytes)
Packit 577717
{
Packit 577717
	if (domain != PERFCTR_DOMAIN_CPU_REGS)
Packit 577717
		return -EINVAL;
Packit 577717
	return access_regs((struct perfctr_cpu_control*)control, dstp, dstbytes, 0);
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int i, cstatus;
Packit 577717
	struct perfctr_low_ctrs now;
Packit 577717
Packit 577717
	write_perfseq_begin(&state->user.sequence);
Packit 577717
Packit 577717
	/* quiesce the counters */
Packit 577717
	mtspr(SPRN_MMCR0, MMCR0_FC);
Packit 577717
	get_cpu_cache()->ppc64_mmcr0 = MMCR0_FC;
Packit 577717
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->user.cstatus))
Packit 577717
		perfctr_cpu_isuspend(state);
Packit 577717
Packit 577717
	perfctr_cpu_read_counters(state, &now;;
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		state->user.tsc_sum += now.tsc - state->user.tsc_start;
Packit 577717
Packit 577717
	for (i = 0; i < perfctr_cstatus_nractrs(cstatus); ++i)
Packit 577717
		state->user.pmc[i].sum += (u32)(now.pmc[i]-state->user.pmc[i].start);
Packit 577717
Packit 577717
	write_perfseq_end(&state->user.sequence);
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_resume(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	struct perfctr_low_ctrs now;
Packit 577717
	unsigned int i, cstatus;
Packit 577717
Packit 577717
	write_perfseq_begin(&state->user.sequence);
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->user.cstatus))
Packit 577717
	    perfctr_cpu_iresume(state);
Packit 577717
	perfctr_cpu_write_control(state);
Packit 577717
Packit 577717
	perfctr_cpu_read_counters(state, &now;;
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		state->user.tsc_start = now.tsc;
Packit 577717
Packit 577717
	for (i = 0; i < perfctr_cstatus_nractrs(cstatus); ++i)
Packit 577717
		state->user.pmc[i].start = now.pmc[i];
Packit 577717
Packit 577717
	write_perfseq_end(&state->user.sequence);
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_sample(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int i, cstatus, nractrs;
Packit 577717
	struct perfctr_low_ctrs now;
Packit 577717
Packit 577717
	write_perfseq_begin(&state->user.sequence);
Packit 577717
	perfctr_cpu_read_counters(state, &now;;
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus)) {
Packit 577717
		state->user.tsc_sum += now.tsc - state->user.tsc_start;
Packit 577717
		state->user.tsc_start = now.tsc;
Packit 577717
	}
Packit 577717
	nractrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nractrs; ++i) {
Packit 577717
		state->user.pmc[i].sum += (u32)(now.pmc[i]-state->user.pmc[i].start);
Packit 577717
		state->user.pmc[i].start = now.pmc[i];
Packit 577717
	}
Packit 577717
	write_perfseq_end(&state->user.sequence);
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_clear_counters(void)
Packit 577717
{
Packit 577717
	struct per_cpu_cache *cache;
Packit 577717
Packit 577717
	cache = get_cpu_cache();
Packit 577717
	memset(cache, 0, sizeof *cache);
Packit 577717
	cache->id = 0;
Packit 577717
Packit 577717
	ppc64_clear_counters();
Packit 577717
}
Packit 577717
Packit 577717
/****************************************************************
Packit 577717
 *								*
Packit 577717
 * Processor detection and initialisation procedures.		*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
static void ppc64_cpu_setup(void)
Packit 577717
{
Packit 577717
	/* allow user to initialize these???? */
Packit 577717
Packit 577717
        unsigned long long mmcr0 = mfspr(SPRN_MMCR0);
Packit 577717
        unsigned long long mmcra = mfspr(SPRN_MMCRA);
Packit 577717
Packit 577717
Packit 577717
        ppc64_enable_pmcs();
Packit 577717
Packit 577717
        mmcr0 |= MMCR0_FC;
Packit 577717
        mtspr(SPRN_MMCR0, mmcr0);
Packit 577717
Packit 577717
        mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
Packit 577717
        mmcr0 |= MMCR0_PMC1CE|MMCR0_PMCjCE;
Packit 577717
        mtspr(SPRN_MMCR0, mmcr0);
Packit 577717
Packit 577717
        mmcra |= MMCRA_SAMPLE_ENABLE;
Packit 577717
        mtspr(SPRN_MMCRA, mmcra);
Packit 577717
Packit 577717
	printk("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
Packit 577717
            mfspr(SPRN_MMCR0));
Packit 577717
	printk("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
Packit 577717
            mfspr(SPRN_MMCR1));
Packit 577717
	printk("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
Packit 577717
            mfspr(SPRN_MMCRA));
Packit 577717
Packit 577717
/*         mtmsrd(mfmsr() | MSR_PMM); */
Packit 577717
Packit 577717
	ppc64_clear_counters();
Packit 577717
Packit 577717
	mmcr0 = mfspr(SPRN_MMCR0);
Packit 577717
        mmcr0 &= ~MMCR0_PMAO;
Packit 577717
        mmcr0 &= ~MMCR0_FC;
Packit 577717
        mtspr(SPRN_MMCR0, mmcr0);
Packit 577717
Packit 577717
        printk("start on cpu %d, mmcr0 %llx\n", smp_processor_id(), mmcr0);
Packit 577717
}
Packit 577717
Packit 577717
Packit 577717
static void perfctr_cpu_clear_one(void *ignore)
Packit 577717
{
Packit 577717
	/* PREEMPT note: when called via on_each_cpu(),
Packit 577717
	   this is in IRQ context with preemption disabled. */
Packit 577717
	perfctr_cpu_clear_counters();
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_reset(void)
Packit 577717
{
Packit 577717
	on_each_cpu(perfctr_cpu_clear_one, NULL, 1, 1);
Packit 577717
	perfctr_cpu_set_ihandler(NULL);
Packit 577717
}
Packit 577717
Packit 577717
int __init perfctr_cpu_init(void)
Packit 577717
{
Packit 577717
	extern unsigned long ppc_proc_freq;
Packit 577717
	extern unsigned long ppc_tb_freq;
Packit 577717
Packit 577717
	perfctr_info.cpu_features = PERFCTR_FEATURE_RDTSC
Packit 577717
		| PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_PCINT;
Packit 577717
Packit 577717
	perfctr_cpu_name = "PowerPC64";
Packit 577717
Packit 577717
	perfctr_info.cpu_khz = ppc_proc_freq / 1000;
Packit 577717
	/* We need to round here rather than truncating, because in a
Packit 577717
	 * few cases the raw ratio can end up being 7.9999 or
Packit 577717
	 * suchlike */
Packit 577717
	perfctr_info.tsc_to_cpu_mult =
Packit 577717
		(ppc_proc_freq + ppc_tb_freq - 1) / ppc_tb_freq;
Packit 577717
Packit 577717
	on_each_cpu((void *)ppc64_cpu_setup, NULL, 0, 1);
Packit 577717
Packit 577717
	perfctr_ppc64_init_tests();
Packit 577717
Packit 577717
	perfctr_cpu_reset();
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
void __exit perfctr_cpu_exit(void)
Packit 577717
{
Packit 577717
	perfctr_cpu_reset();
Packit 577717
}
Packit 577717
Packit 577717
/****************************************************************
Packit 577717
 *								*
Packit 577717
 * Hardware reservation.					*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
static spinlock_t service_mutex = SPIN_LOCK_UNLOCKED;
Packit 577717
static const char *current_service = NULL;
Packit 577717
Packit 577717
const char *perfctr_cpu_reserve(const char *service)
Packit 577717
{
Packit 577717
	const char *ret;
Packit 577717
Packit 577717
	spin_lock(&service_mutex);
Packit 577717
Packit 577717
	ret = current_service;
Packit 577717
	if (ret)
Packit 577717
		goto out;
Packit 577717
Packit 577717
	ret = "unknown driver (oprofile?)";
Packit 577717
	if (reserve_pmc_hardware(do_perfctr_interrupt) != 0)
Packit 577717
		goto out;
Packit 577717
Packit 577717
	current_service = service;
Packit 577717
	ret = NULL;
Packit 577717
Packit 577717
 out:
Packit 577717
	spin_unlock(&service_mutex);
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_release(const char *service)
Packit 577717
{
Packit 577717
	spin_lock(&service_mutex);
Packit 577717
Packit 577717
	if (service != current_service) {
Packit 577717
		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
Packit 577717
		       __FUNCTION__, service, current_service);
Packit 577717
		goto out;
Packit 577717
	}
Packit 577717
Packit 577717
	/* power down the counters */
Packit 577717
	perfctr_cpu_reset();
Packit 577717
	current_service = NULL;
Packit 577717
	release_pmc_hardware();
Packit 577717
Packit 577717
 out:
Packit 577717
	spin_unlock(&service_mutex);
Packit 577717
}