Blame src/perfctr-2.6.x/linux/drivers/perfctr/arm.c

Packit 577717
/* $Id: arm.c,v 1.1.2.3 2009/06/11 12:33:51 mikpe Exp $
Packit 577717
 * ARM/XScale performance-monitoring counters driver.
Packit 577717
 *
Packit 577717
 * Copyright (C) 2005-2009  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
#define __NO_VERSION__
Packit 577717
#include <linux/module.h>
Packit 577717
#include <linux/init.h>
Packit 577717
#include <linux/sched.h>
Packit 577717
#include <linux/perfctr.h>
Packit 577717
#include <asm/cputype.h>
Packit 577717
Packit 577717
#include "compat.h"
Packit 577717
Packit 577717
/* Support for lazy evntsel and perfctr register updates. */
Packit 577717
struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
Packit 577717
	union {
Packit 577717
		unsigned int id;	/* cache owner id */
Packit 577717
	} k1;
Packit 577717
	union {
Packit 577717
		struct {
Packit 577717
			unsigned int pmnc;
Packit 577717
		} xsc1;
Packit 577717
		struct {
Packit 577717
			unsigned int evtsel;
Packit 577717
			unsigned int inten;
Packit 577717
			unsigned int pmnc;
Packit 577717
		} xsc2;
Packit 577717
	} arm;
Packit 577717
} ____cacheline_aligned;
Packit 577717
static struct per_cpu_cache per_cpu_cache[NR_CPUS] __cacheline_aligned;
Packit 577717
#define __get_cpu_cache(cpu) (&per_cpu_cache[cpu])
Packit 577717
#define get_cpu_cache()	(&per_cpu_cache[smp_processor_id()])
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[4];
Packit 577717
};
Packit 577717
Packit 577717
#define PMU_XSC1	1
Packit 577717
#define PMU_XSC2	2
Packit 577717
static unsigned int pmu_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
#ifndef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
#define perfctr_cstatus_has_ictrs(cstatus)	0
Packit 577717
#endif
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->k1.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->k1.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->k1.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
 *								*
Packit 577717
 * Driver procedures.						*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
/*
Packit 577717
 * XScale1 driver procedures.
Packit 577717
 */
Packit 577717
Packit 577717
static u32 xsc1_read_pmnc(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c0, c0, 0" : "=r"(val));
Packit 577717
	/* bits 1, 2, 7, 11, 28-31 are read-unpredictable */
Packit 577717
	val &= 0x0ffff779;
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
static void xsc1_write_pmnc(u32 val)
Packit 577717
{
Packit 577717
	/* bits 7, 11, 28-31 are write-as-0 */
Packit 577717
	val &= 0x0ffff77f;
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c0, c0, 0" : : "r"(val));
Packit 577717
}
Packit 577717
Packit 577717
static u32 xsc1_read_ccnt(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c1, c0, 0" : "=r"(val));
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static void xsc1_write_ccnt(u32 val)
Packit 577717
{
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c1, c0, 0" : : "r"(val));
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static u32 xsc1_read_pmc(u32 counter)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	switch (counter) {
Packit 577717
	default: /* impossible, but silences gcc warning */
Packit 577717
	case 0:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c2, c0, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c3, c0, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	}
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static void xsc1_write_pmc(u32 counter, u32 val)
Packit 577717
{
Packit 577717
	switch (counter) {
Packit 577717
	case 0:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c2, c0, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c3, c0, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	}
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void xsc1_clear_counters(void)
Packit 577717
{
Packit 577717
	u32 pmnc;
Packit 577717
Packit 577717
	pmnc = xsc1_read_pmnc();
Packit 577717
	/* preserve CCNT settings */
Packit 577717
	pmnc &= (1 << 10) | (1 << 6) | (1 << 3) | (1 << 0);
Packit 577717
	/* update non-CCNT settings: set event selectors to idle, and
Packit 577717
	   reset the performance counters and their overflow flags. */
Packit 577717
	pmnc |= (0xFF << 20) | (0xFF << 12) | (0x3 << 8) | (1 << 1);
Packit 577717
	xsc1_write_pmnc(pmnc);
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int xsc1_nr_pmcs(void)
Packit 577717
{
Packit 577717
	return 2;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * XScale2 driver procedures.
Packit 577717
 */
Packit 577717
Packit 577717
static u32 xsc2_read_pmnc(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c0, c1, 0" : "=r"(val));
Packit 577717
	/* bits 1, 2, 4-23 are read-unpredictable */
Packit 577717
	val &= 0xff000009;
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
static void xsc2_write_pmnc(u32 val)
Packit 577717
{
Packit 577717
	/* bits 4-23 are write-as-0, 24-31 are write ignored */
Packit 577717
	val &= 0x0000000f;
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c0, c1, 0" : : "r"(val));
Packit 577717
}
Packit 577717
Packit 577717
static u32 xsc2_read_ccnt(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c1, c1, 0" : "=r"(val));
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static void xsc2_write_ccnt(u32 val)
Packit 577717
{
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c1, c1, 0" : : "r"(val));
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static u32 xsc2_read_inten(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c4, c1, 0" : "=r"(val));
Packit 577717
	/* bits 5-31 are read-unpredictable */
Packit 577717
	val &= 0x0000001f;
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
static void xsc2_write_inten(u32 val)
Packit 577717
{
Packit 577717
	/* bits 5-31 are write-as-zero */
Packit 577717
	val &= 0x0000001f;
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c4, c1, 0" : : "r"(val));
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static u32 xsc2_read_flag(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c5, c1, 0" : "=r"(val));
Packit 577717
	/* bits 5-31 are read-unpredictable */
Packit 577717
	val &= 0x0000001f;
Packit 577717
	return val;
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void xsc2_write_flag(u32 val)
Packit 577717
{
Packit 577717
	/* bits 5-31 are write-as-zero */
Packit 577717
	val &= 0x0000001f;
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c5, c1, 0" : : "r"(val));
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static u32 xsc2_read_evtsel(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	__asm__ __volatile__("mrc p14, 0, %0, c8, c1, 0" : "=r"(val));
Packit 577717
	return val;
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void xsc2_write_evtsel(u32 val)
Packit 577717
{
Packit 577717
	__asm__ __volatile__("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));
Packit 577717
}
Packit 577717
Packit 577717
static u32 xsc2_read_pmc(u32 counter)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	switch (counter) {
Packit 577717
	default: /* impossible, but silences gcc warning */
Packit 577717
	case 0:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c0, c2, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c1, c2, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	case 2:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c2, c2, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	case 3:
Packit 577717
		__asm__ __volatile__("mrc p14, 0, %0, c3, c2, 0" : "=r"(val));
Packit 577717
		break;
Packit 577717
	}
Packit 577717
	return val;
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
static void xsc2_write_pmc(u32 counter, u32 val)
Packit 577717
{
Packit 577717
	switch (counter) {
Packit 577717
	case 0:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c0, c2, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	case 1:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c1, c2, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	case 2:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c2, c2, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	case 3:
Packit 577717
		__asm__ __volatile__("mcr p14, 0, %0, c3, c2, 0" : : "r"(val));
Packit 577717
		break;
Packit 577717
	}
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void xsc2_clear_counters(void)
Packit 577717
{
Packit 577717
	u32 val;
Packit 577717
Packit 577717
	/* clear interrupt enable bits */
Packit 577717
	val = xsc2_read_inten();
Packit 577717
	val &= (1 << 0);		/* all but CCNT */
Packit 577717
	xsc2_write_inten(val);
Packit 577717
Packit 577717
	/* set event selectors to idle */
Packit 577717
	xsc2_write_evtsel(0xFFFFFFFF);
Packit 577717
Packit 577717
	/* reset the performance counters */
Packit 577717
	val = xsc2_read_pmnc();
Packit 577717
	val &= (1 << 3) | (1 << 0);	/* preserve CCNT settings */
Packit 577717
	val |= (1 << 1);		/* reset the performance counters */
Packit 577717
	xsc2_write_pmnc(val);
Packit 577717
Packit 577717
	/* clear overflow status bits */
Packit 577717
	xsc2_write_flag(0x1E);		/* all but CCNT */
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int xsc2_nr_pmcs(void)
Packit 577717
{
Packit 577717
	return 4;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * XScale driver procedures.
Packit 577717
 */
Packit 577717
Packit 577717
static u32 xscale_read_ccnt(void)
Packit 577717
{
Packit 577717
	if (pmu_type == PMU_XSC1)
Packit 577717
		return xsc1_read_ccnt();
Packit 577717
	else
Packit 577717
		return xsc2_read_ccnt();
Packit 577717
}
Packit 577717
Packit 577717
static u32 xscale_read_pmc(u32 counter)
Packit 577717
{
Packit 577717
	if (pmu_type == PMU_XSC1)
Packit 577717
		return xsc1_read_pmc(counter);
Packit 577717
	else
Packit 577717
		return xsc2_read_pmc(counter);
Packit 577717
}
Packit 577717
Packit 577717
static void xscale_clear_counters(void)
Packit 577717
{
Packit 577717
	if (pmu_type == PMU_XSC1)
Packit 577717
		xsc1_clear_counters();
Packit 577717
	else
Packit 577717
		xsc2_clear_counters();
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int xscale_nr_pmcs(void)
Packit 577717
{
Packit 577717
	if (pmu_type == PMU_XSC1)
Packit 577717
		return xsc1_nr_pmcs();
Packit 577717
	else
Packit 577717
		return xsc2_nr_pmcs();
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int xscale_check_event(unsigned int evntsel)
Packit 577717
{
Packit 577717
	/* Events 0x00-0x0D are defined for the XScale core
Packit 577717
	   and the IXP42x family.
Packit 577717
	   Event 0xFF is defined as an "idle" event, but users
Packit 577717
	   have no reason to specify it, so we reject it.
Packit 577717
	   Events 0x10-0x16 are defined in oprofile, but not
Packit 577717
	   in the XScale core or IXP42x manuals. */
Packit 577717
	return (evntsel <= 0x0D) ? 0 : -1;
Packit 577717
}
Packit 577717
Packit 577717
static void xscale_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->cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		ctrs->tsc = xscale_read_ccnt();
Packit 577717
	nrctrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nrctrs; ++i) {
Packit 577717
		unsigned int pmc = state->pmc[i].map;
Packit 577717
		ctrs->pmc[i] = xscale_read_pmc(pmc);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static int xscale_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[4];
Packit 577717
Packit 577717
	nr_pmcs = xscale_nr_pmcs();
Packit 577717
	nractrs = state->control.nractrs;
Packit 577717
	nrctrs = nractrs + state->control.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
	memset(evntsel, 0, sizeof evntsel);
Packit 577717
	for(i = 0; i < nrctrs; ++i) {
Packit 577717
		pmc = state->control.pmc_map[i];
Packit 577717
		state->pmc[i].map = pmc;
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
		evntsel[pmc] = state->control.evntsel[i];
Packit 577717
		if (xscale_check_event(evntsel[pmc]))
Packit 577717
			return -EINVAL;
Packit 577717
	}
Packit 577717
Packit 577717
	switch (pmu_type) {
Packit 577717
	case PMU_XSC1:
Packit 577717
		state->arm.xsc1.pmnc =
Packit 577717
			((evntsel[1] << 20) |
Packit 577717
			 (evntsel[0] << 12) |
Packit 577717
			 (pmi_mask << 4) |	/* inten field */
Packit 577717
			 1);			/* enable */
Packit 577717
		break;
Packit 577717
	case PMU_XSC2:
Packit 577717
		state->arm.xsc2.evtsel =
Packit 577717
			((evntsel[3] << 24) |
Packit 577717
			 (evntsel[2] << 16) |
Packit 577717
			 (evntsel[1] << 8) |
Packit 577717
			 evntsel[0]);
Packit 577717
		state->arm.xsc2.inten = pmi_mask << 1;
Packit 577717
		break;
Packit 577717
	}
Packit 577717
Packit 577717
	state->k1.id = new_id();
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 *//* XXX: that is FALSE on XScale! */
Packit 577717
static void xscale_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->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->pmc[i].map;
Packit 577717
		unsigned int now = read_pmc(pmc);
Packit 577717
		state->pmc[i].sum += now - state->pmc[i].start;
Packit 577717
		state->pmc[i].start = now;
Packit 577717
	}
Packit 577717
	/* cache->k1.id is still == state->k1.id */
Packit 577717
}
Packit 577717
Packit 577717
static void xscale_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[4];
Packit 577717
Packit 577717
	cpu = smp_processor_id();
Packit 577717
	cache = __get_cpu_cache(cpu);
Packit 577717
	if (cache->k1.id == state->k1.id) {
Packit 577717
		cache->k1.id = 0; /* force reload of cleared EVNTSELs */
Packit 577717
		if (is_isuspend_cpu(state, cpu))
Packit 577717
			return; /* skip reload of PMCs */
Packit 577717
	}
Packit 577717
	/* XXX: the rest is still the PPC code */
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->cstatus;
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
Packit 577717
		pmc[state->pmc[i].map] = state->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->k1.id remains != state->k1.id */
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static void xscale_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->k1.id == state->k1.id)
Packit 577717
		return;
Packit 577717
	switch (pmu_type) {
Packit 577717
	case PMU_XSC1:
Packit 577717
		value = state->arm.xsc1.pmnc;
Packit 577717
		if (value != cache->arm.xsc1.pmnc) {
Packit 577717
			cache->arm.xsc1.pmnc = value;
Packit 577717
			xsc1_write_pmnc(value);
Packit 577717
		}
Packit 577717
		break;
Packit 577717
	case PMU_XSC2:
Packit 577717
		value = cache->arm.xsc2.pmnc;
Packit 577717
		if (value & 1) {
Packit 577717
			value &= ~1;
Packit 577717
			cache->arm.xsc2.pmnc = value;
Packit 577717
			xsc2_write_pmnc(value);
Packit 577717
		}
Packit 577717
		value = state->arm.xsc2.evtsel;
Packit 577717
		if (value != cache->arm.xsc2.evtsel) {
Packit 577717
			cache->arm.xsc2.evtsel = value;
Packit 577717
			xsc2_write_evtsel(value);
Packit 577717
		}
Packit 577717
		value = state->arm.xsc2.inten;
Packit 577717
		if (value != cache->arm.xsc2.inten) {
Packit 577717
			cache->arm.xsc2.inten = value;
Packit 577717
			xsc2_write_inten(value);
Packit 577717
		}
Packit 577717
		value = cache->arm.xsc2.pmnc;
Packit 577717
		value |= 1;
Packit 577717
		cache->arm.xsc2.pmnc = value;
Packit 577717
		xsc2_write_pmnc(value);
Packit 577717
	}
Packit 577717
	cache->k1.id = state->k1.id;
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 xscale_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 xscale_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 xscale_isuspend(state);
Packit 577717
}
Packit 577717
Packit 577717
static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	return xscale_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->ppc_mmcr[0] |= MMCR0_PMXE;
Packit 577717
#ifdef CONFIG_SMP
Packit 577717
	clear_isuspend_cpu(state);
Packit 577717
#else
Packit 577717
	get_cpu_cache()->k1.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
	/* XXX: XScale has an overflow status register */
Packit 577717
	/* XXX: XSC1 A stepping has an erratum making the
Packit 577717
	   overflow status bits unreliable */
Packit 577717
	/* XXX: use different procedures for XSC1 and XSC2 */
Packit 577717
Packit 577717
	/* XXX: the rest is still the X86 code */
Packit 577717
	unsigned int cstatus, nrctrs, pmc, pmc_mask;
Packit 577717
Packit 577717
	cstatus = state->cstatus;
Packit 577717
	pmc = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
Packit 577717
	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
Packit 577717
		if ((int)state->pmc[pmc].start >= 0) { /* XXX: ">" ? */
Packit 577717
			/* XXX: "+=" to correct for overshots */
Packit 577717
			state->pmc[pmc].start = state->control.ireset[pmc];
Packit 577717
			pmc_mask |= (1 << pmc);
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return pmc_mask;
Packit 577717
}
Packit 577717
Packit 577717
static inline int check_ireset(const struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int nrctrs, i;
Packit 577717
Packit 577717
	i = state->control.nractrs;
Packit 577717
	nrctrs = i + state->control.nrictrs;
Packit 577717
	for(; i < nrctrs; ++i)
Packit 577717
		if (state->control.ireset[i] >= 0)	/* XScale-specific */
Packit 577717
			return -EINVAL;
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	unsigned int cstatus, nrctrs, i;
Packit 577717
Packit 577717
	cstatus = state->cstatus;
Packit 577717
	nrctrs = perfctr_cstatus_nrctrs(cstatus);
Packit 577717
	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
Packit 577717
		state->pmc[i].start = state->control.ireset[i];
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(const struct perfctr_cpu_state *state) { return 0; }
Packit 577717
static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
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 xscale_check_control(state);
Packit 577717
}
Packit 577717
Packit 577717
int perfctr_cpu_update_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
Packit 577717
{
Packit 577717
	int err;
Packit 577717
Packit 577717
	clear_isuspend_cpu(state);
Packit 577717
	state->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.nrictrs)
Packit 577717
		return -EPERM;
Packit 577717
Packit 577717
	err = check_ireset(state);
Packit 577717
	if (err < 0)
Packit 577717
		return err;
Packit 577717
	err = check_control(state); /* may initialise state->cstatus */
Packit 577717
	if (err < 0)
Packit 577717
		return err;
Packit 577717
	state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on,
Packit 577717
					     state->control.nractrs,
Packit 577717
					     state->control.nrictrs);
Packit 577717
	setup_imode_start_values(state);
Packit 577717
	return 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
	if (perfctr_cstatus_has_ictrs(state->cstatus))
Packit 577717
		perfctr_cpu_isuspend(state);
Packit 577717
	perfctr_cpu_read_counters(state, &now;;
Packit 577717
	cstatus = state->cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
		state->tsc_sum += now.tsc - state->tsc_start;
Packit 577717
	nractrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nractrs; ++i)
Packit 577717
		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_resume(struct perfctr_cpu_state *state)
Packit 577717
{
Packit 577717
	if (perfctr_cstatus_has_ictrs(state->cstatus))
Packit 577717
	    perfctr_cpu_iresume(state);
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->cstatus;
Packit 577717
		if (perfctr_cstatus_has_tsc(cstatus))
Packit 577717
			state->tsc_start = now.tsc;
Packit 577717
		nrctrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
		for(i = 0; i < nrctrs; ++i)
Packit 577717
			state->pmc[i].start = now.pmc[i];
Packit 577717
	}
Packit 577717
	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
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
	perfctr_cpu_read_counters(state, &now;;
Packit 577717
	cstatus = state->cstatus;
Packit 577717
	if (perfctr_cstatus_has_tsc(cstatus)) {
Packit 577717
		state->tsc_sum += now.tsc - state->tsc_start;
Packit 577717
		state->tsc_start = now.tsc;
Packit 577717
	}
Packit 577717
	nractrs = perfctr_cstatus_nractrs(cstatus);
Packit 577717
	for(i = 0; i < nractrs; ++i) {
Packit 577717
		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
Packit 577717
		state->pmc[i].start = now.pmc[i];
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
/****************************************************************
Packit 577717
 *								*
Packit 577717
 * Processor detection and initialisation procedures.		*
Packit 577717
 *								*
Packit 577717
 ****************************************************************/
Packit 577717
Packit 577717
static int __init xscale_init(void)
Packit 577717
{
Packit 577717
	static char xsc1_name[] __initdata = "XScale1";
Packit 577717
	static char xsc2_name[] __initdata = "XScale2";
Packit 577717
	u32 id;
Packit 577717
Packit 577717
	//asm("mrc p15, 0, %0, c0, c0, 0" : "=r"(id));
Packit 577717
	id = read_cpuid(CPUID_ID);
Packit 577717
Packit 577717
	/* check for Intel/V5TE */
Packit 577717
	if ((id & 0xffff0000) != 0x69050000)
Packit 577717
		return -ENODEV;
Packit 577717
	/* check coregen for XSC1 or XSC2 */
Packit 577717
	switch ((id >> 13) & 0x7) {
Packit 577717
	case 0x1:
Packit 577717
		pmu_type = PMU_XSC1;
Packit 577717
		perfctr_info.cpu_type = PERFCTR_ARM_XSC1;
Packit 577717
		perfctr_cpu_name = xsc1_name;
Packit 577717
		break;
Packit 577717
	case 0x2:
Packit 577717
		pmu_type = PMU_XSC2;
Packit 577717
		perfctr_info.cpu_type = PERFCTR_ARM_XSC2;
Packit 577717
		perfctr_cpu_name = xsc2_name;
Packit 577717
		break;
Packit 577717
	default:
Packit 577717
		return -ENODEV;
Packit 577717
	}
Packit 577717
	perfctr_info.cpu_features = 0;
Packit 577717
	/* XXX: detect cpu_khz by sampling CCNT over mdelay()? */
Packit 577717
	return 0;
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->k1.id = -1;
Packit 577717
Packit 577717
	xscale_clear_counters();
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);
Packit 577717
	perfctr_cpu_set_ihandler(NULL);
Packit 577717
}
Packit 577717
Packit 577717
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
Packit 577717
static int reserve_pmu_irq(void)
Packit 577717
{
Packit 577717
	int ret;
Packit 577717
Packit 577717
	ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
Packit 577717
			  "XScale PMU", NULL);
Packit 577717
	if (ret < 0)
Packit 577717
		return ret;
Packit 577717
	/* fiddle pmnc PMU_ENABLE, PMU_CNT64 */
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
static void release_pmu_irq(void)
Packit 577717
{
Packit 577717
	write_pmnc(read_pmnc() & ~PMU_ENABLE);
Packit 577717
	free_irq(XSCALE_PMU_IRQ, NULL);
Packit 577717
}
Packit 577717
Packit 577717
#else
Packit 577717
static inline int reserve_pmu_irq(void) { return 0; }
Packit 577717
static inline void release_pmu_irq(void) { }
Packit 577717
#endif
Packit 577717
Packit 577717
static void do_init_tests(void)
Packit 577717
{
Packit 577717
#ifdef CONFIG_PERFCTR_INIT_TESTS
Packit 577717
	if (reserve_pmu_irq() >= 0) {
Packit 577717
		perfctr_xscale_init_tests();
Packit 577717
		release_pmu_irq();
Packit 577717
	}
Packit 577717
#endif
Packit 577717
}
Packit 577717
Packit 577717
int __init perfctr_cpu_init(void)
Packit 577717
{
Packit 577717
	int err;
Packit 577717
Packit 577717
	preempt_disable();
Packit 577717
Packit 577717
	err = xscale_init();
Packit 577717
	if (err)
Packit 577717
		goto out;
Packit 577717
Packit 577717
	do_init_tests();
Packit 577717
Packit 577717
	perfctr_info.cpu_khz = 266; /* XXX: perfctr_cpu_khz(); */
Packit 577717
	perfctr_info.tsc_to_cpu_mult = 1;
Packit 577717
 out:
Packit 577717
	preempt_enable();
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
	mutex_lock(&mutex);
Packit 577717
	ret = current_service;
Packit 577717
	if (ret)
Packit 577717
		goto out_unlock;
Packit 577717
	ret = "unknown driver (oprofile? ixp425_eth?)";
Packit 577717
	if (reserve_pmu_irq() < 0)
Packit 577717
		goto out_unlock;
Packit 577717
	current_service = service;
Packit 577717
	__module_get(THIS_MODULE);
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
		goto out_unlock;
Packit 577717
	}
Packit 577717
	/* power down the counters */
Packit 577717
	perfctr_cpu_reset();
Packit 577717
	current_service = 0;
Packit 577717
	release_pmu_irq();
Packit 577717
	module_put(THIS_MODULE);
Packit 577717
 out_unlock:
Packit 577717
	mutex_unlock(&mutex);
Packit 577717
}