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

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
...@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg) ...@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int arm11_request_interrupts(int *irqs, int nr) int arm11_request_interrupts(const int *irqs, int nr)
{ {
unsigned int i; unsigned int i;
int ret = 0; int ret = 0;
...@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr) ...@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr)
return ret; return ret;
} }
void arm11_release_interrupts(int *irqs, int nr) void arm11_release_interrupts(const int *irqs, int nr)
{ {
unsigned int i; unsigned int i;
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
int arm11_setup_pmu(void); int arm11_setup_pmu(void);
int arm11_start_pmu(void); int arm11_start_pmu(void);
int arm11_stop_pmu(void); int arm11_stop_pmu(void);
int arm11_request_interrupts(int *, int); int arm11_request_interrupts(const int *, int);
void arm11_release_interrupts(int *, int); void arm11_release_interrupts(const int *, int);
#endif #endif
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
/* #define DEBUG */ /* #define DEBUG */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -43,6 +44,7 @@ ...@@ -43,6 +44,7 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/board-eb.h> #include <mach/board-eb.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/pmu.h>
#include "op_counter.h" #include "op_counter.h"
#include "op_arm_model.h" #include "op_arm_model.h"
...@@ -58,6 +60,7 @@ ...@@ -58,6 +60,7 @@
* Bitmask of used SCU counters * Bitmask of used SCU counters
*/ */
static unsigned int scu_em_used; 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) * 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) ...@@ -225,33 +228,40 @@ static int em_setup_ctrs(void)
return 0; 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) static int em_start(void)
{ {
int ret; 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) { if (ret == 0) {
em_call_function(arm11_start_pmu); em_call_function(arm11_start_pmu);
ret = scu_start(); ret = scu_start();
if (ret) if (ret) {
arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); arm11_release_interrupts(pmu_irqs->irqs,
pmu_irqs->num_irqs);
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
} }
}
out:
return ret; return ret;
} }
static void em_stop(void) static void em_stop(void)
{ {
em_call_function(arm11_stop_pmu); 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(); scu_stop();
release_pmu(pmu_irqs);
} }
/* /*
...@@ -283,15 +293,7 @@ static int em_setup(void) ...@@ -283,15 +293,7 @@ static int em_setup(void)
em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);
/* return init_pmu();
* 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;
} }
struct op_arm_model_spec op_mpcore_spec = { struct op_arm_model_spec op_mpcore_spec = {
......
...@@ -19,39 +19,47 @@ ...@@ -19,39 +19,47 @@
/* #define DEBUG */ /* #define DEBUG */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/pmu.h>
#include "op_counter.h" #include "op_counter.h"
#include "op_arm_model.h" #include "op_arm_model.h"
#include "op_model_arm11_core.h" #include "op_model_arm11_core.h"
static int irqs[] = { static const struct pmu_irqs *pmu_irqs;
#ifdef CONFIG_ARCH_OMAP2
3,
#endif
#ifdef CONFIG_ARCH_BCMRING
IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */
#endif
};
static void armv6_pmu_stop(void) static void armv6_pmu_stop(void)
{ {
arm11_stop_pmu(); 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) static int armv6_pmu_start(void)
{ {
int ret; int ret;
ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs)); pmu_irqs = reserve_pmu();
if (ret >= 0) 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(); ret = arm11_start_pmu();
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}
out:
return ret; return ret;
} }
......
...@@ -11,11 +11,14 @@ ...@@ -11,11 +11,14 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/pmu.h>
#include "op_counter.h" #include "op_counter.h"
#include "op_arm_model.h" #include "op_arm_model.h"
#include "op_model_v7.h" #include "op_model_v7.h"
...@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg) ...@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int armv7_request_interrupts(int *irqs, int nr) int armv7_request_interrupts(const int *irqs, int nr)
{ {
unsigned int i; unsigned int i;
int ret = 0; int ret = 0;
...@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr) ...@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr)
return ret; return ret;
} }
void armv7_release_interrupts(int *irqs, int nr) void armv7_release_interrupts(const int *irqs, int nr)
{ {
unsigned int i; unsigned int i;
...@@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void) ...@@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void)
} }
#endif #endif
static const struct pmu_irqs *pmu_irqs;
static int irqs[] = {
#ifdef CONFIG_ARCH_OMAP3
INT_34XX_BENCH_MPU_EMUL,
#endif
};
static void armv7_pmnc_stop(void) static void armv7_pmnc_stop(void)
{ {
...@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void) ...@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void)
armv7_pmnc_dump_regs(); armv7_pmnc_dump_regs();
#endif #endif
armv7_stop_pmnc(); 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) static int armv7_pmnc_start(void)
{ {
int ret; int ret;
pmu_irqs = reserve_pmu();
if (IS_ERR(pmu_irqs))
return PTR_ERR(pmu_irqs);
#ifdef DEBUG #ifdef DEBUG
armv7_pmnc_dump_regs(); armv7_pmnc_dump_regs();
#endif #endif
ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs)); ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
if (ret >= 0) if (ret >= 0) {
armv7_start_pmnc(); armv7_start_pmnc();
} else {
release_pmu(pmu_irqs);
pmu_irqs = NULL;
}
return ret; return ret;
} }
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
int armv7_setup_pmu(void); int armv7_setup_pmu(void);
int armv7_start_pmu(void); int armv7_start_pmu(void);
int armv7_stop_pmu(void); int armv7_stop_pmu(void);
int armv7_request_interrupts(int *, int); int armv7_request_interrupts(const int *, int);
void armv7_release_interrupts(int *, int); void armv7_release_interrupts(const int *, int);
#endif #endif
...@@ -17,12 +17,14 @@ ...@@ -17,12 +17,14 @@
/* #define DEBUG */ /* #define DEBUG */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/pmu.h>
#include "op_counter.h" #include "op_counter.h"
#include "op_arm_model.h" #include "op_arm_model.h"
...@@ -33,17 +35,6 @@ ...@@ -33,17 +35,6 @@
#define PMU_RESET (CCNT_RESET | PMN_RESET) #define PMU_RESET (CCNT_RESET | PMN_RESET)
#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */ #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 * Different types of events that can be counted by the XScale PMU
* as used by Oprofile userspace. Here primarily for documentation * as used by Oprofile userspace. Here primarily for documentation
...@@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg) ...@@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static const struct pmu_irqs *pmu_irqs;
static void xscale_pmu_stop(void) static void xscale_pmu_stop(void)
{ {
u32 pmnc = read_pmnc(); u32 pmnc = read_pmnc();
...@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void) ...@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void)
pmnc &= ~PMU_ENABLE; pmnc &= ~PMU_ENABLE;
write_pmnc(pmnc); 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) static int xscale_pmu_start(void)
{ {
int ret; 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, ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt,
"XScale PMU", (void *)results); IRQF_DISABLED, "XScale PMU", (void *)results);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n", 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; return ret;
} }
......
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