summaryrefslogtreecommitdiffstats
path: root/arch/arm/oprofile
diff options
context:
space:
mode:
authorJamie Iles <jamie.iles@picochip.com>2010-02-02 20:24:07 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-02-12 17:23:43 +0000
commit1618fdd9602c689de2f820a88cb3e283a39c3d90 (patch)
treebe2cec6548d61dc83b7fc538fa929533f9cb9112 /arch/arm/oprofile
parent0f4f0672ac950c96cffaf84a666d35e817d7c3ca (diff)
downloadlinux-1618fdd9602c689de2f820a88cb3e283a39c3d90.tar.gz
linux-1618fdd9602c689de2f820a88cb3e283a39c3d90.tar.bz2
linux-1618fdd9602c689de2f820a88cb3e283a39c3d90.zip
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: Jamie Iles <jamie.iles@picochip.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/oprofile')
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.c4
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.h4
-rw-r--r--arch/arm/oprofile/op_model_mpcore.c42
-rw-r--r--arch/arm/oprofile/op_model_v6.c30
-rw-r--r--arch/arm/oprofile/op_model_v7.c30
-rw-r--r--arch/arm/oprofile/op_model_v7.h4
-rw-r--r--arch/arm/oprofile/op_model_xscale.c35
7 files changed, 85 insertions, 64 deletions
diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c
index ad80752cb9fb..ef3e2653b90c 100644
--- a/arch/arm/oprofile/op_model_arm11_core.c
+++ b/arch/arm/oprofile/op_model_arm11_core.c
@@ -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;
diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h
index 6f8538e5a960..1902b99d9dfd 100644
--- a/arch/arm/oprofile/op_model_arm11_core.h
+++ b/arch/arm/oprofile/op_model_arm11_core.h
@@ -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
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c
index 4ce0f9801e2e..f73ce875a395 100644
--- a/arch/arm/oprofile/op_model_mpcore.c
+++ b/arch/arm/oprofile/op_model_mpcore.c
@@ -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 = {
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
index f7d2ec5ee9a1..a22357a2fd08 100644
--- a/arch/arm/oprofile/op_model_v6.c
+++ b/arch/arm/oprofile/op_model_v6.c
@@ -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;
}
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
index 2088a6c0cc0e..8642d0891ae1 100644
--- a/arch/arm/oprofile/op_model_v7.c
+++ b/arch/arm/oprofile/op_model_v7.c
@@ -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;
}
diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
index 0e19bcc2e100..9ca334b39c75 100644
--- a/arch/arm/oprofile/op_model_v7.h
+++ b/arch/arm/oprofile/op_model_v7.h
@@ -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
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
index 724ab9ce2526..1d34a02048bd 100644
--- a/arch/arm/oprofile/op_model_xscale.c
+++ b/arch/arm/oprofile/op_model_xscale.c
@@ -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,6 +358,8 @@ 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();
@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void)
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;
}