]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
ARM: 5901/2: arm/oprofile: reserve the PMU when starting
authorJamie Iles <jamie.iles@picochip.com>
Tue, 2 Feb 2010 19:24:07 +0000 (20:24 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 12 Feb 2010 17:23:43 +0000 (17:23 +0000)
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>
arch/arm/oprofile/op_model_arm11_core.c
arch/arm/oprofile/op_model_arm11_core.h
arch/arm/oprofile/op_model_mpcore.c
arch/arm/oprofile/op_model_v6.c
arch/arm/oprofile/op_model_v7.c
arch/arm/oprofile/op_model_v7.h
arch/arm/oprofile/op_model_xscale.c

index ad80752cb9fb2d721479904fd58a7b94950ca142..ef3e2653b90ceb1966bb64e1bb14ad087c966895 100644 (file)
@@ -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;
 
index 6f8538e5a96078a05d0a751e8cbf61ad78e4ceb6..1902b99d9dfdd23b67e98915864c602c0892bf4e 100644 (file)
@@ -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
index 4ce0f9801e2ef2c5ea9d92e29ec1c680b8335aec..f73ce875a395012c7f7b9500a5af1abbecafc438 100644 (file)
@@ -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 = {
index f7d2ec5ee9a1282be6f6089625b97906fbe9df0d..a22357a2fd08270ce4f369443ec966b1f317ee6c 100644 (file)
 /* #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;
 }
 
index 2088a6c0cc0e36f3e8ba23239f1a62fbb80e4858..8642d0891ae15eac8f2de05e6b02a381ba7cf131 100644 (file)
  */
 #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;
 }
index 0e19bcc2e1007eb75beb929ab0adc9a920be195d..9ca334b39c75f8fd76b4b365445ef03c24c0127b 100644 (file)
@@ -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
index 724ab9ce252674ff02d0e319cc25cd2a7b22da01..1d34a02048bd3a8da91ef1c350dc9656fcbedbd9 100644 (file)
 /* #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"
 #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;
        }