Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1618fdd9 authored by Jamie Iles's avatar Jamie Iles Committed by Russell King
Browse files

ARM: 5901/2: arm/oprofile: reserve the PMU when starting



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: default avatarJamie Iles <jamie.iles@picochip.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 0f4f0672
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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;

+2 −2
Original line number Diff line number Diff line
@@ -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
+22 −20
Original line number Diff line number Diff line
@@ -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 = {
+19 −11
Original line number Diff line number Diff line
@@ -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;
}

+19 −11
Original line number Diff line number Diff line
@@ -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,12 +365,7 @@ 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)
{
@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void)
	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;
}
Loading