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

Packit 577717
/* $Id: ppc.c,v 1.43 2007/10/06 13:02:07 mikpe Exp $
Packit 577717
 * PPC32 performance-monitoring counters driver.
Packit 577717
 *
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, get_tbl() */
Packit 577717
Packit 577717
#include "ppc_tests.h"
Packit 577717
Packit 577717
/* Support for lazy evntsel and 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 int ppc_mmcr[3];
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
	unsigned int tsc;
Packit 577717
	unsigned int pmc[6];
Packit 577717
};
Packit 577717
Packit 577717
enum pm_type {
Packit 577717
	PM_NONE,
Packit 577717
	PM_604,
Packit 577717
	PM_604e,
Packit 577717
	PM_750,	/* XXX: Minor event set diffs between IBM and Moto. */
Packit 577717
	PM_7400,
Packit 577717
	PM_7450,
Packit 577717
};
Packit 577717
static enum pm_type pm_type;
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
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
static void perfctr_default_ihandler(unsigned long pc)
Packit 577717
{
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
	preempt_disable();
Packit 577717
	(*perfctr_ihandler)(instruction_pointer(regs));
Packit 577717
	preempt_enable_no_resched();
Packit 577717
}
Packit 577717
Packit 577717
static inline int perfctr_reserve_pmc_hardware(void)
Packit 577717
{
Packit 577717
	return reserve_pmc_hardware(do_perfctr_interrupt);
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
static inline int perfctr_reserve_pmc_hardware(void)
Packit 577717
{
Packit 577717
	return reserve_pmc_hardware(NULL);
Packit 577717
}
Packit 577717
#define perfctr_cstatus_has_ictrs(cstatus)	0
Packit 577717
#endif
Packit 577717
Packit 577717
static inline void perfctr_release_pmc_hardware(void)
Packit 577717
{
Packit 577717
	release_pmc_hardware();
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
/* The ppc driver internally uses cstatus & (1<<30) to record that
Packit 577717
   a context has an asynchronously changing MMCR0. */
Packit 577717
static inline unsigned int perfctr_cstatus_set_mmcr0_quirk(unsigned int cstatus)
Packit 577717
{
Packit 577717
	return cstatus | (1 << 30);
Packit 577717
}
Packit 577717
Packit 577717
static inline int perfctr_cstatus_has_mmcr0_quirk(unsigned int cstatus)
Packit 577717
{
Packit 577717
	return cstatus & (1 << 30);
Packit 577717
}
Packit 577717
Packit 577717
/****************************************************************
Packit 577717
 *								*
Packit 577717
 * Driver procedures.						*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
/*
Packit 577717
 * The PowerPC 604/750/74xx family.
Packit 577717
 *
Packit 577717
 * Common features
Packit 577717
 * ---------------
Packit 577717
 * - Per counter event selection data in subfields of control registers.
Packit 577717
 *   MMCR0 contains both global control and PMC1/PMC2 event selectors.
Packit 577717
 * - Overflow interrupt support is present in all processors, but an
Packit 577717
 *   erratum makes it difficult to use in 750/7400/7410 processors.
Packit 577717
 * - There is no concept of per-counter qualifiers:
Packit 577717
 *   - User-mode/supervisor-mode restrictions are global.
Packit 577717
 *   - Two groups of counters, PMC1 and PMC2-PMC<highest>. Each group
Packit 577717
 *     has a single overflow interrupt/event enable/disable flag.
Packit 577717
 * - The instructions used to read (mfspr) and write (mtspr) the control
Packit 577717
 *   and counter registers (SPRs) only support hardcoded register numbers.
Packit 577717
 *   There is no support for accessing an SPR via a runtime value.
Packit 577717
 * - Each counter supports its own unique set of events. However, events
Packit 577717
 *   0-1 are common for PMC1-PMC4, and events 2-4 are common for PMC1-PMC4.
Packit 577717
 * - There is no separate high-resolution core clock counter.
Packit 577717
 *   The time-base counter is available, but it typically runs an order of
Packit 577717
 *   magnitude slower than the core clock.
Packit 577717
 *   Any performance counter can be programmed to count core clocks, but
Packit 577717
 *   doing this (a) reserves one PMC, and (b) needs indirect accesses
Packit 577717
 *   since the SPR number in general isn't known at compile-time.
Packit 577717
 *
Packit 577717
 * 604
Packit 577717
 * ---
Packit 577717
 * 604 has MMCR0, PMC1, PMC2, SIA, and SDA.
Packit 577717
 *
Packit 577717
 * MMCR0[THRESHOLD] is not automatically multiplied.
Packit 577717
 *
Packit 577717
 * On the 604, software must always reset MMCR0[ENINT] after
Packit 577717
 * taking a PMI. This is not the case for the 604e.
Packit 577717
 *
Packit 577717
 * 604e
Packit 577717
 * ----
Packit 577717
 * 604e adds MMCR1, PMC3, and PMC4.
Packit 577717
 * Bus-to-core multiplier is available via HID1[PLL_CFG].
Packit 577717
 *
Packit 577717
 * MMCR0[THRESHOLD] is automatically multiplied by 4.
Packit 577717
 *
Packit 577717
 * When the 604e vectors to the PMI handler, it automatically
Packit 577717
 * clears any pending PMIs. Unlike the 604, the 604e does not
Packit 577717
 * require MMCR0[ENINT] to be cleared (and possibly reset)
Packit 577717
 * before external interrupts can be re-enabled.
Packit 577717
 *
Packit 577717
 * 750
Packit 577717
 * ---
Packit 577717
 * 750 adds user-readable MMCRn/PMCn/SIA registers, and removes SDA.
Packit 577717
 *
Packit 577717
 * MMCR0[THRESHOLD] is not automatically multiplied.
Packit 577717
 *
Packit 577717
 * Motorola MPC750UM.pdf, page C-78, states: "The performance monitor
Packit 577717
 * of the MPC755 functions the same as that of the MPC750, (...), except
Packit 577717
 * that for both the MPC750 and MPC755, no combination of the thermal
Packit 577717
 * assist unit, the decrementer register, and the performance monitor
Packit 577717
 * can be used at any one time. If exceptions for any two of these
Packit 577717
 * functional blocks are enabled together, multiple exceptions caused
Packit 577717
 * by any of these three blocks cause unpredictable results."
Packit 577717
 *
Packit 577717
 * IBM 750CXe_Err_DD2X.pdf, Erratum #13, states that a PMI which
Packit 577717
 * occurs immediately after a delayed decrementer exception can
Packit 577717
 * corrupt SRR0, causing the processor to hang. It also states that
Packit 577717
 * PMIs via TB bit transitions can be used to simulate the decrementer.
Packit 577717
 *
Packit 577717
 * 750FX adds dual-PLL support and programmable core frequency switching.
Packit 577717
 *
Packit 577717
 * 750FX DD2.3 fixed the DEC/PMI SRR0 corruption erratum.
Packit 577717
 *
Packit 577717
 * 74xx
Packit 577717
 * ----
Packit 577717
 * 7400 adds MMCR2 and BAMR.
Packit 577717
 *
Packit 577717
 * MMCR0[THRESHOLD] is multiplied by 2 or 32, as specified
Packit 577717
 * by MMCR2[THRESHMULT].
Packit 577717
 *
Packit 577717
 * 74xx changes the semantics of several MMCR0 control bits,
Packit 577717
 * compared to 604/750.
Packit 577717
 *
Packit 577717
 * PPC7410 Erratum No. 10: Like the MPC750 TAU/DECR/PMI erratum.
Packit 577717
 * Erratum No. 14 marks TAU as unsupported in 7410, but this leaves
Packit 577717
 * perfmon and decrementer interrupts as being mutually exclusive.
Packit 577717
 * Affects PPC7410 1.0-1.2 (PVR 0x800C1100-0x800C1102). 1.3 and up
Packit 577717
 * (PVR 0x800C1103 up) are Ok.
Packit 577717
 *
Packit 577717
 * 7450 adds PMC5 and PMC6.
Packit 577717
 *
Packit 577717
 * 7455/7445 V3.3 (PVR 80010303) and later use the 7457 PLL table,
Packit 577717
 * earlier revisions use the 7450 PLL table
Packit 577717
 */
Packit 577717
Packit 577717
static inline unsigned int read_pmc(unsigned int pmc)
Packit 577717
{
Packit 577717
	switch (pmc) {
Packit 577717
	default: /* impossible, but silences gcc warning */
Packit 577717
	case 0:
Packit 577717
		return mfspr(SPRN_PMC1);
Packit 577717
	case 1:
Packit 577717
		return mfspr(SPRN_PMC2);
Packit 577717
	case 2:
Packit 577717
		return mfspr(SPRN_PMC3);
Packit 577717
	case 3:
Packit 577717
		return mfspr(SPRN_PMC4);
Packit 577717
	case 4:
Packit 577717
		return mfspr(SPRN_PMC5);
Packit 577717
	case 5:
Packit 577717
		return mfspr(SPRN_PMC6);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void ppc_read_counters(struct perfctr_cpu_state *state,
Packit 577717
			      struct perfctr_low_ctrs *ctrs)
Packit 577717
{
Packit 577717
	unsigned int cstatus, nrctrs, i;
Packit 577717
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		ctrs->tsc = get_tbl();
Packit 577717
	nrctrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nrctrs; ++i) {
Packit 577717
		unsigned int pmc = state->control.pmc_map[i];
Packit 577717
		ctrs->pmc[i] = read_pmc(pmc);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int pmc_max_event(unsigned int pmc)
Packit 577717
{
Packit 577717
	switch (pmc) {
Packit 577717
	default: /* impossible, but silences gcc warning */
Packit 577717
	case 0:
Packit 577717
		return 127;
Packit 577717
	case 1:
Packit 577717
		return 63;
Packit 577717
	case 2:
Packit 577717
		return 31;
Packit 577717
	case 3:
Packit 577717
		return 31;
Packit 577717
	case 4:
Packit 577717
		return 31;
Packit 577717
	case 5:
Packit 577717
		return 63;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int get_nr_pmcs(void)
Packit 577717
{
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
		return 6;
Packit 577717
	case PM_7400:
Packit 577717
	case PM_750:
Packit 577717
	case PM_604e:
Packit 577717
		return 4;
Packit 577717
	case PM_604:
Packit 577717
		return 2;
Packit 577717
	default: /* PM_NONE, but silences gcc warning */
Packit 577717
		return 0;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static int ppc_check_control(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int i, nractrs, nrctrs, pmc_mask, pmi_mask, pmc;
Packit 577717
	unsigned int nr_pmcs, evntsel[6];
Packit 577717
Packit 577717
	nr_pmcs = get_nr_pmcs();
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
	pmi_mask = 0;
Packit 577717
	evntsel[1-1] = (state->control.mmcr0 >> (31-25)) & 0x7F;
Packit 577717
	evntsel[2-1] = (state->control.mmcr0 >> (31-31)) & 0x3F;
Packit 577717
	evntsel[3-1] = (state->control.mmcr1 >> (31- 4)) & 0x1F;
Packit 577717
	evntsel[4-1] = (state->control.mmcr1 >> (31- 9)) & 0x1F;
Packit 577717
	evntsel[5-1] = (state->control.mmcr1 >> (31-14)) & 0x1F;
Packit 577717
	evntsel[6-1] = (state->control.mmcr1 >> (31-20)) & 0x3F;
Packit 577717
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
		if (i >= nractrs)
Packit 577717
			pmi_mask |= (1<
Packit 577717
Packit 577717
		if (evntsel[pmc] > pmc_max_event(pmc))
Packit 577717
			return -EINVAL;
Packit 577717
	}
Packit 577717
Packit 577717
	/* unused event selectors must be zero */
Packit 577717
	for(i = 0; i < ARRAY_SIZE(evntsel); ++i)
Packit 577717
		if (!(pmc_mask & (1<
Packit 577717
			return -EINVAL;
Packit 577717
Packit 577717
	/* XXX: temporary limitation */
Packit 577717
	if ((pmi_mask & ~1) && (pmi_mask & ~1) != (pmc_mask & ~1))
Packit 577717
		return -EINVAL;
Packit 577717
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
	case PM_7400:
Packit 577717
		if (state->control.mmcr2 & MMCR2_RESERVED)
Packit 577717
			return -EINVAL;
Packit 577717
		break;
Packit 577717
	default:
Packit 577717
		if (state->control.mmcr2)
Packit 577717
			return -EINVAL;
Packit 577717
	}
Packit 577717
Packit 577717
	/* check MMCR1; non-existent event selectors are taken care of
Packit 577717
	   by the "unused event selectors must be zero" check above */
Packit 577717
	if (state->control.mmcr1 & MMCR1__RESERVED)
Packit 577717
		return -EINVAL;
Packit 577717
Packit 577717
	/* We do not yet handle TBEE as the only exception cause,
Packit 577717
	   so PMXE requires at least one interrupt-mode counter. */
Packit 577717
	if ((state->control.mmcr0 & MMCR0_PMXE) && !state->control.header.nrictrs)
Packit 577717
		return -EINVAL;
Packit 577717
Packit 577717
	state->id = new_id();
Packit 577717
Packit 577717
	/*
Packit 577717
	 * MMCR0[FC] and MMCR0[TRIGGER] may change on 74xx if FCECE or
Packit 577717
	 * TRIGGER is set. At suspends we must read MMCR0 back into
Packit 577717
	 * the state and the cache and then freeze the counters, and
Packit 577717
	 * at resumes we must unfreeze the counters and reload MMCR0.
Packit 577717
	 */
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
	case PM_7400:
Packit 577717
		if (state->control.mmcr0 & (MMCR0_FCECE | MMCR0_TRIGGER))
Packit 577717
			state->user.cstatus = perfctr_cstatus_set_mmcr0_quirk(state->user.cstatus);
Packit 577717
	default:
Packit 577717
		;
Packit 577717
	}
Packit 577717
Packit 577717
	/* The MMCR0 handling for FCECE and TRIGGER is also needed for PMXE. */
Packit 577717
	if (state->control.mmcr0 & (MMCR0_PMXE | MMCR0_FCECE | MMCR0_TRIGGER))
Packit 577717
		state->user.cstatus = perfctr_cstatus_set_mmcr0_quirk(state->user.cstatus);
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
Packit 577717
/* PRE: counters frozen */
Packit 577717
static void ppc_isuspend(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
	set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */
Packit 577717
	cache = __get_cpu_cache(cpu);
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
		unsigned int pmc = state->control.pmc_map[i];
Packit 577717
		unsigned int now = read_pmc(pmc);
Packit 577717
		state->user.pmc[i].sum += now - state->user.pmc[i].start;
Packit 577717
		state->user.pmc[i].start = now;
Packit 577717
	}
Packit 577717
	/* cache->id is still == state->id */
Packit 577717
}
Packit 577717
Packit 577717
static void ppc_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
	unsigned int pmc[6];
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
	 * 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->ppc_mmcr[0] & MMCR0_FC)) {
Packit 577717
		cache->ppc_mmcr[0] |= MMCR0_FC;
Packit 577717
		mtspr(SPRN_MMCR0, cache->ppc_mmcr[0]);
Packit 577717
	}
Packit 577717
	memset(&pmc[0], 0, sizeof pmc);
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
		pmc[state->control.pmc_map[i]] = state->user.pmc[i].start;
Packit 577717
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
		mtspr(SPRN_PMC6, pmc[6-1]);
Packit 577717
		mtspr(SPRN_PMC5, pmc[5-1]);
Packit 577717
	case PM_7400:
Packit 577717
	case PM_750:
Packit 577717
	case PM_604e:
Packit 577717
		mtspr(SPRN_PMC4, pmc[4-1]);
Packit 577717
		mtspr(SPRN_PMC3, pmc[3-1]);
Packit 577717
	case PM_604:
Packit 577717
		mtspr(SPRN_PMC2, pmc[2-1]);
Packit 577717
		mtspr(SPRN_PMC1, pmc[1-1]);
Packit 577717
	case PM_NONE:
Packit 577717
		;
Packit 577717
	}
Packit 577717
	/* cache->id remains != state->id */
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void ppc_write_control(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	struct per_cpu_cache *cache;
Packit 577717
	unsigned int value;
Packit 577717
Packit 577717
	cache = get_cpu_cache();
Packit 577717
	if (cache->id == state->id)
Packit 577717
		return;
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.mmcr2;
Packit 577717
	if (value != cache->ppc_mmcr[2]) {
Packit 577717
		cache->ppc_mmcr[2] = value;
Packit 577717
		mtspr(SPRN_MMCR2, value);
Packit 577717
	}
Packit 577717
	value = state->control.mmcr1;
Packit 577717
	if (value != cache->ppc_mmcr[1]) {
Packit 577717
		cache->ppc_mmcr[1] = value;
Packit 577717
		mtspr(SPRN_MMCR1, value);
Packit 577717
	}
Packit 577717
	value = state->control.mmcr0;
Packit 577717
	if (value != cache->ppc_mmcr[0]) {
Packit 577717
		cache->ppc_mmcr[0] = value;
Packit 577717
		mtspr(SPRN_MMCR0, value);
Packit 577717
	}
Packit 577717
	cache->id = state->id;
Packit 577717
}
Packit 577717
Packit 577717
static void ppc_clear_counters(void)
Packit 577717
{
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
	case PM_7400:
Packit 577717
		mtspr(SPRN_MMCR2, 0);
Packit 577717
		mtspr(SPRN_BAMR, 0);
Packit 577717
	case PM_750:
Packit 577717
	case PM_604e:
Packit 577717
		mtspr(SPRN_MMCR1, 0);
Packit 577717
	case PM_604:
Packit 577717
		mtspr(SPRN_MMCR0, 0);
Packit 577717
	case PM_NONE:
Packit 577717
		;
Packit 577717
	}
Packit 577717
	switch (pm_type) {
Packit 577717
	case PM_7450:
Packit 577717
		mtspr(SPRN_PMC6, 0);
Packit 577717
		mtspr(SPRN_PMC5, 0);
Packit 577717
	case PM_7400:
Packit 577717
	case PM_750:
Packit 577717
	case PM_604e:
Packit 577717
		mtspr(SPRN_PMC4, 0);
Packit 577717
		mtspr(SPRN_PMC3, 0);
Packit 577717
	case PM_604:
Packit 577717
		mtspr(SPRN_PMC2, 0);
Packit 577717
		mtspr(SPRN_PMC1, 0);
Packit 577717
	case PM_NONE:
Packit 577717
		;
Packit 577717
	}
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
	return ppc_write_control(state);
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
	return ppc_read_counters(state, ctrs);
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
	return ppc_isuspend(state);
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	return ppc_iresume(state);
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
	state->control.mmcr0 |= MMCR0_PMXE;
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, nrctrs, i, pmc_mask;
Packit 577717
Packit 577717
	cstatus = state->user.cstatus;
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
	pmc_mask = 0;
Packit 577717
	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
Packit 577717
		if ((int)state->user.pmc[i].start < 0) { /* PPC-specific */
Packit 577717
			unsigned 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
	if (!pmc_mask && (state->control.mmcr0 & MMCR0_TBEE))
Packit 577717
		pmc_mask = (1<<8); /* fake TB bit flip indicator */
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) /* PPC-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
	return ppc_check_control(state);
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
		state->user.cstatus = 0;
Packit 577717
		return err;
Packit 577717
	}
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
 * suitable for accessing control data of type unsigned int.
Packit 577717
 */
Packit 577717
static const struct {
Packit 577717
	unsigned int spr;
Packit 577717
	unsigned int offset;
Packit 577717
} reg_offsets[] = {
Packit 577717
	{ SPRN_MMCR0, offsetof(struct perfctr_cpu_control, mmcr0) },
Packit 577717
	{ SPRN_MMCR1, offsetof(struct perfctr_cpu_control, mmcr1) },
Packit 577717
	{ SPRN_MMCR2, offsetof(struct perfctr_cpu_control, mmcr2) },
Packit 577717
	{ SPRN_PMC1,  offsetof(struct perfctr_cpu_control, ireset[1-1]) },
Packit 577717
	{ SPRN_PMC2,  offsetof(struct perfctr_cpu_control, ireset[2-1]) },
Packit 577717
	{ SPRN_PMC3,  offsetof(struct perfctr_cpu_control, ireset[3-1]) },
Packit 577717
	{ SPRN_PMC4,  offsetof(struct perfctr_cpu_control, ireset[4-1]) },
Packit 577717
	{ SPRN_PMC5,  offsetof(struct perfctr_cpu_control, ireset[5-1]) },
Packit 577717
	{ SPRN_PMC6,  offsetof(struct perfctr_cpu_control, ireset[6-1]) },
Packit 577717
};
Packit 577717
Packit 577717
static int get_reg_offset(unsigned int spr)
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
			return reg_offsets[i].offset;
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, *where;
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);
Packit 577717
		if (offset < 0)
Packit 577717
			return -EINVAL;
Packit 577717
		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
	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, nractrs;
Packit 577717
	struct perfctr_low_ctrs now;
Packit 577717
Packit 577717
	write_perfseq_begin(&state->user.sequence);
Packit 577717
	if (perfctr_cstatus_has_mmcr0_quirk(state->user.cstatus)) {
Packit 577717
		unsigned int mmcr0 = mfspr(SPRN_MMCR0);
Packit 577717
		mtspr(SPRN_MMCR0, mmcr0 | MMCR0_FC);
Packit 577717
		get_cpu_cache()->ppc_mmcr[0] = mmcr0 | MMCR0_FC;
Packit 577717
		state->control.mmcr0 = mmcr0;
Packit 577717
	}
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->user.cstatus))
Packit 577717
		perfctr_cpu_isuspend(state);
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
	nractrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nractrs; ++i)
Packit 577717
		state->user.pmc[i].sum += now.pmc[i] - state->user.pmc[i].start;
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
	write_perfseq_begin(&state->user.sequence);
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->user.cstatus))
Packit 577717
	    perfctr_cpu_iresume(state);
Packit 577717
	if (perfctr_cstatus_has_mmcr0_quirk(state->user.cstatus))
Packit 577717
		get_cpu_cache()->id = 0; /* force reload of MMCR0 */
Packit 577717
	perfctr_cpu_write_control(state);
Packit 577717
	//perfctr_cpu_read_counters(state, &state->start);
Packit 577717
	{
Packit 577717
		struct perfctr_low_ctrs now;
Packit 577717
		unsigned int i, cstatus, nrctrs;
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
		nrctrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
		for(i = 0; i < nrctrs; ++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 += 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 = -1;
Packit 577717
Packit 577717
	ppc_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
/* Derive CPU core frequency from TB frequency and PLL_CFG. */
Packit 577717
Packit 577717
enum pll_type {
Packit 577717
	PLL_NONE,	/* for e.g. 604 which has no HID1[PLL_CFG] */
Packit 577717
	PLL_604e,
Packit 577717
	PLL_750,
Packit 577717
	PLL_750FX,
Packit 577717
	PLL_7400,
Packit 577717
	PLL_7450,
Packit 577717
	PLL_7457,
Packit 577717
};
Packit 577717
Packit 577717
/* These are the known bus-to-core ratios, indexed by PLL_CFG.
Packit 577717
   Multiplied by 2 since half-multiplier steps are present. */
Packit 577717
Packit 577717
static unsigned char cfg_ratio_604e[16] __initdata = { // *2
Packit 577717
	2, 2, 14, 2, 4, 13, 5, 9,
Packit 577717
	6, 11, 8, 10, 3, 12, 7, 0
Packit 577717
};
Packit 577717
Packit 577717
static unsigned char cfg_ratio_750[16] __initdata = { // *2
Packit 577717
	5, 15, 14, 2, 4, 13, 20, 9, // 0b0110 is 18 if L1_TSTCLK=0, but that is abnormal
Packit 577717
	6, 11, 8, 10, 16, 12, 7, 0
Packit 577717
};
Packit 577717
Packit 577717
static unsigned char cfg_ratio_750FX[32] __initdata = { // *2
Packit 577717
	0, 0, 2, 2, 4, 5, 6, 7,
Packit 577717
	8, 9, 10, 11, 12, 13, 14, 15,
Packit 577717
	16, 17, 18, 19, 20, 22, 24, 26,
Packit 577717
	28, 30, 32, 34, 36, 38, 40, 0
Packit 577717
};
Packit 577717
Packit 577717
static unsigned char cfg_ratio_7400[16] __initdata = { // *2
Packit 577717
	18, 15, 14, 2, 4, 13, 5, 9,
Packit 577717
	6, 11, 8, 10, 16, 12, 7, 0
Packit 577717
};
Packit 577717
Packit 577717
static unsigned char cfg_ratio_7450[32] __initdata = { // *2
Packit 577717
	1, 0, 15, 30, 14, 0, 2, 0,
Packit 577717
	4, 0, 13, 26, 5, 0, 9, 18,
Packit 577717
	6, 0, 11, 22, 8, 20, 10, 24,
Packit 577717
	16, 28, 12, 32, 7, 0, 0, 0
Packit 577717
};
Packit 577717
Packit 577717
static unsigned char cfg_ratio_7457[32] __initdata = { // *2
Packit 577717
	23, 34, 15, 30, 14, 36, 2, 40,
Packit 577717
	4, 42, 13, 26, 17, 48, 19, 18,
Packit 577717
	6, 21, 11, 22, 8, 20, 10, 24,
Packit 577717
	16, 28, 12, 32, 27, 56, 0, 25
Packit 577717
};
Packit 577717
Packit 577717
static unsigned int __init tb_to_core_ratio(enum pll_type pll_type)
Packit 577717
{
Packit 577717
	unsigned char *cfg_ratio;
Packit 577717
	unsigned int shift = 28, mask = 0xF, hid1, pll_cfg, ratio;
Packit 577717
Packit 577717
	switch (pll_type) {
Packit 577717
	case PLL_604e:
Packit 577717
		cfg_ratio = cfg_ratio_604e;
Packit 577717
		break;
Packit 577717
	case PLL_750:
Packit 577717
		cfg_ratio = cfg_ratio_750;
Packit 577717
		break;
Packit 577717
	case PLL_750FX:
Packit 577717
		cfg_ratio = cfg_ratio_750FX;
Packit 577717
		hid1 = mfspr(SPRN_HID1);
Packit 577717
		switch ((hid1 >> 16) & 0x3) { /* HID1[PI0,PS] */
Packit 577717
		case 0:		/* PLL0 with external config */
Packit 577717
			shift = 31-4;	/* access HID1[PCE] */
Packit 577717
			break;
Packit 577717
		case 2:		/* PLL0 with internal config */
Packit 577717
			shift = 31-20;	/* access HID1[PC0] */
Packit 577717
			break;
Packit 577717
		case 1: case 3:	/* PLL1 */
Packit 577717
			shift = 31-28;	/* access HID1[PC1] */
Packit 577717
			break;
Packit 577717
		}
Packit 577717
		mask = 0x1F;
Packit 577717
		break;
Packit 577717
	case PLL_7400:
Packit 577717
		cfg_ratio = cfg_ratio_7400;
Packit 577717
		break;
Packit 577717
	case PLL_7450:
Packit 577717
		cfg_ratio = cfg_ratio_7450;
Packit 577717
		shift = 12;
Packit 577717
		mask = 0x1F;
Packit 577717
		break;
Packit 577717
	case PLL_7457:
Packit 577717
		cfg_ratio = cfg_ratio_7457;
Packit 577717
		shift = 12;
Packit 577717
		mask = 0x1F;
Packit 577717
		break;
Packit 577717
	default:
Packit 577717
		return 0;
Packit 577717
	}
Packit 577717
	hid1 = mfspr(SPRN_HID1);
Packit 577717
	pll_cfg = (hid1 >> shift) & mask;
Packit 577717
	ratio = cfg_ratio[pll_cfg];
Packit 577717
	if (!ratio)
Packit 577717
		printk(KERN_WARNING "perfctr: unknown PLL_CFG 0x%x\n", pll_cfg);
Packit 577717
	return (4/2) * ratio;
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int __init pll_to_core_khz(enum pll_type pll_type)
Packit 577717
{
Packit 577717
	unsigned int tb_to_core = tb_to_core_ratio(pll_type);
Packit 577717
	perfctr_info.tsc_to_cpu_mult = tb_to_core;
Packit 577717
	return tb_ticks_per_jiffy * tb_to_core * (HZ/10) / (1000/10);
Packit 577717
}
Packit 577717
Packit 577717
/* Extract core and timebase frequencies from Open Firmware. */
Packit 577717
Packit 577717
#ifdef CONFIG_PPC_OF
Packit 577717
static unsigned int __init of_to_core_khz(void)
Packit 577717
{
Packit 577717
	struct device_node *cpu;
Packit 577717
	unsigned int *fp, core, tb;
Packit 577717
Packit 577717
	cpu = find_type_devices("cpu");
Packit 577717
	if (!cpu)
Packit 577717
		return 0;
Packit 577717
	fp = (unsigned int*)get_property(cpu, "clock-frequency", NULL);
Packit 577717
	if (!fp || !(core = *fp))
Packit 577717
		return 0;
Packit 577717
	fp = (unsigned int*)get_property(cpu, "timebase-frequency", NULL);
Packit 577717
	if (!fp || !(tb = *fp))
Packit 577717
		return 0;
Packit 577717
	perfctr_info.tsc_to_cpu_mult = core / tb;
Packit 577717
	return core / 1000;
Packit 577717
}
Packit 577717
#else
Packit 577717
static inline unsigned int of_to_core_khz(void) { return 0; }
Packit 577717
#endif
Packit 577717
Packit 577717
static unsigned int __init detect_cpu_khz(enum pll_type pll_type)
Packit 577717
{
Packit 577717
	unsigned int khz;
Packit 577717
Packit 577717
	khz = pll_to_core_khz(pll_type);
Packit 577717
	if (khz)
Packit 577717
		return khz;
Packit 577717
Packit 577717
	khz = of_to_core_khz();
Packit 577717
	if (khz)
Packit 577717
		return khz;
Packit 577717
Packit 577717
	printk(KERN_WARNING "perfctr: unable to determine CPU speed\n");
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
static int __init known_init(void)
Packit 577717
{
Packit 577717
	static char known_name[] __initdata = "PowerPC 60x/7xx/74xx";
Packit 577717
	unsigned int features;
Packit 577717
	enum pll_type pll_type;
Packit 577717
	unsigned int pvr;
Packit 577717
	int have_mmcr1;
Packit 577717
Packit 577717
	features = PERFCTR_FEATURE_RDTSC | PERFCTR_FEATURE_RDPMC;
Packit 577717
	have_mmcr1 = 1;
Packit 577717
	pvr = mfspr(SPRN_PVR);
Packit 577717
	switch (PVR_VER(pvr)) {
Packit 577717
	case 0x0004: /* 604 */
Packit 577717
		pm_type = PM_604;
Packit 577717
		pll_type = PLL_NONE;
Packit 577717
		features = PERFCTR_FEATURE_RDTSC;
Packit 577717
		have_mmcr1 = 0;
Packit 577717
		break;
Packit 577717
	case 0x0009: /* 604e;  */
Packit 577717
	case 0x000A: /* 604ev */
Packit 577717
		pm_type = PM_604e;
Packit 577717
		pll_type = PLL_604e;
Packit 577717
		features = PERFCTR_FEATURE_RDTSC;
Packit 577717
		break;
Packit 577717
	case 0x0008: /* 750/740 */
Packit 577717
		pm_type = PM_750;
Packit 577717
		pll_type = PLL_750;
Packit 577717
		break;
Packit 577717
	case 0x7000: case 0x7001: /* IBM750FX */
Packit 577717
		if ((pvr & 0xFF0F) >= 0x0203)
Packit 577717
			features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_750;
Packit 577717
		pll_type = PLL_750FX;
Packit 577717
		break;
Packit 577717
	case 0x7002: /* IBM750GX */
Packit 577717
		features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_750;
Packit 577717
		pll_type = PLL_750FX;
Packit 577717
		break;
Packit 577717
	case 0x000C: /* 7400 */
Packit 577717
		pm_type = PM_7400;
Packit 577717
		pll_type = PLL_7400;
Packit 577717
		break;
Packit 577717
	case 0x800C: /* 7410 */
Packit 577717
		if ((pvr & 0xFFFF) >= 0x1103)
Packit 577717
			features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_7400;
Packit 577717
		pll_type = PLL_7400;
Packit 577717
		break;
Packit 577717
	case 0x8000: /* 7451/7441 */
Packit 577717
		features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_7450;
Packit 577717
		pll_type = PLL_7450;
Packit 577717
		break;
Packit 577717
	case 0x8001: /* 7455/7445 */
Packit 577717
		features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_7450;
Packit 577717
		pll_type = ((pvr & 0xFFFF) < 0x0303) ? PLL_7450 : PLL_7457;
Packit 577717
		break;
Packit 577717
	case 0x8002: /* 7457/7447 */
Packit 577717
	case 0x8003: /* 7447A */
Packit 577717
		features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_7450;
Packit 577717
		pll_type = PLL_7457;
Packit 577717
		break;
Packit 577717
	case 0x8004: /* 7448 */
Packit 577717
		features |= PERFCTR_FEATURE_PCINT;
Packit 577717
		pm_type = PM_7450;
Packit 577717
		pll_type = PLL_NONE; /* known to differ from 7447A, no details yet */
Packit 577717
		break;
Packit 577717
	default:
Packit 577717
		return -ENODEV;
Packit 577717
	}
Packit 577717
	perfctr_info.cpu_features = features;
Packit 577717
	perfctr_cpu_name = known_name;
Packit 577717
	perfctr_info.cpu_khz = detect_cpu_khz(pll_type);
Packit 577717
	perfctr_ppc_init_tests(have_mmcr1);
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
static int __init unknown_init(void)
Packit 577717
{
Packit 577717
	static char unknown_name[] __initdata = "Generic PowerPC with TB";
Packit 577717
	unsigned int khz;
Packit 577717
Packit 577717
	khz = detect_cpu_khz(PLL_NONE);
Packit 577717
	if (!khz)
Packit 577717
		return -ENODEV;
Packit 577717
	perfctr_info.cpu_features = PERFCTR_FEATURE_RDTSC;
Packit 577717
	perfctr_cpu_name = unknown_name;
Packit 577717
	perfctr_info.cpu_khz = khz;
Packit 577717
	pm_type = PM_NONE;
Packit 577717
	return 0;
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
static int init_done;
Packit 577717
Packit 577717
int __init perfctr_cpu_init(void)
Packit 577717
{
Packit 577717
	int err;
Packit 577717
Packit 577717
	perfctr_info.cpu_features = 0;
Packit 577717
Packit 577717
	err = known_init();
Packit 577717
	if (err) {
Packit 577717
		err = unknown_init();
Packit 577717
		if (err)
Packit 577717
			goto out;
Packit 577717
	}
Packit 577717
Packit 577717
	init_done = 1;
Packit 577717
 out:
Packit 577717
	return err;
Packit 577717
}
Packit 577717
Packit 577717
void __exit perfctr_cpu_exit(void)
Packit 577717
{
Packit 577717
}
Packit 577717
Packit 577717
/****************************************************************
Packit 577717
 *								*
Packit 577717
 * Hardware reservation.					*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
static DEFINE_MUTEX(mutex);
Packit 577717
static const char *current_service = 0;
Packit 577717
Packit 577717
const char *perfctr_cpu_reserve(const char *service)
Packit 577717
{
Packit 577717
	const char *ret;
Packit 577717
Packit 577717
	if (!init_done)
Packit 577717
		return "unsupported hardware";
Packit 577717
	mutex_lock(&mutex);
Packit 577717
	ret = current_service;
Packit 577717
	if (ret)
Packit 577717
		goto out_unlock;
Packit 577717
	ret = "unknown driver (oprofile?)";
Packit 577717
	if (perfctr_reserve_pmc_hardware() < 0)
Packit 577717
		goto out_unlock;
Packit 577717
	current_service = service;
Packit 577717
	perfctr_cpu_reset();
Packit 577717
	ret = NULL;
Packit 577717
 out_unlock:
Packit 577717
	mutex_unlock(&mutex);
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_release(const char *service)
Packit 577717
{
Packit 577717
	mutex_lock(&mutex);
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
	} else {
Packit 577717
		/* power down the counters */
Packit 577717
		perfctr_cpu_reset();
Packit 577717
		current_service = 0;
Packit 577717
		perfctr_release_pmc_hardware();
Packit 577717
	}
Packit 577717
	mutex_unlock(&mutex);
Packit 577717
}