powerpc/perf: Add e6500 PMU driver
authorPriyanka Jain <Priyanka.Jain@freescale.com>
Wed, 5 Jun 2013 20:22:10 +0000 (15:22 -0500)
committerScott Wood <scottwood@freescale.com>
Wed, 7 Aug 2013 23:38:04 +0000 (18:38 -0500)
e6500 core performance monitors has the following features:
- 6 performance monitor counters
- 512 events supported
- no threshold events

e6500 PMU has more specific events (Data L1 cache misses, Instruction L1
cache misses, etc ) than e500 PMU (which only had Data L1 cache reloads,
etc). Where available, the more specific events have been used which will
produce slightly different results than e500 PMU equivalents.

Signed-off-by: Priyanka Jain <Priyanka.Jain@freescale.com>
Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/include/asm/reg_fsl_emb.h
arch/powerpc/perf/Makefile
arch/powerpc/perf/e6500-pmu.c [new file with mode: 0644]

index c51d52ed7b0fc216d4ad7fd32384dc06f196704a..0e3ddf5177f655016a6aa6e27fa278c3b820cd5c 100644 (file)
 #define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
 #define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
 #define PMLCA_CE       0x04000000      /* Condition Enable */
+#define PMLCA_FGCS1    0x00000002      /* Freeze in guest state */
+#define PMLCA_FGCS0    0x00000001      /* Freeze in hypervisor state */
 
-#define PMLCA_EVENT_MASK 0x00ff0000    /* Event field */
+#define PMLCA_EVENT_MASK 0x01ff0000    /* Event field */
 #define PMLCA_EVENT_SHIFT      16
 
 #define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
index 510fae10513d11eaa49abfe3f395370fba830473..60d71eea919c7f2e64b8d74e6732e4883fa3f61b 100644 (file)
@@ -9,7 +9,7 @@ obj64-$(CONFIG_PPC_PERF_CTRS)   += power4-pmu.o ppc970-pmu.o power5-pmu.o \
 obj32-$(CONFIG_PPC_PERF_CTRS)  += mpc7450-pmu.o
 
 obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
-obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
+obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
 
 obj-$(CONFIG_PPC64)            += $(obj64-y)
 obj-$(CONFIG_PPC32)            += $(obj32-y)
diff --git a/arch/powerpc/perf/e6500-pmu.c b/arch/powerpc/perf/e6500-pmu.c
new file mode 100644 (file)
index 0000000..3d877aa
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Performance counter support for e6500 family processors.
+ *
+ * Author: Priyanka Jain, Priyanka.Jain@freescale.com
+ * Based on e500-pmu.c
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Map of generic hardware event types to hardware events
+ * Zero if unsupported
+ */
+static int e6500_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = 1,
+       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
+       [PERF_COUNT_HW_CACHE_MISSES] = 221,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
+       [PERF_COUNT_HW_BRANCH_MISSES] = 15,
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int e6500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {
+                               /*RESULT_ACCESS         RESULT_MISS */
+               [C(OP_READ)] = {        27,             222     },
+               [C(OP_WRITE)] = {       28,             223     },
+               [C(OP_PREFETCH)] = {    29,             0       },
+       },
+       [C(L1I)] = {
+                               /*RESULT_ACCESS         RESULT_MISS */
+               [C(OP_READ)] = {        2,              254     },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    37,             0       },
+       },
+       /*
+        * Assuming LL means L2, it's not a good match for this model.
+        * It does not have separate read/write events (but it does have
+        * separate instruction/data events).
+        */
+       [C(LL)] = {
+                               /*RESULT_ACCESS         RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       0,              0       },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       /*
+        * There are data/instruction MMU misses, but that's a miss on
+        * the chip's internal level-one TLB which is probably not
+        * what the user wants.  Instead, unified level-two TLB misses
+        * are reported here.
+        */
+       [C(DTLB)] = {
+                               /*RESULT_ACCESS         RESULT_MISS */
+               [C(OP_READ)] = {        26,             66      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {
+                               /*RESULT_ACCESS         RESULT_MISS */
+               [C(OP_READ)] = {        12,             15      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {
+                               /* RESULT_ACCESS        RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+static int num_events = 512;
+
+/* Upper half of event id is PMLCb, for threshold events */
+static u64 e6500_xlate_event(u64 event_id)
+{
+       u32 event_low = (u32)event_id;
+       if (event_low >= num_events ||
+               (event_id & (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)))
+               return 0;
+
+       return FSL_EMB_EVENT_VALID;
+}
+
+static struct fsl_emb_pmu e6500_pmu = {
+       .name                   = "e6500 family",
+       .n_counter              = 6,
+       .n_restricted           = 0,
+       .xlate_event            = e6500_xlate_event,
+       .n_generic              = ARRAY_SIZE(e6500_generic_events),
+       .generic_events         = e6500_generic_events,
+       .cache_events           = &e6500_cache_events,
+};
+
+static int init_e6500_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+               strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e6500"))
+               return -ENODEV;
+
+       return register_fsl_emb_pmu(&e6500_pmu);
+}
+
+early_initcall(init_e6500_pmu);