fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / arm / oprofile / op_model_xscale.c
index 284874b..7c3289c 100644 (file)
@@ -7,7 +7,7 @@
  * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
  * @remark Copyright 2004 Intel Corporation
  * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
- * @remark Copyright 2004 Oprofile Authors
+ * @remark Copyright 2004 OProfile Authors
  *
  * @remark Read the file COPYING
  *
@@ -20,7 +20,8 @@
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
+
 #include <asm/system.h>
 
 #include "op_counter.h"
 #define PMN_RESET      0x002   /* Reset event counters */
 #define        CCNT_RESET      0x004   /* Reset clock counter */
 #define        PMU_RESET       (CCNT_RESET | PMN_RESET)
+#define PMU_CNT64      0x008   /* Make CCNT count every 64th cycle */
 
 /* TODO do runtime detection */
-#ifdef CONFIG_ARCH_IOP310
-#define XSCALE_PMU_IRQ  IRQ_XS80200_PMU
+#ifdef CONFIG_ARCH_IOP32X
+#define XSCALE_PMU_IRQ  IRQ_IOP32X_CORE_PMU
 #endif
-#ifdef CONFIG_ARCH_IOP321
-#define XSCALE_PMU_IRQ  IRQ_IOP321_CORE_PMU
+#ifdef CONFIG_ARCH_IOP33X
+#define XSCALE_PMU_IRQ  IRQ_IOP33X_CORE_PMU
 #endif
-#ifdef CONFIG_ARCH_IOP331
-#define XSCALE_PMU_IRQ  IRQ_IOP331_CORE_PMU
+#ifdef CONFIG_ARCH_PXA
+#define XSCALE_PMU_IRQ  IRQ_PMU
 #endif
 
 /*
@@ -84,7 +86,7 @@ static struct pmu_counter results[MAX_COUNTERS];
 /*
  * There are two versions of the PMU in current XScale processors
  * with differing register layouts and number of performance counters.
- * e.g. IOP321 is xsc1 whilst IOP331 is xsc2.
+ * e.g. IOP32x is xsc1 whilst IOP33x is xsc2.
  * We detect which register layout to use in xscale_detect_pmu()
  */
 enum { PMU_XSC1, PMU_XSC2 };
@@ -125,12 +127,15 @@ static struct pmu_type *pmu;
 
 static void write_pmnc(u32 val)
 {
-       /* upper 4bits and 7, 11 are write-as-0 */
-       val &= 0xffff77f;
-       if (pmu->id == PMU_XSC1)
+       if (pmu->id == PMU_XSC1) {
+               /* upper 4bits and 7, 11 are write-as-0 */
+               val &= 0xffff77f;
                __asm__ __volatile__ ("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
-       else
+       } else {
+               /* bits 4-23 are write-as-0, 24-31 are write ignored */
+               val &= 0xf;
                __asm__ __volatile__ ("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
+       }
 }
 
 static u32 read_pmnc(void)
@@ -139,8 +144,11 @@ static u32 read_pmnc(void)
 
        if (pmu->id == PMU_XSC1)
                __asm__ __volatile__ ("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
-       else
+       else {
                __asm__ __volatile__ ("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
+               /* bits 1-2 and 4-23 are read-unpredictable */
+               val &= 0xff000009;
+       }
 
        return val;
 }
@@ -249,7 +257,7 @@ static int xscale_setup_ctrs(void)
        int i;
 
        for (i = CCNT; i < MAX_COUNTERS; i++) {
-               if (counter_config[i].event)
+               if (counter_config[i].enabled)
                        continue;
 
                counter_config[i].event = EVT_UNUSED;
@@ -298,9 +306,9 @@ static void inline __xsc1_check_ctrs(void)
        /*       Overflow bit gets cleared. There's no workaround.       */
        /*       Fixed in B stepping or later                            */
 
-       pmnc &= ~(PMU_ENABLE | pmu->cnt_ovf[PMN0] | pmu->cnt_ovf[PMN1] |
-               pmu->cnt_ovf[CCNT]);
-       write_pmnc(pmnc);
+       /* Write the value back to clear the overflow flags. Overflow */
+       /* flags remain in pmnc for use below */
+       write_pmnc(pmnc & ~PMU_ENABLE);
 
        for (i = CCNT; i <= PMN1; i++) {
                if (!(pmu->int_mask[i] & pmu->int_enable))
@@ -334,10 +342,9 @@ static void inline __xsc2_check_ctrs(void)
        __asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag));
 }
 
-static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
 {
-       unsigned long eip = instruction_pointer(regs);
-       int i, is_kernel = !user_mode(regs);
+       int i;
        u32 pmnc;
 
        if (pmu->id == PMU_XSC1)
@@ -350,7 +357,7 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs
                        continue;
 
                write_counter(i, -(u32)results[i].reset_counter);
-               oprofile_add_sample(eip, is_kernel, i, smp_processor_id());
+               oprofile_add_sample(get_irq_regs(), i);
                results[i].ovf--;
        }
 
@@ -375,7 +382,7 @@ static int xscale_pmu_start(void)
        int ret;
        u32 pmnc = read_pmnc();
 
-       ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, SA_INTERRUPT,
+       ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
                        "XScale PMU", (void *)results);
 
        if (ret < 0) {
@@ -386,8 +393,10 @@ static int xscale_pmu_start(void)
 
        if (pmu->id == PMU_XSC1)
                pmnc |= pmu->int_enable;
-       else
+       else {
                __asm__ __volatile__ ("mcr p14, 0, %0, c4, c1, 0" : : "r" (pmu->int_enable));
+               pmnc &= ~PMU_CNT64;
+       }
 
        pmnc |= PMU_ENABLE;
        write_pmnc(pmnc);