mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
0f4f0672ac
commit
1618fdd960
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,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)
|
||||
ret = arm11_start_pmu();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
|
||||
"XScale PMU", (void *)results);
|
||||
pmu_irqs = reserve_pmu();
|
||||
if (IS_ERR(pmu_irqs))
|
||||
return PTR_ERR(pmu_irqs);
|
||||
|
||||
pmnc = read_pmnc();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue