Commit 6c4fe420 authored by Kumar Gala's avatar Kumar Gala Committed by Linus Torvalds

[PATCH] ppc32: performance Monitor/Oprofile support for e500

Adds oprofile support for the e500 PowerPC core.
Signed-off-by: default avatarAndy Fleming <afleming@freescale.com>
Signed-off-by: default avatarKumar Gala <kumar.gala@freescale.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f481178e
...@@ -14,7 +14,7 @@ extra-y += vmlinux.lds ...@@ -14,7 +14,7 @@ extra-y += vmlinux.lds
obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
process.o signal.o ptrace.o align.o \ process.o signal.o ptrace.o align.o \
semaphore.o syscalls.o setup.o \ semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.o cputable.o ppc_htab.o perfmon.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
...@@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB) += ppc-stub.o ...@@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB) += ppc-stub.o
obj-$(CONFIG_SMP) += smp.o smp-tbsync.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o obj-$(CONFIG_TAU) += temp.o
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o
ifndef CONFIG_MATH_EMULATION ifndef CONFIG_MATH_EMULATION
obj-$(CONFIG_8xx) += softemu8xx.o obj-$(CONFIG_8xx) += softemu8xx.o
......
...@@ -643,7 +643,8 @@ interrupt_base: ...@@ -643,7 +643,8 @@ interrupt_base:
EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE) EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE)
/* Performance Monitor */ /* Performance Monitor */
EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE) EXCEPTION(0x2060, PerformanceMonitor, PerformanceMonitorException, EXC_XFER_STD)
/* Debug Interrupt */ /* Debug Interrupt */
DEBUG_EXCEPTION DEBUG_EXCEPTION
......
/* kernel/perfmon.c
* PPC 32 Performance Monitor Infrastructure
*
* Author: Andy Fleming
* Copyright (c) 2004 Freescale Semiconductor, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/prctl.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/reg.h>
#include <asm/xmon.h>
/* A lock to regulate grabbing the interrupt */
spinlock_t perfmon_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_FSL_BOOKE
static void dummy_perf(struct pt_regs *regs)
{
unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
pmgc0 &= ~PMGC0_PMIE;
mtpmr(PMRN_PMGC0, pmgc0);
}
#else
/* Ensure exceptions are disabled */
#define MMCR0_PMXE (1UL << (31 - 5))
static void dummy_perf(struct pt_regs *regs)
{
unsigned int mmcr0 = mfspr(SPRN_MMCR0);
mmcr0 &= ~MMCR0_PMXE;
mtspr(SPRN_MMCR0, mmcr0);
}
#endif
void (*perf_irq)(struct pt_regs *) = dummy_perf;
/* Grab the interrupt, if it's free.
* Returns 0 on success, -1 if the interrupt is taken already */
int request_perfmon_irq(void (*handler)(struct pt_regs *))
{
int err = 0;
spin_lock(&perfmon_lock);
if (perf_irq == dummy_perf)
perf_irq = handler;
else {
pr_info("perfmon irq already handled by %p\n", perf_irq);
err = -1;
}
spin_unlock(&perfmon_lock);
return err;
}
void free_perfmon_irq(void)
{
spin_lock(&perfmon_lock);
perf_irq = dummy_perf;
spin_unlock(&perfmon_lock);
}
EXPORT_SYMBOL(perf_irq);
EXPORT_SYMBOL(request_perfmon_irq);
EXPORT_SYMBOL(free_perfmon_irq);
/* kernel/perfmon_fsl_booke.c
* Freescale Book-E Performance Monitor code
*
* Author: Andy Fleming
* Copyright (c) 2004 Freescale Semiconductor, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/prctl.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/reg.h>
#include <asm/xmon.h>
void init_pmc_stop(int ctr);
void set_pmc_event(int ctr, int event);
void set_pmc_user_kernel(int ctr, int user, int kernel);
void set_pmc_marked(int ctr, int mark0, int mark1);
void pmc_start_ctr(int ctr, int enable);
void pmc_start_ctrs(int enable);
void pmc_stop_ctrs(void);
void dump_pmcs(void);
static inline u32 get_pmlca(int ctr);
static inline void set_pmlca(int ctr, u32 pmlca);
static inline u32 get_pmlca(int ctr)
{
u32 pmlca;
switch (ctr) {
case 0:
pmlca = mfpmr(PMRN_PMLCA0);
break;
case 1:
pmlca = mfpmr(PMRN_PMLCA1);
break;
case 2:
pmlca = mfpmr(PMRN_PMLCA2);
break;
case 3:
pmlca = mfpmr(PMRN_PMLCA3);
break;
default:
panic("Bad ctr number\n");
}
return pmlca;
}
static inline void set_pmlca(int ctr, u32 pmlca)
{
switch (ctr) {
case 0:
mtpmr(PMRN_PMLCA0, pmlca);
break;
case 1:
mtpmr(PMRN_PMLCA1, pmlca);
break;
case 2:
mtpmr(PMRN_PMLCA2, pmlca);
break;
case 3:
mtpmr(PMRN_PMLCA3, pmlca);
break;
default:
panic("Bad ctr number\n");
}
}
void init_pmc_stop(int ctr)
{
u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
PMLCA_FCM1 | PMLCA_FCM0);
u32 pmlcb = 0;
switch (ctr) {
case 0:
mtpmr(PMRN_PMLCA0, pmlca);
mtpmr(PMRN_PMLCB0, pmlcb);
break;
case 1:
mtpmr(PMRN_PMLCA1, pmlca);
mtpmr(PMRN_PMLCB1, pmlcb);
break;
case 2:
mtpmr(PMRN_PMLCA2, pmlca);
mtpmr(PMRN_PMLCB2, pmlcb);
break;
case 3:
mtpmr(PMRN_PMLCA3, pmlca);
mtpmr(PMRN_PMLCB3, pmlcb);
break;
default:
panic("Bad ctr number!\n");
}
}
void set_pmc_event(int ctr, int event)
{
u32 pmlca;
pmlca = get_pmlca(ctr);
pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
((event << PMLCA_EVENT_SHIFT) &
PMLCA_EVENT_MASK);
set_pmlca(ctr, pmlca);
}
void set_pmc_user_kernel(int ctr, int user, int kernel)
{
u32 pmlca;
pmlca = get_pmlca(ctr);
if(user)
pmlca &= ~PMLCA_FCU;
else
pmlca |= PMLCA_FCU;
if(kernel)
pmlca &= ~PMLCA_FCS;
else
pmlca |= PMLCA_FCS;
set_pmlca(ctr, pmlca);
}
void set_pmc_marked(int ctr, int mark0, int mark1)
{
u32 pmlca = get_pmlca(ctr);
if(mark0)
pmlca &= ~PMLCA_FCM0;
else
pmlca |= PMLCA_FCM0;
if(mark1)
pmlca &= ~PMLCA_FCM1;
else
pmlca |= PMLCA_FCM1;
set_pmlca(ctr, pmlca);
}
void pmc_start_ctr(int ctr, int enable)
{
u32 pmlca = get_pmlca(ctr);
pmlca &= ~PMLCA_FC;
if (enable)
pmlca |= PMLCA_CE;
else
pmlca &= ~PMLCA_CE;
set_pmlca(ctr, pmlca);
}
void pmc_start_ctrs(int enable)
{
u32 pmgc0 = mfpmr(PMRN_PMGC0);
pmgc0 &= ~PMGC0_FAC;
pmgc0 |= PMGC0_FCECE;
if (enable)
pmgc0 |= PMGC0_PMIE;
else
pmgc0 &= ~PMGC0_PMIE;
mtpmr(PMRN_PMGC0, pmgc0);
}
void pmc_stop_ctrs(void)
{
u32 pmgc0 = mfpmr(PMRN_PMGC0);
pmgc0 |= PMGC0_FAC;
pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
mtpmr(PMRN_PMGC0, pmgc0);
}
void dump_pmcs(void)
{
printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0));
printk("pmc\t\tpmlca\t\tpmlcb\n");
printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0),
mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0));
printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1),
mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1));
printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2),
mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2));
printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3),
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
}
EXPORT_SYMBOL(init_pmc_stop);
EXPORT_SYMBOL(set_pmc_event);
EXPORT_SYMBOL(set_pmc_user_kernel);
EXPORT_SYMBOL(set_pmc_marked);
EXPORT_SYMBOL(pmc_start_ctr);
EXPORT_SYMBOL(pmc_start_ctrs);
EXPORT_SYMBOL(pmc_stop_ctrs);
EXPORT_SYMBOL(dump_pmcs);
...@@ -71,6 +71,7 @@ void (*debugger_fault_handler)(struct pt_regs *regs); ...@@ -71,6 +71,7 @@ void (*debugger_fault_handler)(struct pt_regs *regs);
* Trap & Exception support * Trap & Exception support
*/ */
extern void (*perf_irq)(struct pt_regs *);
spinlock_t die_lock = SPIN_LOCK_UNLOCKED; spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
...@@ -726,6 +727,11 @@ void AltivecAssistException(struct pt_regs *regs) ...@@ -726,6 +727,11 @@ void AltivecAssistException(struct pt_regs *regs)
} }
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
void PerformanceMonitorException(struct pt_regs *regs)
{
perf_irq(regs);
}
#ifdef CONFIG_FSL_BOOKE #ifdef CONFIG_FSL_BOOKE
void CacheLockingException(struct pt_regs *regs, unsigned long address, void CacheLockingException(struct pt_regs *regs, unsigned long address,
unsigned long error_code) unsigned long error_code)
......
...@@ -6,4 +6,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ ...@@ -6,4 +6,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o \ oprofilefs.o oprofile_stats.o \
timer_int.o ) timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.o oprofile-y := $(DRIVER_OBJS) common.o op_model_fsl_booke.o
/*
* PPC 32 oprofile support
* Based on PPC64 oprofile support
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
*
* Copyright (C) Freescale Semiconductor, Inc 2004
*
* Author: Andy Fleming
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/oprofile.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/errno.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/perfmon.h>
#include <asm/cputable.h>
#include "op_impl.h"
extern struct op_ppc32_model op_model_fsl_booke;
static struct op_ppc32_model *model;
static struct op_counter_config ctr[OP_MAX_COUNTER];
static struct op_system_config sys;
static void op_handle_interrupt(struct pt_regs *regs)
{
model->handle_interrupt(regs, ctr);
}
static int op_ppc32_setup(void)
{
/* Install our interrupt handler into the existing hook. */
if(request_perfmon_irq(&op_handle_interrupt))
return -EBUSY;
mb();
/* Pre-compute the values to stuff in the hardware registers. */
model->reg_setup(ctr, &sys, model->num_counters);
#if 0
/* FIXME: Make multi-cpu work */
/* Configure the registers on all cpus. */
on_each_cpu(model->reg_setup, NULL, 0, 1);
#endif
return 0;
}
static void op_ppc32_shutdown(void)
{
mb();
/* Remove our interrupt handler. We may be removing this module. */
free_perfmon_irq();
}
static void op_ppc32_cpu_start(void *dummy)
{
model->start(ctr);
}
static int op_ppc32_start(void)
{
on_each_cpu(op_ppc32_cpu_start, NULL, 0, 1);
return 0;
}
static inline void op_ppc32_cpu_stop(void *dummy)
{
model->stop();
}
static void op_ppc32_stop(void)
{
on_each_cpu(op_ppc32_cpu_stop, NULL, 0, 1);
}
static int op_ppc32_create_files(struct super_block *sb, struct dentry *root)
{
int i;
for (i = 0; i < model->num_counters; ++i) {
struct dentry *dir;
char buf[3];
snprintf(buf, sizeof buf, "%d", i);
dir = oprofilefs_mkdir(sb, root, buf);
oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
/* FIXME: Not sure if this is used */
oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
}
oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
/* Default to tracing both kernel and user */
sys.enable_kernel = 1;
sys.enable_user = 1;
return 0;
}
static struct oprofile_operations oprof_ppc32_ops = {
.create_files = op_ppc32_create_files,
.setup = op_ppc32_setup,
.shutdown = op_ppc32_shutdown,
.start = op_ppc32_start,
.stop = op_ppc32_stop,
.cpu_type = NULL /* To be filled in below. */
};
int __init oprofile_arch_init(struct oprofile_operations **ops)
{
char *name;
int cpu_id = smp_processor_id();
#ifdef CONFIG_FSL_BOOKE
model = &op_model_fsl_booke;
#else
printk(KERN_ERR "oprofile enabled on unsupported processor!\n");
return -ENODEV;
#endif
name = kmalloc(32, GFP_KERNEL);
if (NULL == name)
return -ENOMEM;
sprintf(name, "ppc/%s", cur_cpu_spec[cpu_id]->cpu_name);
oprof_ppc32_ops.cpu_type = name;
model->num_counters = cur_cpu_spec[cpu_id]->num_pmcs;
*ops = &oprof_ppc32_ops;
printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
oprof_ppc32_ops.cpu_type);
return 0;
}
void oprofile_arch_exit(void)
{
kfree(oprof_ppc32_ops.cpu_type);
oprof_ppc32_ops.cpu_type = NULL;
}
/**
* @file init.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/errno.h>
int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
return -ENODEV;
}
void oprofile_arch_exit(void)
{
}
/*
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
*
* Based on alpha version.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
#define OP_MAX_COUNTER 8
/* Per-counter configuration as set via oprofilefs. */
struct op_counter_config {
unsigned long enabled;
unsigned long event;
unsigned long count;
unsigned long kernel;
unsigned long user;
unsigned long unit_mask;
};
/* System-wide configuration as set via oprofilefs. */
struct op_system_config {
unsigned long enable_kernel;
unsigned long enable_user;
};
/* Per-arch configuration */
struct op_ppc32_model {
void (*reg_setup) (struct op_counter_config *,
struct op_system_config *,
int num_counters);
void (*start) (struct op_counter_config *);
void (*stop) (void);
void (*handle_interrupt) (struct pt_regs *,
struct op_counter_config *);
int num_counters;
};
#endif /* OP_IMPL_H */
/*
* oprofile/op_model_e500.c
*
* Freescale Book-E oprofile support, based on ppc64 oprofile support
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
*
* Copyright (c) 2004 Freescale Semiconductor, Inc
*
* Author: Andy Fleming
* Maintainer: Kumar Gala <Kumar.Gala@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/cputable.h>
#include <asm/reg_booke.h>
#include <asm/page.h>
#include <asm/perfmon.h>
#include "op_impl.h"
static unsigned long reset_value[OP_MAX_COUNTER];
static int num_counters;
static int oprofile_running;
static inline unsigned int ctr_read(unsigned int i)
{
switch(i) {
case 0:
return mfpmr(PMRN_PMC0);
case 1:
return mfpmr(PMRN_PMC1);
case 2:
return mfpmr(PMRN_PMC2);
case 3:
return mfpmr(PMRN_PMC3);
default:
return 0;
}
}
static inline void ctr_write(unsigned int i, unsigned int val)
{
switch(i) {
case 0:
mtpmr(PMRN_PMC0, val);
break;
case 1:
mtpmr(PMRN_PMC1, val);
break;
case 2:
mtpmr(PMRN_PMC2, val);
break;
case 3:
mtpmr(PMRN_PMC3, val);
break;
default:
break;
}
}
static void fsl_booke_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
int i;
num_counters = num_ctrs;
/* freeze all counters */
pmc_stop_ctrs();
/* Our counters count up, and "count" refers to
* how much before the next interrupt, and we interrupt
* on overflow. So we calculate the starting value
* which will give us "count" until overflow.
* Then we set the events on the enabled counters */
for (i = 0; i < num_counters; ++i) {
reset_value[i] = 0x80000000UL - ctr[i].count;
init_pmc_stop(i);
set_pmc_event(i, ctr[i].event);
set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
}
}
static void fsl_booke_start(struct op_counter_config *ctr)
{
int i;
mtmsr(mfmsr() | MSR_PMM);
for (i = 0; i < num_counters; ++i) {
if (ctr[i].enabled) {
ctr_write(i, reset_value[i]);
/* Set Each enabled counterd to only
* count when the Mark bit is not set */
set_pmc_marked(i, 1, 0);
pmc_start_ctr(i, 1);
} else {
ctr_write(i, 0);
/* Set the ctr to be stopped */
pmc_start_ctr(i, 0);
}
}
/* Clear the freeze bit, and enable the interrupt.
* The counters won't actually start until the rfi clears
* the PMM bit */
pmc_start_ctrs(1);
oprofile_running = 1;
pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
mfpmr(PMRN_PMGC0));
}
static void fsl_booke_stop(void)
{
/* freeze counters */
pmc_stop_ctrs();
oprofile_running = 0;
pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
mfpmr(PMRN_PMGC0));
mb();
}
static void fsl_booke_handle_interrupt(struct pt_regs *regs,
struct op_counter_config *ctr)
{
unsigned long pc;
int is_kernel;
int val;
int i;
unsigned int cpu = smp_processor_id();
/* set the PMM bit (see comment below) */
mtmsr(mfmsr() | MSR_PMM);
pc = regs->nip;
is_kernel = (pc >= KERNELBASE);
for (i = 0; i < num_counters; ++i) {
val = ctr_read(i);
if (val < 0) {
if (oprofile_running && ctr[i].enabled) {
oprofile_add_sample(pc, is_kernel, i, cpu);
ctr_write(i, reset_value[i]);
} else {
ctr_write(i, 0);
}
}
}
/* The freeze bit was set by the interrupt. */
/* Clear the freeze bit, and reenable the interrupt.
* The counters won't actually start until the rfi clears
* the PMM bit */
pmc_start_ctrs(1);
}
struct op_ppc32_model op_model_fsl_booke = {
.reg_setup = fsl_booke_reg_setup,
.start = fsl_booke_start,
.stop = fsl_booke_stop,
.handle_interrupt = fsl_booke_handle_interrupt,
};
#ifndef __PERFMON_H
#define __PERFMON_H
int request_perfmon_irq(void (*handler)(struct pt_regs *));
void free_perfmon_irq(void);
#ifdef CONFIG_FSL_BOOKE
void init_pmc_stop(int ctr);
void set_pmc_event(int ctr, int event);
void set_pmc_user_kernel(int ctr, int user, int kernel);
void set_pmc_marked(int ctr, int mark0, int mark1);
void pmc_start_ctr(int ctr, int enable);
void pmc_start_ctrs(int enable);
void pmc_stop_ctrs(void);
void dump_pmcs(void);
#endif
#endif /* __PERFMON_H */
...@@ -51,6 +51,59 @@ do { \ ...@@ -51,6 +51,59 @@ do { \
#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v)) #define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
/* Freescale Book E Performance Monitor APU Registers */
#define PMRN_PMC0 0x010 /* Performance Monitor Counter 0 */
#define PMRN_PMC1 0x011 /* Performance Monitor Counter 1 */
#define PMRN_PMC2 0x012 /* Performance Monitor Counter 1 */
#define PMRN_PMC3 0x013 /* Performance Monitor Counter 1 */
#define PMRN_PMLCA0 0x090 /* PM Local Control A0 */
#define PMRN_PMLCA1 0x091 /* PM Local Control A1 */
#define PMRN_PMLCA2 0x092 /* PM Local Control A2 */
#define PMRN_PMLCA3 0x093 /* PM Local Control A3 */
#define PMLCA_FC 0x80000000 /* Freeze Counter */
#define PMLCA_FCS 0x40000000 /* Freeze in Supervisor */
#define PMLCA_FCU 0x20000000 /* Freeze in User */
#define PMLCA_FCM1 0x10000000 /* Freeze when PMM==1 */
#define PMLCA_FCM0 0x08000000 /* Freeze when PMM==0 */
#define PMLCA_CE 0x04000000 /* Condition Enable */
#define PMLCA_EVENT_MASK 0x007f0000 /* Event field */
#define PMLCA_EVENT_SHIFT 16
#define PMRN_PMLCB0 0x110 /* PM Local Control B0 */
#define PMRN_PMLCB1 0x111 /* PM Local Control B1 */
#define PMRN_PMLCB2 0x112 /* PM Local Control B2 */
#define PMRN_PMLCB3 0x113 /* PM Local Control B3 */
#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshhold Multiple Field */
#define PMLCB_THRESHMUL_SHIFT 8
#define PMLCB_THRESHOLD_MASK 0x003f /* Threshold Field */
#define PMLCB_THRESHOLD_SHIFT 0
#define PMRN_PMGC0 0x190 /* PM Global Control 0 */
#define PMGC0_FAC 0x80000000 /* Freeze all Counters */
#define PMGC0_PMIE 0x40000000 /* Interrupt Enable */
#define PMGC0_FCECE 0x20000000 /* Freeze countes on
Enabled Condition or
Event */
#define PMRN_UPMC0 0x000 /* User Performance Monitor Counter 0 */
#define PMRN_UPMC1 0x001 /* User Performance Monitor Counter 1 */
#define PMRN_UPMC2 0x002 /* User Performance Monitor Counter 1 */
#define PMRN_UPMC3 0x003 /* User Performance Monitor Counter 1 */
#define PMRN_UPMLCA0 0x080 /* User PM Local Control A0 */
#define PMRN_UPMLCA1 0x081 /* User PM Local Control A1 */
#define PMRN_UPMLCA2 0x082 /* User PM Local Control A2 */
#define PMRN_UPMLCA3 0x083 /* User PM Local Control A3 */
#define PMRN_UPMLCB0 0x100 /* User PM Local Control B0 */
#define PMRN_UPMLCB1 0x101 /* User PM Local Control B1 */
#define PMRN_UPMLCB2 0x102 /* User PM Local Control B2 */
#define PMRN_UPMLCB3 0x103 /* User PM Local Control B3 */
#define PMRN_UPMGC0 0x180 /* User PM Global Control 0 */
/* Machine State Register (MSR) Fields */ /* Machine State Register (MSR) Fields */
#define MSR_UCLE (1<<26) /* User-mode cache lock enable */ #define MSR_UCLE (1<<26) /* User-mode cache lock enable */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment