Skip to content

Commit

Permalink
ARM: 5901/2: arm/oprofile: reserve the PMU when starting
Browse files Browse the repository at this point in the history
Make sure that we have access to the performance counters and
that they aren't being used by perf events or anything else.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Jean Pihet <jpihet@mvista.com>
Signed-off-by: Jamie Iles <jamie.iles@picochip.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Jamie Iles authored and Russell King committed Feb 12, 2010
1 parent 0f4f067 commit 1618fdd
Showing 7 changed files with 85 additions and 64 deletions.
4 changes: 2 additions & 2 deletions arch/arm/oprofile/op_model_arm11_core.c
Original file line number Diff line number Diff line change
@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
return IRQ_HANDLED;
}

int arm11_request_interrupts(int *irqs, int nr)
int arm11_request_interrupts(const int *irqs, int nr)
{
unsigned int i;
int ret = 0;
@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr)
return ret;
}

void arm11_release_interrupts(int *irqs, int nr)
void arm11_release_interrupts(const int *irqs, int nr)
{
unsigned int i;

4 changes: 2 additions & 2 deletions arch/arm/oprofile/op_model_arm11_core.h
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@
int arm11_setup_pmu(void);
int arm11_start_pmu(void);
int arm11_stop_pmu(void);
int arm11_request_interrupts(int *, int);
void arm11_release_interrupts(int *, int);
int arm11_request_interrupts(const int *, int);
void arm11_release_interrupts(const int *, int);

#endif
42 changes: 22 additions & 20 deletions arch/arm/oprofile/op_model_mpcore.c
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@
/* #define DEBUG */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
@@ -43,6 +44,7 @@
#include <mach/hardware.h>
#include <mach/board-eb.h>
#include <asm/system.h>
#include <asm/pmu.h>

#include "op_counter.h"
#include "op_arm_model.h"
@@ -58,6 +60,7 @@
* Bitmask of used SCU counters
*/
static unsigned int scu_em_used;
static const struct pmu_irqs *pmu_irqs;

/*
* 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
@@ -225,33 +228,40 @@ static int em_setup_ctrs(void)
return 0;
}

static int arm11_irqs[] = {
[0] = IRQ_EB11MP_PMU_CPU0,
[1] = IRQ_EB11MP_PMU_CPU1,
[2] = IRQ_EB11MP_PMU_CPU2,
[3] = IRQ_EB11MP_PMU_CPU3
};

static int em_start(void)
{
int ret;

ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
pmu_irqs = reserve_pmu();
if (IS_ERR(pmu_irqs)) {
ret = PTR_ERR(pmu_irqs);
goto out;
}

ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
if (ret == 0) {
em_call_function(arm11_start_pmu);

ret = scu_start();
if (ret)
arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
if (ret) {
arm11_release_interrupts(pmu_irqs->irqs,
pmu_irqs->num_irqs);
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}
}

out:
return ret;
}

static void em_stop(void)
{
em_call_function(arm11_stop_pmu);
arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
scu_stop();
release_pmu(pmu_irqs);
}

/*
@@ -283,15 +293,7 @@ static int em_setup(void)
em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);

/*
* Send CP15 PMU interrupts to the owner CPU.
*/
em_route_irq(IRQ_EB11MP_PMU_CPU0, 0);
em_route_irq(IRQ_EB11MP_PMU_CPU1, 1);
em_route_irq(IRQ_EB11MP_PMU_CPU2, 2);
em_route_irq(IRQ_EB11MP_PMU_CPU3, 3);

return 0;
return init_pmu();
}

struct op_arm_model_spec op_mpcore_spec = {
30 changes: 19 additions & 11 deletions arch/arm/oprofile/op_model_v6.c
Original file line number Diff line number Diff line change
@@ -19,39 +19,47 @@
/* #define DEBUG */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/pmu.h>

#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_arm11_core.h"

static int irqs[] = {
#ifdef CONFIG_ARCH_OMAP2
3,
#endif
#ifdef CONFIG_ARCH_BCMRING
IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */
#endif
};
static const struct pmu_irqs *pmu_irqs;

static void armv6_pmu_stop(void)
{
arm11_stop_pmu();
arm11_release_interrupts(irqs, ARRAY_SIZE(irqs));
arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}

static int armv6_pmu_start(void)
{
int ret;

ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs));
if (ret >= 0)
pmu_irqs = reserve_pmu();
if (IS_ERR(pmu_irqs)) {
ret = PTR_ERR(pmu_irqs);
goto out;
}

ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
if (ret >= 0) {
ret = arm11_start_pmu();
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}

out:
return ret;
}

30 changes: 19 additions & 11 deletions arch/arm/oprofile/op_model_v7.c
Original file line number Diff line number Diff line change
@@ -11,11 +11,14 @@
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/smp.h>

#include <asm/pmu.h>

#include "op_counter.h"
#include "op_arm_model.h"
#include "op_model_v7.h"
@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
return IRQ_HANDLED;
}

int armv7_request_interrupts(int *irqs, int nr)
int armv7_request_interrupts(const int *irqs, int nr)
{
unsigned int i;
int ret = 0;
@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr)
return ret;
}

void armv7_release_interrupts(int *irqs, int nr)
void armv7_release_interrupts(const int *irqs, int nr)
{
unsigned int i;

@@ -362,32 +365,37 @@ static void armv7_pmnc_dump_regs(void)
}
#endif


static int irqs[] = {
#ifdef CONFIG_ARCH_OMAP3
INT_34XX_BENCH_MPU_EMUL,
#endif
};
static const struct pmu_irqs *pmu_irqs;

static void armv7_pmnc_stop(void)
{
#ifdef DEBUG
armv7_pmnc_dump_regs();
#endif
armv7_stop_pmnc();
armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}

static int armv7_pmnc_start(void)
{
int ret;

pmu_irqs = reserve_pmu();
if (IS_ERR(pmu_irqs))
return PTR_ERR(pmu_irqs);

#ifdef DEBUG
armv7_pmnc_dump_regs();
#endif
ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
if (ret >= 0)
ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
if (ret >= 0) {
armv7_start_pmnc();
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}

return ret;
}
4 changes: 2 additions & 2 deletions arch/arm/oprofile/op_model_v7.h
Original file line number Diff line number Diff line change
@@ -97,7 +97,7 @@
int armv7_setup_pmu(void);
int armv7_start_pmu(void);
int armv7_stop_pmu(void);
int armv7_request_interrupts(int *, int);
void armv7_release_interrupts(int *, int);
int armv7_request_interrupts(const int *, int);
void armv7_release_interrupts(const int *, int);

#endif
35 changes: 19 additions & 16 deletions arch/arm/oprofile/op_model_xscale.c
Original file line number Diff line number Diff line change
@@ -17,12 +17,14 @@
/* #define DEBUG */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/irq.h>

#include <asm/cputype.h>
#include <asm/pmu.h>

#include "op_counter.h"
#include "op_arm_model.h"
@@ -33,17 +35,6 @@
#define PMU_RESET (CCNT_RESET | PMN_RESET)
#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */

/* TODO do runtime detection */
#ifdef CONFIG_ARCH_IOP32X
#define XSCALE_PMU_IRQ IRQ_IOP32X_CORE_PMU
#endif
#ifdef CONFIG_ARCH_IOP33X
#define XSCALE_PMU_IRQ IRQ_IOP33X_CORE_PMU
#endif
#ifdef CONFIG_ARCH_PXA
#define XSCALE_PMU_IRQ IRQ_PMU
#endif

/*
* Different types of events that can be counted by the XScale PMU
* as used by Oprofile userspace. Here primarily for documentation
@@ -367,27 +358,39 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
return IRQ_HANDLED;
}

static const struct pmu_irqs *pmu_irqs;

static void xscale_pmu_stop(void)
{
u32 pmnc = read_pmnc();

pmnc &= ~PMU_ENABLE;
write_pmnc(pmnc);

free_irq(XSCALE_PMU_IRQ, results);
free_irq(pmu_irqs->irqs[0], results);
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}

static int xscale_pmu_start(void)
{
int ret;
u32 pmnc = read_pmnc();
u32 pmnc;

pmu_irqs = reserve_pmu();
if (IS_ERR(pmu_irqs))
return PTR_ERR(pmu_irqs);

pmnc = read_pmnc();

ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
"XScale PMU", (void *)results);
ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt,
IRQF_DISABLED, "XScale PMU", (void *)results);

if (ret < 0) {
printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n",
XSCALE_PMU_IRQ);
pmu_irqs->irqs[0]);
release_pmu(pmu_irqs);
pmu_irqs = NULL;
return ret;
}

0 comments on commit 1618fdd

Please sign in to comment.