[PATCH 2/5] arm/oprofile: reserve the PMU when starting

Jean Pihet jpihet at mvista.com
Mon Dec 14 11:01:45 EST 2009


Hi,

On Mon, 2009-12-14 at 14:04 +0000, Jamie Iles wrote:
> 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 at arm.com>
> Signed-off-by: Jamie Iles <jamie.iles at picochip.com>
> ---
>  arch/arm/oprofile/op_model_arm11_core.c |    4 +-
>  arch/arm/oprofile/op_model_arm11_core.h |    4 +-
>  arch/arm/oprofile/op_model_mpcore.c     |   42 ++++++++++++++++--------------
>  arch/arm/oprofile/op_model_v6.c         |   33 ++++++++++++++----------
>  arch/arm/oprofile/op_model_v7.c         |   30 ++++++++++++++--------
>  arch/arm/oprofile/op_model_v7.h         |    4 +-
I am OK with the changes for ARMv7.

Regards,
Jean

>  arch/arm/oprofile/op_model_xscale.c     |   35 ++++++++++++++-----------
>  7 files changed, 85 insertions(+), 67 deletions(-)
> 
> diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c
> index ad80752..ef3e265 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 6f8538e..1902b99 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 4ce0f98..f73ce87 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 e468017..a22357a 100644
> --- a/arch/arm/oprofile/op_model_v6.c
> +++ b/arch/arm/oprofile/op_model_v6.c
> @@ -19,42 +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
> -#ifdef CONFIG_ARCH_PC3XX
> -        IRQ_NPMUIRQ,
> -#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 f20295f..9258fca 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"
> @@ -299,7 +302,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;
> @@ -322,7 +325,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;
>  
> @@ -366,12 +369,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)
>  {
> @@ -379,19 +377,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 0e19bcc..9ca334b 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 724ab9c..1d34a02 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;
>  	}
>  





More information about the linux-arm-kernel mailing list